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.

610 lines
12 KiB

  1. /*
  2. * X E M I T 2 . C P P
  3. *
  4. * XML emitter processing
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. #include "_xmllib.h"
  9. DEC_CONST CHAR gc_szXmlVersion[] = "<?xml version=\"1.0\"?>";
  10. DEC_CONST UINT gc_cchXmlVersion = CElems(gc_szXmlVersion) - 1 ;
  11. // class CXMLEmitter ---------------------------------------------------------
  12. //
  13. SCODE
  14. CXMLEmitter::ScAddNmspc (
  15. /* [in] */ const auto_ref_ptr<CNmspc>& pns,
  16. /* [in] */ CXNode* pxnRoot)
  17. {
  18. Assert (pxnRoot);
  19. auto_ref_ptr<CXNode> pxn;
  20. CStackBuffer<WCHAR> pwsz;
  21. SCODE sc = S_OK;
  22. UINT cch;
  23. // Allocate enough space for the prefix, colon and alias
  24. //
  25. cch = CchConstString(gc_wszXmlns) + 1 + pns->CchAlias();
  26. if (NULL == pwsz.resize(CbSizeWsz(cch)))
  27. {
  28. sc = E_OUTOFMEMORY;
  29. goto ret;
  30. }
  31. wcsncpy (pwsz.get(), gc_wszXmlns, CchConstString(gc_wszXmlns));
  32. if (pns->CchAlias())
  33. {
  34. pwsz[CchConstString(gc_wszXmlns)] = L':';
  35. wcsncpy(pwsz.get() + CchConstString(gc_wszXmlns) + 1,
  36. pns->PszAlias(),
  37. pns->CchAlias());
  38. pwsz[cch] = 0;
  39. }
  40. else
  41. pwsz[CchConstString(gc_wszXmlns)] = 0;
  42. // Create the namespace attribute
  43. //
  44. sc = pxnRoot->ScGetChildNode (CXNode::XN_NAMESPACE, pxn.load());
  45. if (FAILED(sc))
  46. goto ret;
  47. Assert (pxn.get());
  48. sc = ScAddAttribute (pxn.get(),
  49. pwsz.get(),
  50. cch,
  51. pns->PszHref(),
  52. pns->CchHref());
  53. if (FAILED(sc))
  54. goto ret;
  55. ret:
  56. return sc;
  57. }
  58. SCODE
  59. CXMLEmitter::ScAddAttribute (
  60. /* [in] */ CXNode * pxn,
  61. /* [in] */ LPCWSTR pwszTag,
  62. /* [in] */ UINT cchTag,
  63. /* [in] */ LPCWSTR pwszValue,
  64. /* [in] */ UINT cchValue)
  65. {
  66. SCODE sc = S_OK;
  67. // Format:
  68. //
  69. // " " [<alias> ":"] <tag> "=\"" <value> "\""
  70. //
  71. sc = m_pxb->ScAddTextBytes (1, " ");
  72. if (FAILED(sc))
  73. goto ret;
  74. sc = pxn->ScSetTag (this, cchTag, pwszTag);
  75. if (FAILED (sc))
  76. goto ret;
  77. sc = m_pxb->ScAddTextBytes (2, "=\"");
  78. if (FAILED(sc))
  79. goto ret;
  80. sc = pxn->ScSetValue (pwszValue, cchValue);
  81. if (FAILED (sc))
  82. goto ret;
  83. sc = m_pxb->ScAddTextBytes (1, "\"");
  84. if (FAILED(sc))
  85. goto ret;
  86. ret:
  87. return sc;
  88. }
  89. BOOL
  90. CXMLEmitter::NmspcEmittingOp::operator() (const CRCWszN&, const auto_ref_ptr<CNmspc>& nmspc )
  91. {
  92. return SUCCEEDED (m_emitter->ScAddNmspc (nmspc, m_pxnParent.get()));
  93. }
  94. SCODE
  95. CXMLEmitter::ScNewNode (
  96. /* [in] */ XNT xnt,
  97. /* [in] */ LPCWSTR pwszTag,
  98. /* [in] */ CXNode * pxnParent,
  99. /* [in] */ auto_ref_ptr<CXNode>& pxnOut)
  100. {
  101. auto_ref_ptr<CXNode> pxn;
  102. SCODE sc = S_OK;
  103. // Create the node
  104. //
  105. sc = pxnParent->ScGetChildNode (xnt, pxn.load());
  106. if (FAILED(sc))
  107. goto ret;
  108. // Set the tag name
  109. //
  110. switch (xnt)
  111. {
  112. case CXNode::XN_ELEMENT:
  113. case CXNode::XN_ATTRIBUTE:
  114. sc = pxn->ScSetTag (this, static_cast<UINT>(wcslen(pwszTag)), pwszTag);
  115. if (FAILED (sc))
  116. goto ret;
  117. case CXNode::XN_NAMESPACE:
  118. break;
  119. }
  120. // Pass back a reference
  121. //
  122. Assert (S_OK == sc);
  123. pxnOut = pxn.get();
  124. ret:
  125. return sc;
  126. }
  127. SCODE
  128. CXMLEmitter::ScSetRoot (LPCWSTR pwszTag)
  129. {
  130. SCODE sc = S_OK;
  131. if (!m_pxnRoot.get())
  132. {
  133. // Create the <?xml version="1.0"?> node and insert it
  134. // into the document.
  135. //
  136. sc = m_pxb->ScAddTextBytes (gc_cchXmlVersion, gc_szXmlVersion);
  137. if (FAILED(sc))
  138. goto ret;
  139. sc = ScNewRootNode (pwszTag);
  140. if (FAILED(sc))
  141. goto ret;
  142. }
  143. ret:
  144. return sc;
  145. }
  146. SCODE
  147. CXMLEmitter::ScNewRootNode (LPCWSTR pwszTag)
  148. {
  149. SCODE sc = S_OK;
  150. if (m_pxnRoot.get() == NULL)
  151. {
  152. // Initialize the emitter's namespace cache
  153. //
  154. sc = ScInit();
  155. if (FAILED (sc))
  156. goto ret;
  157. // Take this chance to initialize the local cache
  158. //
  159. if (!m_cacheLocal.FInit())
  160. {
  161. sc = E_OUTOFMEMORY;
  162. goto ret;
  163. }
  164. if (m_pNmspcLoader)
  165. {
  166. // Load all the document level namespaces
  167. //
  168. sc = m_pNmspcLoader->ScLoadNamespaces(this);
  169. }
  170. else
  171. {
  172. // Load the default namespace
  173. //
  174. sc = ScPreloadNamespace (gc_wszDav);
  175. }
  176. if (FAILED(sc))
  177. goto ret;
  178. // Create the node
  179. //
  180. m_pxnRoot.take_ownership (new CXNode (CXNode::XN_ELEMENT, m_pxb.get()));
  181. if (!m_pxnRoot.get())
  182. {
  183. sc = E_OUTOFMEMORY;
  184. goto ret;
  185. }
  186. // Set the tag name
  187. //
  188. sc = m_pxnRoot->ScSetTag (this, static_cast<UINT>(wcslen(pwszTag)), pwszTag);
  189. if (FAILED (sc))
  190. goto ret;
  191. // Namespace must have been populated before root node is created
  192. //
  193. Assert (S_OK == sc);
  194. // It's time to add all the namespaces
  195. //
  196. {
  197. NmspcEmittingOp op (this, m_pxnRoot.get());
  198. m_cache.ForEach(op);
  199. }
  200. }
  201. ret:
  202. return sc;
  203. }
  204. SCODE
  205. CXMLEmitter::ScFindNmspc (LPCWSTR pwsz, UINT cch, auto_ref_ptr<CNmspc>& pns)
  206. {
  207. Assert (pwsz);
  208. SCODE sc = S_OK;
  209. // Emitter has two namespace cache, one is the docoument level cache
  210. // for namespaces that span the whole XML body, and the other one is
  211. // for namesapces that scopes on the current record only.
  212. //
  213. // Look into the record level cache first
  214. //
  215. if (m_cacheLocal.CItems())
  216. {
  217. CRCWszN key(pwsz, cch);
  218. auto_ref_ptr<CNmspc>* parp;
  219. parp = m_cacheLocal.Lookup (key);
  220. if (NULL != parp)
  221. {
  222. pns = *parp;
  223. return S_OK;
  224. }
  225. }
  226. // Try and find the namespace in the document's cache
  227. //
  228. sc = ScNmspcFromHref (pwsz, cch, pns);
  229. return sc;
  230. }
  231. SCODE
  232. CXMLEmitter::ScPreloadNamespace (LPCWSTR pwszTag)
  233. {
  234. LPCWSTR pwsz;
  235. SCODE sc = S_OK;
  236. UINT cch;
  237. Assert (pwszTag);
  238. // This must be done before root node is created
  239. //
  240. Assert (!m_pxnRoot.get());
  241. // And should no local namespace yet
  242. //
  243. Assert (m_cacheLocal.CItems() == 0);
  244. // Find the namespace separator
  245. //
  246. cch = CchNmspcFromTag (static_cast<UINT>(wcslen(pwszTag)), pwszTag, &pwsz);
  247. if (cch != 0)
  248. {
  249. // Add to namespace cache
  250. //
  251. auto_ref_ptr<CNmspc> pns;
  252. sc = ScNmspcFromHref (pwszTag, cch, pns);
  253. if (FAILED (sc))
  254. goto ret;
  255. }
  256. ret:
  257. return sc;
  258. }
  259. //
  260. // CXMLEmitter::ScPreloadNamespace
  261. // Preload namespaces
  262. SCODE
  263. CXMLEmitter::ScPreloadLocalNamespace (CXNode * pxn, LPCWSTR pwszTag)
  264. {
  265. LPCWSTR pwsz;
  266. SCODE sc = S_OK;
  267. UINT cch;
  268. Assert (pwszTag);
  269. // This must be done after root node is created
  270. //
  271. Assert (m_pxnRoot.get());
  272. // Find the namespace separator
  273. //
  274. cch = CchNmspcFromTag (static_cast<UINT>(wcslen(pwszTag)), pwszTag, &pwsz);
  275. if (cch != 0)
  276. {
  277. auto_ref_ptr<CNmspc> pns;
  278. // Add to namespace cache
  279. //
  280. sc = ScFindNmspc (pwszTag, cch, pns);
  281. if (FAILED (sc))
  282. goto ret;
  283. if (S_FALSE == sc)
  284. {
  285. // It wasn't there, so if the root of the document has
  286. // already been committed, then remove the name from the
  287. // document cache and add it to the chunk cache.
  288. //
  289. CRCWszN key = IndexKey(pns);
  290. // First, remove from the parent
  291. //
  292. Assert (NULL == m_cacheLocal.Lookup (key));
  293. m_cache.Remove (key);
  294. // Looks like this is a new namespace to this
  295. // chunk and needs to be cached.
  296. //
  297. if (!m_cacheLocal.FAdd (key, pns))
  298. {
  299. sc = E_OUTOFMEMORY;
  300. goto ret;
  301. }
  302. // Emit this namespace
  303. //
  304. sc = ScAddNmspc (pns, pxn);
  305. if (FAILED(sc))
  306. goto ret;
  307. // Regardless of whether or not this namespace was
  308. // new to this chunk, we do not want it added to the
  309. // document. So we cannot return S_FALSE.
  310. //
  311. sc = S_OK;
  312. }
  313. }
  314. ret:
  315. return sc;
  316. }
  317. // CEmitterNode --------------------------------------------------------------
  318. //
  319. SCODE
  320. CEmitterNode::ScConstructNode (
  321. /* [in] */ CXMLEmitter& emitter,
  322. /* [in] */ CXNode* pxnParent,
  323. /* [in] */ LPCWSTR pwszTag,
  324. /* [in] */ LPCWSTR pwszValue,
  325. /* [in] */ LPCWSTR pwszType)
  326. {
  327. SCODE sc = S_OK;
  328. // Create the new node...
  329. //
  330. Assert (pxnParent);
  331. Assert (m_emitter.get() == NULL);
  332. sc = emitter.ScNewNode (CXNode::XN_ELEMENT, pwszTag, pxnParent, m_pxn);
  333. if (FAILED (sc))
  334. goto ret;
  335. XmlTrace ("XML: constructing node:\n-- tag: %ws\n", pwszTag);
  336. // Set the value type if it existed
  337. //
  338. if (pwszType)
  339. {
  340. // Create the namespace attribute
  341. //
  342. auto_ref_ptr<CXNode> pxnType;
  343. sc = m_pxn->ScGetChildNode (CXNode::XN_ATTRIBUTE, pxnType.load());
  344. if (FAILED(sc))
  345. goto ret;
  346. Assert (pxnType.get());
  347. XmlTrace ("-- type: %ws\n", pwszType);
  348. sc = emitter.ScAddAttribute (pxnType.get(),
  349. gc_wszLexType,
  350. gc_cchLexType,
  351. pwszType,
  352. static_cast<UINT>(wcslen(pwszType)));
  353. if (FAILED (sc))
  354. goto ret;
  355. }
  356. // Set the value
  357. // Value must be emitted after type
  358. //
  359. if (pwszValue)
  360. {
  361. XmlTrace ("-- value: %ws\n", pwszValue);
  362. sc = m_pxn->ScSetValue (pwszValue);
  363. if (FAILED (sc))
  364. goto ret;
  365. }
  366. // Stuff the emitter into the node
  367. //
  368. m_emitter = &emitter;
  369. ret:
  370. return sc;
  371. }
  372. SCODE
  373. CEmitterNode::ScAddNode (
  374. /* [in] */ LPCWSTR pwszTag,
  375. /* [in] */ CEmitterNode& en,
  376. /* [in] */ LPCWSTR pwszValue,
  377. /* [in] */ LPCWSTR pwszType)
  378. {
  379. SCODE sc = S_OK;
  380. // Construct the node
  381. //
  382. Assert (m_emitter.get());
  383. sc = en.ScConstructNode (*m_emitter,
  384. m_pxn.get(),
  385. pwszTag,
  386. pwszValue,
  387. pwszType);
  388. if (FAILED (sc))
  389. goto ret;
  390. ret:
  391. return sc;
  392. }
  393. SCODE
  394. CEmitterNode::ScAddMultiByteNode (
  395. /* [in] */ LPCWSTR pwszTag,
  396. /* [in] */ CEmitterNode& en,
  397. /* [in] */ LPCSTR pszValue,
  398. /* [in] */ LPCWSTR pwszType)
  399. {
  400. SCODE sc = ScAddNode (pwszTag, en, NULL, pwszType);
  401. if (FAILED (sc))
  402. goto ret;
  403. Assert (pszValue);
  404. sc = en.Pxn()->ScSetValue (pszValue, static_cast<UINT>(strlen(pszValue)));
  405. if (FAILED (sc))
  406. goto ret;
  407. ret:
  408. return sc;
  409. }
  410. SCODE
  411. CEmitterNode::ScAddUTF8Node (
  412. /* [in] */ LPCWSTR pwszTag,
  413. /* [in] */ CEmitterNode& en,
  414. /* [in] */ LPCSTR pszValue,
  415. /* [in] */ LPCWSTR pwszType)
  416. {
  417. SCODE sc = ScAddNode (pwszTag, en, NULL, pwszType);
  418. if (FAILED (sc))
  419. goto ret;
  420. Assert (pszValue);
  421. sc = en.Pxn()->ScSetUTF8Value (pszValue, static_cast<UINT>(strlen(pszValue)));
  422. if (FAILED(sc))
  423. goto ret;
  424. ret:
  425. return sc;
  426. }
  427. SCODE
  428. CEmitterNode::ScAddDateNode (
  429. /* [in] */ LPCWSTR pwszTag,
  430. /* [in] */ FILETIME* pft,
  431. /* [in] */ CEmitterNode& en)
  432. {
  433. SYSTEMTIME st;
  434. WCHAR rgwch[128];
  435. Assert (pft);
  436. if (!FileTimeToSystemTime (pft, &st))
  437. {
  438. // In case the filetime is invalid, default to zero
  439. //
  440. FILETIME ftDefault = {0};
  441. FileTimeToSystemTime (&ftDefault, &st);
  442. }
  443. if (FGetDateIso8601FromSystime (&st, rgwch, CElems(rgwch)))
  444. {
  445. return ScAddNode (pwszTag,
  446. en,
  447. rgwch,
  448. gc_wszDavType_Date_ISO8601);
  449. }
  450. return W_DAV_XML_NODE_NOT_CONSTRUCTED;
  451. }
  452. SCODE
  453. CEmitterNode::ScAddInt64Node (
  454. /* [in] */ LPCWSTR pwszTag,
  455. /* [in] */ LARGE_INTEGER * pli,
  456. /* [in] */ CEmitterNode& en)
  457. {
  458. WCHAR rgwch[36];
  459. Assert (pli);
  460. _ui64tow (pli->QuadPart, rgwch, 10);
  461. return ScAddNode (pwszTag, en, rgwch,gc_wszDavType_Int);
  462. }
  463. SCODE
  464. CEmitterNode::ScAddBoolNode (
  465. /* [in] */ LPCWSTR pwszTag,
  466. /* [in] */ BOOL f,
  467. /* [in] */ CEmitterNode& en)
  468. {
  469. return ScAddNode (pwszTag,
  470. en,
  471. (f ? gc_wsz1 : gc_wsz0),
  472. gc_wszDavType_Boolean);
  473. }
  474. SCODE
  475. CEmitterNode::ScAddBase64Node (
  476. /* [in] */ LPCWSTR pwszTag,
  477. /* [in] */ ULONG cb,
  478. /* [in] */ LPVOID pv,
  479. /* [in] */ CEmitterNode& en,
  480. /* [in] */ BOOL fSupressType,
  481. /* [in] */ BOOL fUseBinHexIfNoValue)
  482. {
  483. auto_heap_ptr<WCHAR> pwszBuf;
  484. Assert (pwszTag);
  485. Assert (pv);
  486. // If they didn't request type supression, then label this node
  487. // with the correct type -- bin.base64
  488. //
  489. LPCWSTR pwszType;
  490. if (fSupressType)
  491. {
  492. pwszType = NULL;
  493. }
  494. else
  495. {
  496. // If fUseBinHexIfNoValue is TRUE AND cb = 0, then use "bin.hex"
  497. // as the type rather than bin.base64. This is to handle WebFolders (shipped Office9)
  498. // which doesn't seem to handle 0 length bin.base64 properties correctly
  499. // (fails).
  500. //
  501. if (fUseBinHexIfNoValue && (0 == cb))
  502. pwszType = gc_wszDavType_Bin_Hex;
  503. else
  504. pwszType = gc_wszDavType_Bin_Base64;
  505. }
  506. if (cb)
  507. {
  508. // Allocate a buffer big enough for the entire encoded string.
  509. // Base64 uses 4 chars out for each 3 bytes in, AND if there is ANY
  510. // "remainder", it needs another 4 chars to encode the remainder.
  511. // ("+2" BEFORE "/3" ensures that we count any remainder as a whole
  512. // set of 3 bytes that need 4 chars to hold the encoding.)
  513. // We also need one char for terminal NULL of our string --
  514. // CbSizeWsz takes care of that for the alloc, and we explicitly pass
  515. // cchBuf+1 for the call to EncodeBase64.
  516. //
  517. ULONG cchBuf = CchNeededEncodeBase64 (cb);
  518. pwszBuf = static_cast<LPWSTR>(ExAlloc(CbSizeWsz(cchBuf)));
  519. EncodeBase64 (reinterpret_cast<BYTE*>(pv), cb, pwszBuf, cchBuf + 1);
  520. }
  521. return ScAddNode (pwszTag, en, pwszBuf, pwszType);
  522. }