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.

838 lines
18 KiB

  1. /*
  2. * X N O D E . C P P
  3. *
  4. * XML emitter processing
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. #include "_xmllib.h"
  9. #include <string.h>
  10. #include <stdio.h>
  11. // class CXNode - Emitting ---------------------------------------------------
  12. //
  13. // Our own version of WideCharToMultiByte(CP_UTF8, ...)
  14. //
  15. // UTF-8 multi-byte encoding. See Appendix A.2 of the Unicode book for
  16. // more info.
  17. //
  18. // Unicode value 1st byte 2nd byte 3rd byte
  19. // 000000000xxxxxxx 0xxxxxxx
  20. // 00000yyyyyxxxxxx 110yyyyy 10xxxxxx
  21. // zzzzyyyyyyxxxxxx 1110zzzz 10yyyyyy 10xxxxxx
  22. //
  23. inline
  24. VOID WideCharToUTF8Chars (WCHAR wch, BYTE * pb, UINT * pib)
  25. {
  26. Assert (pb);
  27. Assert (pib);
  28. UINT ib = *pib;
  29. // single-byte: 0xxxxxxx
  30. //
  31. if (wch < 0x80)
  32. {
  33. pb[ib] = static_cast<BYTE>(wch);
  34. }
  35. //
  36. // two-byte: 110xxxxx 10xxxxxx
  37. //
  38. else if (wch < 0x800)
  39. {
  40. // Because we alloc'd two extra-bytes,
  41. // we know there is room at the tail of
  42. // the buffer for the overflow...
  43. //
  44. pb[ib++] = static_cast<BYTE>((wch >> 6) | 0xC0);
  45. pb[ib] = static_cast<BYTE>((wch & 0x3F) | 0x80);
  46. }
  47. //
  48. // three-byte: 1110xxxx 10xxxxxx 10xxxxxx
  49. //
  50. else
  51. {
  52. // Because we alloc'd two extra-bytes,
  53. // we know there is room at the tail of
  54. // the buffer for the overflow...
  55. //
  56. pb[ib++] = static_cast<BYTE>((wch >> 12) | 0xE0);
  57. pb[ib++] = static_cast<BYTE>(((wch >> 6) & 0x3F) | 0x80);
  58. pb[ib] = static_cast<BYTE>((wch & 0x3F) | 0x80);
  59. }
  60. *pib = ib;
  61. }
  62. SCODE
  63. CXNode::ScAddUnicodeResponseBytes (
  64. /* [in] */ UINT cch,
  65. /* [in] */ LPCWSTR pcwsz)
  66. {
  67. SCODE sc = S_OK;
  68. // Argh! We need to have a buffer to fill that is
  69. // at least 3 bytes long for the odd occurrence of a
  70. // single unicode char with significant bits above
  71. // 0x7f.
  72. //
  73. UINT cb = min (cch + 2, CB_XMLBODYPART_SIZE);
  74. // We really can handle zero bytes being sloughed into
  75. // the buffer.
  76. //
  77. UINT ib;
  78. UINT iwch;
  79. CStackBuffer<BYTE,512> pb;
  80. if (NULL == pb.resize(cb))
  81. {
  82. sc = E_OUTOFMEMORY;
  83. goto ret;
  84. }
  85. for (iwch = 0; iwch < cch; )
  86. {
  87. for (ib = 0;
  88. (ib < cb-2) && (iwch < cch);
  89. ib++, iwch++)
  90. {
  91. WideCharToUTF8Chars (pcwsz[iwch], pb.get(), &ib);
  92. }
  93. // Add the bytes
  94. //
  95. Assert (ib <= cb);
  96. sc = m_pxb->ScAddTextBytes (ib, reinterpret_cast<LPSTR>(pb.get()));
  97. if (FAILED(sc))
  98. goto ret;
  99. }
  100. ret:
  101. return sc;
  102. }
  103. SCODE
  104. CXNode::ScAddEscapedValueBytes (UINT cch, LPCSTR psz)
  105. {
  106. SCODE sc = S_OK;
  107. const CHAR* pch;
  108. const CHAR* pchLast;
  109. for (pchLast = pch = psz; pch < psz + cch; pch++)
  110. {
  111. // Character Range
  112. // [2] Char ::= #x9
  113. // | #xA
  114. // | #xD
  115. // | [#x20-#xD7FF]
  116. // | [#xE000-#xFFFD]
  117. // | [#x10000-#x10FFFF]
  118. //
  119. // /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
  120. //
  121. // Valid characters also escaped in values:
  122. //
  123. // & -- escaped as &amp;
  124. // < -- excaped as &lt;
  125. // > -- excaped as &gt;
  126. //
  127. if ('&' == *pch)
  128. {
  129. // Add the bytes up to this position
  130. //
  131. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  132. if (FAILED(sc))
  133. goto ret;
  134. // Add the escape sequence
  135. //
  136. sc = m_pxb->ScAddTextBytes (CchConstString(gc_szAmp), gc_szAmp);
  137. if (FAILED(sc))
  138. goto ret;
  139. // Update pchLast to account for what has been emitted
  140. //
  141. pchLast = pch + 1;
  142. }
  143. else if ('<' == *pch)
  144. {
  145. // Add the bytes up to this position
  146. //
  147. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  148. if (FAILED(sc))
  149. goto ret;
  150. // Add the escape sequence
  151. //
  152. sc = m_pxb->ScAddTextBytes (CchConstString(gc_szLessThan), gc_szLessThan);
  153. if (FAILED(sc))
  154. goto ret;
  155. // Update pchLast to account for what has been emitted
  156. //
  157. pchLast = pch + 1;
  158. }
  159. else if ('>' == *pch)
  160. {
  161. // Add the bytes up to this position
  162. //
  163. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  164. if (FAILED(sc))
  165. goto ret;
  166. // Add the escape sequence
  167. //
  168. sc = m_pxb->ScAddTextBytes (CchConstString(gc_szGreaterThan), gc_szGreaterThan);
  169. if (FAILED(sc))
  170. goto ret;
  171. // Update pchLast to account for what has been emitted
  172. //
  173. pchLast = pch + 1;
  174. }
  175. else if ( (0x9 > static_cast<BYTE>(*pch))
  176. || (0xB == *pch)
  177. || (0xC == *pch)
  178. || ((0x20 > *pch) && (0xD < *pch)))
  179. {
  180. char rgch[10];
  181. // Add the bytes up to this position
  182. //
  183. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  184. if (FAILED(sc))
  185. goto ret;
  186. // Add the escape sequence...
  187. //
  188. sprintf (rgch, "&#x%02X;", *pch);
  189. Assert (strlen(rgch) == CchConstString("&#x00;"));
  190. sc = m_pxb->ScAddTextBytes (CchConstString("&#x00;"), rgch);
  191. if (FAILED(sc))
  192. goto ret;
  193. pchLast = pch + 1;
  194. }
  195. else if (pch - pchLast + 1 >= CB_XMLBODYPART_SIZE)
  196. {
  197. // Break up if the bodyparts gets too big
  198. //
  199. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast + 1), pchLast);
  200. if (FAILED(sc))
  201. goto ret;
  202. pchLast = pch + 1;
  203. }
  204. }
  205. // Add any remaining bytes
  206. //
  207. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  208. if (FAILED(sc))
  209. goto ret;
  210. ret:
  211. return sc;
  212. }
  213. SCODE
  214. CXNode::ScAddEscapedAttributeBytes (UINT cch, LPCSTR psz)
  215. {
  216. SCODE sc = S_OK;
  217. const CHAR* pch;
  218. const CHAR* pchLast;
  219. for (pchLast = pch = psz; pch < psz + cch; pch++)
  220. {
  221. // Characters escaped in values:
  222. //
  223. // & -- escaped as &amp;
  224. // " -- excaped as &quot;
  225. //
  226. if ('&' == *pch)
  227. {
  228. // Add the bytes up to this position
  229. //
  230. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  231. if (FAILED(sc))
  232. goto ret;
  233. // Add the escape sequence
  234. //
  235. sc = m_pxb->ScAddTextBytes (CchConstString(gc_szAmp), gc_szAmp);
  236. if (FAILED(sc))
  237. goto ret;
  238. // Update pchLast to account for what has been emitted
  239. //
  240. pchLast = pch + 1;
  241. }
  242. else if ('"' == *pch)
  243. {
  244. // Add the bytes up to this position
  245. //
  246. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  247. if (FAILED(sc))
  248. goto ret;
  249. // Add the escape sequence
  250. //
  251. sc = m_pxb->ScAddTextBytes (CchConstString(gc_szQuote), gc_szQuote);
  252. if (FAILED(sc))
  253. goto ret;
  254. // Update pchLast to account for what has been emitted
  255. //
  256. pchLast = pch + 1;
  257. }
  258. else if ((0x9 > static_cast<BYTE>(*pch))
  259. || (0xB == *pch)
  260. || (0xC == *pch)
  261. || ((0x20 > *pch) && (0xD < *pch)))
  262. {
  263. char rgch[10];
  264. // Add the bytes up to this position
  265. //
  266. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  267. if (FAILED(sc))
  268. goto ret;
  269. // Add the escape sequence...
  270. //
  271. sprintf (rgch, "&#x%02X;", *pch);
  272. Assert (strlen(rgch) == CchConstString("&#x00;"));
  273. sc = m_pxb->ScAddTextBytes (CchConstString("&#x00;"), rgch);
  274. if (FAILED(sc))
  275. goto ret;
  276. pchLast = pch + 1;
  277. }
  278. }
  279. // Add any remaining bytes
  280. //
  281. sc = m_pxb->ScAddTextBytes (static_cast<UINT>(pch - pchLast), pchLast);
  282. if (FAILED(sc))
  283. goto ret;
  284. ret:
  285. return sc;
  286. }
  287. // class CXNode - Construction -----------------------------------------------
  288. //
  289. SCODE
  290. CXNode::ScWriteTagName ()
  291. {
  292. SCODE sc = S_OK;
  293. // If there is a namespace associated with this node,
  294. // when writing out the tag name, add the alias and a
  295. // separator to the data stream.
  296. //
  297. if (m_pns.get() && m_pns->CchAlias())
  298. {
  299. // Add the alias
  300. //
  301. sc = ScAddUnicodeResponseBytes (m_pns->CchAlias(), m_pns->PszAlias());
  302. if (FAILED(sc))
  303. goto ret;
  304. // Add in the separator
  305. //
  306. sc = m_pxb->ScAddTextBytes(1, &gc_chColon);
  307. if (FAILED(sc))
  308. goto ret;
  309. }
  310. // Write the tag
  311. //
  312. Assert (m_pwszTagEscaped.get());
  313. sc = ScAddUnicodeResponseBytes (m_cchTagEscaped, m_pwszTagEscaped.get());
  314. if (FAILED(sc))
  315. goto ret;
  316. ret:
  317. return sc;
  318. }
  319. SCODE
  320. CXNode::ScSetTag (CXMLEmitter* pmsr, UINT cchTag, LPCWSTR pwszTag)
  321. {
  322. LPCWSTR pwszName = pwszTag;
  323. SCODE sc = S_OK;
  324. BOOL fAddNmspc = FALSE;
  325. UINT cch = 0;
  326. UINT cchName = 0;
  327. UINT cchTagEscaped = 64;
  328. auto_heap_ptr<WCHAR> pwszTagEscaped;
  329. // Namespace nodes do not have a namespace associated with them,
  330. // so don't even bother looking...
  331. //
  332. switch (m_xnt)
  333. {
  334. case XN_ELEMENT:
  335. case XN_ATTRIBUTE:
  336. // See if a namespace applies to this tag
  337. //
  338. cch = CchNmspcFromTag (cchTag, pwszTag, &pwszName);
  339. if (0 == cch)
  340. {
  341. m_fHasEmptyNamespace = TRUE;
  342. }
  343. else
  344. {
  345. // Find the namespace to use
  346. //
  347. sc = pmsr->ScFindNmspc (pwszTag, cch, m_pns);
  348. if (FAILED (sc))
  349. goto ret;
  350. // If a new namespace is added in the local namespace
  351. // cache, make sure we emit it in the node
  352. //
  353. //$NOTE: this is how we handle pilot namespace, this is
  354. //$NOTE: is NOT the normal way of handling namespaces. All
  355. //$NOTE: common namespaces should be preloaded.
  356. //$NOTE:
  357. //
  358. fAddNmspc = (sc == S_FALSE);
  359. // We should have preloaded all namespaces. The pilot
  360. // namespace is handled here to avoid emitting invalid
  361. // xml. But we should look into the reason why the pilot
  362. // namespace comes up. so assert here.
  363. //
  364. // Note that this assert should be removed if we decide
  365. // we want to leave uncommon namesapces not preloaded and
  366. // expect them to be treated as pilot namespaces.
  367. //
  368. AssertSz(!fAddNmspc, "Pilot namespace found, safe to ingore,"
  369. "but please raid against HTTP-DAV");
  370. }
  371. break;
  372. case XN_NAMESPACE:
  373. break;
  374. }
  375. // Record the new tag and\or its length
  376. //
  377. // NOTE: the item that goes into the tag cache is the name
  378. // of the property with the namespace stripped off. This is
  379. // important to know when doing searches in the tag cache.
  380. //
  381. cchName = static_cast<UINT>(pwszTag + cchTag - pwszName);
  382. if (0 == cchName )
  383. {
  384. // We really need to have a tag that has a value. Empty
  385. // tags produce invalid XML.
  386. //
  387. sc = E_DAV_INVALID_PROPERTY_NAME;
  388. goto ret;
  389. }
  390. sc = CXAtomCache::ScCacheAtom (&pwszName, cchName);
  391. if (FAILED (sc))
  392. goto ret;
  393. // ScSetTag shouldn't have been called for this node.
  394. //
  395. Assert (!m_pwszTagEscaped.get());
  396. // Allocate buffer for the property tag.
  397. //
  398. pwszTagEscaped = static_cast<WCHAR*>(ExAlloc(CbSizeWsz(cchTagEscaped)));
  399. if (!pwszTagEscaped.get())
  400. {
  401. sc = E_OUTOFMEMORY;
  402. goto ret;
  403. }
  404. // Escape the tag name as required.
  405. //
  406. // If we have an empty namespace, we need to impose additional
  407. // restrictions on the first character of the property name because
  408. // it will be the first character of the xml node, and the first
  409. // character of an xml node can only be a letter or an underscore
  410. // (numbers, etc. are not allowed).
  411. //
  412. // Note: This will disallow an xml node <123> because it is invalid
  413. // xml, but it will ALLOW the xml node <a:123> even though this is
  414. // also invalid. This is by design because most xml parsers will handle
  415. // this appropriately, and it makes more sense to clients.
  416. //
  417. sc = ScEscapePropertyName (pwszName, cchName, pwszTagEscaped.get(), &cchTagEscaped, m_fHasEmptyNamespace);
  418. if (S_FALSE == sc)
  419. {
  420. pwszTagEscaped.clear();
  421. pwszTagEscaped = static_cast<WCHAR*>(ExAlloc(CbSizeWsz(cchTagEscaped)));
  422. if (!pwszTagEscaped.get())
  423. {
  424. sc = E_OUTOFMEMORY;
  425. goto ret;
  426. }
  427. sc = ScEscapePropertyName (pwszName, cchName, pwszTagEscaped.get(), &cchTagEscaped, m_fHasEmptyNamespace);
  428. Assert (S_OK == sc);
  429. }
  430. m_pwszTagEscaped = pwszTagEscaped.relinquish();
  431. m_cchTagEscaped = cchTagEscaped;
  432. // Start a new node if XN_ELEMENT
  433. //
  434. if (m_xnt == XN_ELEMENT)
  435. {
  436. sc = m_pxb->ScAddTextBytes (1, "<");
  437. if (FAILED(sc))
  438. goto ret;
  439. }
  440. sc = ScWriteTagName();
  441. if (FAILED(sc))
  442. goto ret;
  443. if (fAddNmspc)
  444. {
  445. // Add the namespace attribute in the node if necessary
  446. //
  447. sc = pmsr->ScAddNmspc (m_pns, this);
  448. if (FAILED(sc))
  449. goto ret;
  450. // Save the emitter which can be used later to remove the temporary nmspc
  451. //
  452. m_pmsr = pmsr;
  453. }
  454. ret:
  455. return sc;
  456. }
  457. SCODE
  458. CXNode::ScDone ()
  459. {
  460. SCODE sc = S_OK;
  461. // This method should never be called twice
  462. //
  463. Assert (!m_fDone);
  464. switch (m_xnt)
  465. {
  466. case XN_ELEMENT:
  467. if (!m_pwszTagEscaped.get())
  468. {
  469. //$ RAID: 85824: When an invalid property name is unpacked,
  470. // ScSetTag will fail with E_DAV_INVALID_PROPERTY_NAME.
  471. //
  472. // Usuallly, the client will fail when it sees any error
  473. // from CXNode methods, but in this case it may choose to
  474. // continue and ignore this node completely.
  475. //
  476. // For us, it's safe to not to emit anything when no tag name
  477. // is available.
  478. //
  479. break;
  480. //
  481. //$RAID: 85824
  482. }
  483. if (m_fNodeOpen)
  484. {
  485. // Node is open, so emit a complete closing node
  486. // </tag>
  487. //
  488. sc = m_pxb->ScAddTextBytes (2, "</");
  489. if (FAILED(sc))
  490. goto ret;
  491. // Add tag
  492. //
  493. sc = ScWriteTagName();
  494. if (FAILED(sc))
  495. goto ret;
  496. // closing
  497. //
  498. sc = m_pxb->ScAddTextBytes (1, ">");
  499. if (FAILED(sc))
  500. goto ret;
  501. }
  502. else
  503. {
  504. // Close directly
  505. //
  506. sc = m_pxb->ScAddTextBytes (2, "/>");
  507. if (FAILED(sc))
  508. goto ret;
  509. }
  510. break;
  511. case XN_NAMESPACE:
  512. // Namespace nodes, should not have a namespace associated with
  513. // them.
  514. //
  515. Assert (NULL == m_pns.get());
  516. //
  517. // Otherwise treat it at an attribute -- and fall through
  518. case XN_ATTRIBUTE:
  519. Assert (m_pwszTagEscaped.get());
  520. break;
  521. }
  522. // Remove the pilot namespace from global cache
  523. //
  524. if (m_pmsr)
  525. m_pmsr->RemovePersisted(m_pns);
  526. m_fDone = TRUE;
  527. ret:
  528. return sc;
  529. }
  530. SCODE
  531. CXNode::ScSetFormatedXML (LPCSTR pszValue, UINT cch)
  532. {
  533. SCODE sc = S_OK;
  534. Assert (m_xnt == XN_ELEMENT);
  535. if (!m_fNodeOpen)
  536. {
  537. // We must have written the tag name
  538. //
  539. Assert (m_pwszTagEscaped.get());
  540. // Now that we are adding value to the element node
  541. // We should write the node open
  542. //
  543. sc = m_pxb->ScAddTextBytes (1, ">");
  544. if (FAILED(sc))
  545. goto ret;
  546. m_fNodeOpen = TRUE;
  547. }
  548. // Add the value directly
  549. //
  550. sc = m_pxb->ScAddTextBytes (cch, pszValue);
  551. if (FAILED(sc))
  552. goto ret;
  553. ret:
  554. return sc;
  555. }
  556. SCODE
  557. CXNode::ScSetFormatedXML (LPCWSTR pwszValue, UINT cch)
  558. {
  559. SCODE sc = S_OK;
  560. Assert (m_xnt == XN_ELEMENT);
  561. if (!m_fNodeOpen)
  562. {
  563. // We must have written the tag name
  564. //
  565. Assert (m_pwszTagEscaped.get());
  566. // Now that we are adding value to the element node
  567. // We should write the node open
  568. //
  569. sc = m_pxb->ScAddTextBytes (1, ">");
  570. if (FAILED(sc))
  571. goto ret;
  572. m_fNodeOpen = TRUE;
  573. }
  574. // Add the value directly
  575. //
  576. sc = ScAddUnicodeResponseBytes (cch, pwszValue);
  577. if (FAILED(sc))
  578. goto ret;
  579. ret:
  580. return sc;
  581. }
  582. SCODE
  583. CXNode::ScSetUTF8Value (LPCSTR pszValue, UINT cch)
  584. {
  585. SCODE sc = S_OK;
  586. switch (m_xnt)
  587. {
  588. case XN_ELEMENT:
  589. if (!m_fNodeOpen)
  590. {
  591. // We must have written the tag name
  592. //
  593. Assert (m_pwszTagEscaped.get());
  594. // Now that we are adding value to the element node
  595. // We should write the node open
  596. //
  597. sc = m_pxb->ScAddTextBytes (1, ">");
  598. if (FAILED(sc))
  599. goto ret;
  600. m_fNodeOpen = TRUE;
  601. }
  602. // Write the value
  603. //
  604. sc = ScAddEscapedValueBytes (cch, pszValue);
  605. if (FAILED(sc))
  606. goto ret;
  607. break;
  608. case XN_NAMESPACE:
  609. case XN_ATTRIBUTE:
  610. // Write the value directly
  611. //
  612. sc = ScAddEscapedAttributeBytes (cch, pszValue);
  613. if (FAILED(sc))
  614. goto ret;
  615. break;
  616. }
  617. ret:
  618. return sc;
  619. }
  620. SCODE
  621. CXNode::ScSetValue (LPCSTR pszValue, UINT cch)
  622. {
  623. // Ok, against all better judgement, we need to take this
  624. // multi-byte string and convert it to unicode before doing
  625. // any UTF8 processing on it.
  626. //
  627. // Translations from multibyte to unicode, can never grow in
  628. // character counts, so we are relatively safe allocating this
  629. // on the stack.
  630. //
  631. UINT cchUnicode;
  632. CStackBuffer<WCHAR,512> pwsz;
  633. if (NULL == pwsz.resize(CbSizeWsz(cch)))
  634. return E_OUTOFMEMORY;
  635. cchUnicode = MultiByteToWideChar (GetACP(),
  636. 0,
  637. pszValue,
  638. cch,
  639. pwsz.get(),
  640. cch + 1);
  641. // Terminate the string
  642. //
  643. Assert ((0 == cchUnicode) || (0 != *(pwsz.get() + cchUnicode - 1)));
  644. *(pwsz.get() + cchUnicode) = 0;
  645. // Set the value
  646. //
  647. return ScSetValue (pwsz.get(), cchUnicode);
  648. }
  649. SCODE
  650. CXNode::ScSetValue (LPCWSTR pcwsz, UINT cch)
  651. {
  652. SCODE sc = S_OK;
  653. // Argh! We need to have a buffer to fill that is
  654. // at least 3 bytes long for the odd occurrence of a
  655. // single unicode char with significant bits above
  656. // 0x7f.
  657. // Note that when the value
  658. UINT cb = min (cch + 2, CB_XMLBODYPART_SIZE);
  659. // We really can handle zero bytes being sloughed into
  660. // the buffer.
  661. //
  662. UINT ib;
  663. UINT iwch;
  664. CStackBuffer<BYTE,512> pb;
  665. if (NULL == pb.resize(cb))
  666. {
  667. sc = E_OUTOFMEMORY;
  668. goto ret;
  669. }
  670. for (iwch = 0; iwch < cch; )
  671. {
  672. for (ib = 0; (ib < cb-2) && (iwch < cch); ib++, iwch++)
  673. WideCharToUTF8Chars (pcwsz[iwch], pb.get(), &ib);
  674. // Add the bytes
  675. //
  676. Assert (ib <= cb);
  677. sc = ScSetUTF8Value (reinterpret_cast<LPSTR>(pb.get()), ib);
  678. if (FAILED(sc))
  679. goto ret;
  680. }
  681. ret:
  682. return sc;
  683. }
  684. SCODE
  685. CXNode::ScGetChildNode (XNT xntType, CXNode **ppxnChild)
  686. {
  687. SCODE sc = S_OK;
  688. auto_ref_ptr<CXNode> pxn;
  689. Assert (ppxnChild);
  690. if (XN_ELEMENT == xntType)
  691. {
  692. // Now that new element child node is added, then this node is done open.
  693. // i.e close by ">", instead of "/>"
  694. //
  695. if (!m_fNodeOpen)
  696. {
  697. sc = m_pxb->ScAddTextBytes (1, ">");
  698. if (FAILED(sc))
  699. goto ret;
  700. // Then this node is an open node
  701. //
  702. m_fNodeOpen = TRUE;
  703. }
  704. }
  705. else
  706. {
  707. Assert ((XN_ATTRIBUTE == xntType) || (XN_NAMESPACE == xntType));
  708. }
  709. // Create the child node
  710. //
  711. pxn.take_ownership (new CXNode(xntType, m_pxb));
  712. if (!pxn.get())
  713. {
  714. sc = E_OUTOFMEMORY;
  715. goto ret;
  716. }
  717. // Pass back
  718. //
  719. *ppxnChild = pxn.relinquish();
  720. ret:
  721. return sc;
  722. }