Leaked source code of windows server 2003
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.

569 lines
12 KiB

  1. /*
  2. * X O U T . C P P
  3. *
  4. * XML push model printing
  5. *
  6. * This code was stolen from the XML guys and adapted for our use
  7. * in owner comment processing.
  8. *
  9. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  10. */
  11. #include "_xml.h"
  12. // CXMLOut -------------------------------------------------------------------
  13. //
  14. VOID
  15. CXMLOut::CloseElementDecl(
  16. /* [in] */ BOOL fEmptyNode)
  17. {
  18. // If we get a call to EndAttributesOut, and the
  19. // node is empty, we want to close things up here.
  20. //
  21. if (fEmptyNode)
  22. {
  23. m_sb.Append (L"/>");
  24. }
  25. //
  26. // Otherwise, we can end the attributes as if a new node is
  27. // to follow.
  28. //
  29. else
  30. m_sb.Append (L">");
  31. // Remember that they have been ended!
  32. //
  33. m_fElementNeedsClosing = FALSE;
  34. // Note, we should start to emit the namespaces after the first element
  35. // node is closed. The namespaces for the first node is emitter from
  36. // the namespace cache
  37. //
  38. m_fAddNamespaceDecl = TRUE;
  39. }
  40. VOID
  41. CXMLOut::EndAttributesOut (
  42. /* [in] */ DWORD dwType)
  43. {
  44. // Make sure we setup to close the element
  45. //
  46. if (XML_ELEMENT == dwType)
  47. {
  48. Assert (FALSE == m_fElementNeedsClosing);
  49. m_fElementNeedsClosing = TRUE;
  50. }
  51. }
  52. VOID
  53. CXMLOut::EndChildrenOut (
  54. /* [in] */ BOOL fEmptyNode,
  55. /* [in] */ DWORD dwType,
  56. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  57. /* [in] */ ULONG ulLen)
  58. {
  59. // If there is an element awaiting a close...
  60. //
  61. if (m_fElementNeedsClosing)
  62. {
  63. // ... close it
  64. //
  65. CloseElementDecl (fEmptyNode);
  66. }
  67. switch (dwType)
  68. {
  69. case XML_ELEMENT:
  70. if (!fEmptyNode)
  71. {
  72. m_sb.Append (L"</");
  73. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  74. m_sb.Append (L">");
  75. }
  76. break;
  77. case XML_ATTRIBUTE:
  78. m_sb.Append (L"\"");
  79. break;
  80. case XML_XMLDECL:
  81. case XML_PI:
  82. m_sb.Append (L" ");
  83. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  84. m_sb.Append (L"?>");
  85. break;
  86. case XML_DOCTYPE:
  87. case XML_ENTITYDECL:
  88. case XML_PENTITYDECL:
  89. case XML_ELEMENTDECL:
  90. case XML_ATTLISTDECL:
  91. case XML_NOTATION:
  92. m_sb.Append (L">");
  93. break;
  94. case XML_GROUP:
  95. m_sb.Append (L")");
  96. break;
  97. case XML_INCLUDESECT:
  98. m_sb.Append (L"]]>");
  99. break;
  100. }
  101. }
  102. void
  103. CXMLOut::CreateNodeAttrOut (
  104. /* [in] */ const WCHAR __RPC_FAR *pwszAttr,
  105. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  106. /* [in] */ ULONG ulLen)
  107. {
  108. m_sb.Append (pwszAttr);
  109. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  110. m_sb.Append (L"\"");
  111. }
  112. VOID
  113. CXMLOut::CreateNodeOut(
  114. /* [in] */ DWORD dwType,
  115. /* [in] */ BOOL fTerminal,
  116. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  117. /* [in] */ ULONG ulLen)
  118. {
  119. // If there is an element awaiting a close...
  120. //
  121. if (m_fElementNeedsClosing)
  122. {
  123. // ... close it
  124. //
  125. CloseElementDecl (FALSE);
  126. }
  127. switch (dwType)
  128. {
  129. case XML_ELEMENT:
  130. m_sb.Append (L"<");
  131. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  132. break;
  133. case XML_ATTRIBUTE:
  134. m_sb.Append (L" ");
  135. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  136. m_sb.Append (L"=\"");
  137. break;
  138. case XML_XMLDECL:
  139. case XML_PI:
  140. m_sb.Append (L"<?");
  141. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  142. break;
  143. case XML_DOCTYPE:
  144. m_sb.Append (L"<!DOCTYPE ");
  145. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  146. break;
  147. case XML_ENTITYDECL:
  148. m_sb.Append (L"<!ENTITY ");
  149. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  150. break;
  151. case XML_PENTITYDECL:
  152. m_sb.Append (L"<!ENTITY % ");
  153. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  154. break;
  155. case XML_ELEMENTDECL:
  156. m_sb.Append (L"<!ELEMENT ");
  157. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  158. break;
  159. case XML_ATTLISTDECL:
  160. m_sb.Append (L"<!ATTLIST ");
  161. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  162. break;
  163. case XML_NOTATION:
  164. m_sb.Append (L"<!NOTATION ");
  165. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  166. break;
  167. case XML_GROUP:
  168. m_sb.Append (L" (");
  169. break;
  170. case XML_INCLUDESECT:
  171. m_sb.Append (L"<![");
  172. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  173. m_sb.Append (L"[");
  174. break;
  175. case XML_IGNORESECT:
  176. m_sb.Append (L"<![IGNORE[");
  177. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  178. m_sb.Append (L"]]>");
  179. break;
  180. case XML_CDATA:
  181. m_sb.Append (L"<![CDATA[");
  182. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  183. m_sb.Append (L"]]>");
  184. break;
  185. case XML_COMMENT:
  186. m_sb.Append (L"<!--");
  187. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  188. m_sb.Append (L"-->");
  189. break;
  190. case XML_ENTITYREF:
  191. m_sb.Append (L"&");
  192. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  193. m_sb.Append (L";");
  194. break;
  195. case XML_PEREF:
  196. m_sb.Append (L"%");
  197. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  198. m_sb.Append (L";");
  199. break;
  200. case XML_SYSTEM:
  201. CreateNodeAttrOut (L" SYSTEM \"", pwcText, ulLen);
  202. break;
  203. case XML_PUBLIC:
  204. CreateNodeAttrOut (L" PUBLIC \"", pwcText, ulLen);
  205. break;
  206. case XML_NAME:
  207. m_sb.Append (L" ");
  208. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  209. break;
  210. case XML_STRING:
  211. CreateNodeAttrOut (L" \"", pwcText, ulLen);
  212. break;
  213. case XML_VERSION:
  214. CreateNodeAttrOut (L" version=\"", pwcText, ulLen);
  215. break;
  216. case XML_ENCODING:
  217. CreateNodeAttrOut (L" encoding=\"", pwcText, ulLen);
  218. break;
  219. case XML_NDATA:
  220. m_sb.Append (L" NDATA");
  221. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  222. break;
  223. case XML_PCDATA:
  224. // IMPORTANT: we will get multiple calls to this for each
  225. // entity element, some of which need to be escaped. Handle
  226. // that here.
  227. //
  228. // The elements that need escaping are:
  229. //
  230. // '&' goes to "&amp;"
  231. // '>' goes to "&gt;"
  232. // '<' goes to "&lt;"
  233. // ''' goes to "&qpos;"
  234. // '"' goes to "&quot;"
  235. //
  236. // Note that in the case of attributes, only two need escaping --
  237. // the latter two quote marks. The first three are for node values.
  238. // However, we are going to make some simple assumptions that should
  239. // be reasonable. If we only get a single character that matches on
  240. // of the escape sequences, then escape it.
  241. //
  242. if (1 == ulLen)
  243. {
  244. switch (*pwcText)
  245. {
  246. case L'&':
  247. pwcText = gc_wszAmp;
  248. ulLen = CchConstString (gc_wszAmp);
  249. Assert (5 == ulLen);
  250. break;
  251. case L'>':
  252. pwcText = gc_wszGreaterThan;
  253. ulLen = CchConstString (gc_wszGreaterThan);
  254. Assert (4 == ulLen);
  255. break;
  256. case L'<':
  257. pwcText = gc_wszLessThan;
  258. ulLen = CchConstString (gc_wszLessThan);
  259. Assert (4 == ulLen);
  260. break;
  261. case L'\'':
  262. pwcText = gc_wszApos;
  263. ulLen = CchConstString (gc_wszApos);
  264. Assert (6 == ulLen);
  265. break;
  266. case L'"':
  267. pwcText = gc_wszQuote;
  268. ulLen = CchConstString (gc_wszQuote);
  269. Assert (6 == ulLen);
  270. break;
  271. default:
  272. // There is no mapping required.
  273. //
  274. break;
  275. }
  276. }
  277. Assert (fTerminal);
  278. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  279. break;
  280. case XML_EMPTY:
  281. case XML_ANY:
  282. case XML_MIXED:
  283. case XML_ATTDEF:
  284. case XML_AT_CDATA:
  285. case XML_AT_ID:
  286. case XML_AT_IDREF:
  287. case XML_AT_IDREFS:
  288. case XML_AT_ENTITY:
  289. case XML_AT_ENTITIES:
  290. case XML_AT_NMTOKEN:
  291. case XML_AT_NMTOKENS:
  292. case XML_AT_NOTATION:
  293. case XML_AT_REQUIRED:
  294. case XML_AT_IMPLIED:
  295. case XML_AT_FIXED:
  296. m_sb.Append (L" ");
  297. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  298. break;
  299. case XML_DTDSUBSET:
  300. // Do nothing -- since we've already printed the DTD subset.
  301. // and EndDTDSubset will print the ']' character.
  302. //
  303. break;
  304. default:
  305. m_sb.Append (ulLen * sizeof(WCHAR), pwcText);
  306. break;
  307. }
  308. }
  309. // Owner processing ----------------------------------------------------------
  310. //
  311. SCODE
  312. CXMLOut::ScCompleteChildren (
  313. /* [in] */ BOOL fEmptyNode,
  314. /* [in] */ DWORD dwType,
  315. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  316. /* [in] */ ULONG ulLen)
  317. {
  318. // Close the current owner comment item
  319. //
  320. EndChildrenOut (fEmptyNode, dwType, pwcText, ulLen);
  321. // Decrement the depth of the owner tree
  322. //
  323. --m_lDepth;
  324. XmlTrace ("Xml: Lock: Owner: decrementing depth to: %ld\n", m_lDepth);
  325. return S_OK;
  326. }
  327. SCODE
  328. CXMLOut::ScHandleNode (
  329. /* [in] */ DWORD dwType,
  330. /* [in] */ DWORD dwSubType,
  331. /* [in] */ BOOL fTerminal,
  332. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  333. /* [in] */ ULONG ulLen,
  334. /* [in] */ ULONG ulNamespaceLen,
  335. /* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
  336. /* [in] */ const ULONG ulNsPrefixLen)
  337. {
  338. switch (dwType)
  339. {
  340. case XML_ATTRIBUTE:
  341. // If this is a namespace decl, then there is different
  342. // name reconstruction that needs to happen...
  343. //
  344. if (XML_NS == dwSubType)
  345. {
  346. // ... but before we do that ...
  347. //
  348. // There are some namespaces that should not be added
  349. // to the owners comments at this time (the get added
  350. // by the namespace cache emitting mechanism. If the
  351. // namespaces are to be blocked, handle this now.
  352. //
  353. // Note that by returning S_FALSE, we will not get
  354. // called for the PCDATA nodes that also apply to this
  355. // namespace.
  356. //
  357. if (!m_fAddNamespaceDecl)
  358. return S_FALSE;
  359. Assert ((CchConstString(gc_wszXmlns) == ulLen)
  360. && (!wcsncmp(pwcText, gc_wszXmlns, CchConstString(gc_wszXmlns))));
  361. break;
  362. }
  363. // Otherwise, fall through to the regular processing
  364. //
  365. case XML_ELEMENT:
  366. {
  367. // OK, we are going to be real sneaky here. The
  368. // original, aliased tag is available here without
  369. // having to back-lookup. The pwcText pointer has
  370. // simply been scooted forward in the text to skip
  371. // over the the alias and ':'. So, we can use the
  372. // ulNsPrefixLen to scoot back and not have to do
  373. // any sort of back lookup.
  374. //
  375. if (0 != ulNsPrefixLen)
  376. {
  377. // The prefix len does not take into account the
  378. // colon separator, so we have to here!
  379. //
  380. pwcText -= ulNsPrefixLen + 1;
  381. ulLen += ulNsPrefixLen + 1;
  382. }
  383. break;
  384. }
  385. }
  386. // Acknowledge the change in owner processing
  387. // depth...
  388. //
  389. if (!fTerminal)
  390. {
  391. ++m_lDepth;
  392. XmlTrace ("CXmlOut: incrementing depth to: %ld\n", m_lDepth);
  393. }
  394. // Build up the owner comment where appropriate
  395. //
  396. CreateNodeOut (dwType, fTerminal, pwcText, ulLen);
  397. return S_OK;
  398. }
  399. BOOL
  400. CEmitNmspc::operator()(const CRCWszN&, const auto_ref_ptr<CNmspc>& pns)
  401. {
  402. Assert (pns.get());
  403. // Allocate enough space for the namespace attribute --
  404. // which includes the prefix, an optional colon and an
  405. // alias.
  406. //
  407. CStackBuffer<WCHAR> pwsz;
  408. UINT cch = pns->CchAlias() + CchConstString(gc_wszXmlns) + 1;
  409. if (NULL == pwsz.resize(CbSizeWsz(cch)))
  410. return FALSE;
  411. // Copy over the prefix
  412. //
  413. wcsncpy (pwsz.get(), gc_wszXmlns, CchConstString(gc_wszXmlns));
  414. if (pns->CchAlias())
  415. {
  416. // Copy over the colon and alias
  417. //
  418. pwsz[CchConstString(gc_wszXmlns)] = L':';
  419. wcsncpy(pwsz.get() + CchConstString(gc_wszXmlns) + 1,
  420. pns->PszAlias(),
  421. pns->CchAlias());
  422. // Terminate it
  423. //
  424. pwsz[cch] = 0;
  425. }
  426. else
  427. {
  428. // Terminate it
  429. //
  430. pwsz[CchConstString(gc_wszXmlns)] = 0;
  431. cch = CchConstString(gc_wszXmlns);
  432. }
  433. // Output the namespace element.
  434. //
  435. m_xo.CreateNodeOut (XML_ATTRIBUTE, FALSE, pwsz.get(), cch);
  436. // There may be some escaping that needs to happen for a namespace.
  437. //
  438. LPCWSTR pwszHref = pns->PszHref();
  439. LPCWSTR pwszStart = pns->PszHref();
  440. UINT cchHref = pns->CchHref();
  441. for (; pwszHref < pns->PszHref() + cchHref; pwszHref++)
  442. {
  443. if ((L'\'' == *pwszHref) ||
  444. (L'"' == *pwszHref) ||
  445. (L'&' == *pwszHref))
  446. {
  447. // Emit the stuff leading up to the escaped character
  448. //
  449. m_xo.CreateNodeOut (XML_PCDATA, TRUE, pwszStart, static_cast<UINT>(pwszHref - pwszStart));
  450. // Escape the single character and the underlying code
  451. // will do the proper escaping!
  452. //
  453. m_xo.CreateNodeOut (XML_PCDATA, TRUE, pwszHref, 1);
  454. // Mark our starting point at the next character
  455. //
  456. pwszStart = pwszHref + 1;
  457. }
  458. }
  459. // Finish off the namespace
  460. //
  461. m_xo.CreateNodeOut (XML_PCDATA, TRUE, pwszStart, static_cast<UINT>(pwszHref - pwszStart));
  462. m_xo.EndChildrenOut (FALSE, XML_ATTRIBUTE, pwsz.get(), cch);
  463. return TRUE;
  464. }