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.

930 lines
25 KiB

  1. #include "precomp.h"
  2. #include "..\mcinc.h"
  3. #include "parser.h"
  4. ////////////////////////////////////////////
  5. // CMarsXMLFactory
  6. ////////////////////////////////////////////
  7. CMarsXMLFactory::CMarsXMLFactory()
  8. : m_elemStack(10)
  9. {
  10. ATLASSERT(! m_ptiaTags);
  11. }
  12. CMarsXMLFactory::~CMarsXMLFactory()
  13. {
  14. if (!m_elemStack.IsEmpty())
  15. {
  16. do
  17. {
  18. m_elemStack.Top()->Release_Ref();
  19. m_elemStack.Pop();
  20. }
  21. while (! m_elemStack.IsEmpty());
  22. }
  23. }
  24. // IUnknown
  25. IMPLEMENT_ADDREF_RELEASE(CMarsXMLFactory);
  26. STDMETHODIMP CMarsXMLFactory::QueryInterface(REFIID iid, void **ppvObject)
  27. {
  28. HRESULT hr;
  29. if (iid == IID_IXMLNodeFactory ||
  30. iid == IID_IUnknown )
  31. {
  32. AddRef();
  33. *ppvObject = (IXMLNodeFactory *) this;
  34. hr = S_OK;
  35. }
  36. else
  37. {
  38. *ppvObject = NULL;
  39. hr = E_NOINTERFACE;
  40. }
  41. return hr;
  42. }
  43. // IXMLNodeFactory
  44. HRESULT CMarsXMLFactory::NotifyEvent(IXMLNodeSource *pSource,
  45. XML_NODEFACTORY_EVENT iEvt)
  46. {
  47. return S_OK;
  48. }
  49. HRESULT CMarsXMLFactory::BeginChildren(IXMLNodeSource *pSource,
  50. XML_NODE_INFO *pNodeInfo)
  51. {
  52. return S_OK;
  53. }
  54. HRESULT CMarsXMLFactory::EndChildren(IXMLNodeSource *pSource,
  55. BOOL fEmpty,
  56. XML_NODE_INFO *pNodeInfo)
  57. {
  58. // This call means that the node is completed; all the children and innertext
  59. // have been processed, and the </tag> has been reached. This is the time to
  60. // close up the element.
  61. // Note: any return value other than S_OK indicates failure
  62. HRESULT hr = S_OK;
  63. // It is assumed that the top of the stack is the node whose children are
  64. // ending
  65. if (! m_elemStack.IsEmpty())
  66. {
  67. HRESULT hrTemp;
  68. CXMLElement *pxElem = m_elemStack.Top();
  69. m_elemStack.Pop();
  70. // OnNodeComplete should return S_OK for need to be added to parent,
  71. // S_FALSE for do not need to be added to parent, and
  72. // any failure codes for critical problems
  73. hrTemp = pxElem->OnNodeComplete();
  74. if ((hrTemp == S_OK) && !m_elemStack.IsEmpty())
  75. {
  76. // Addchild takes ownership of the element on S_OK.
  77. // Otherwise, we delete the element here.
  78. // we must delete the element here.
  79. // NOTE: Parent should Add_Ref the child
  80. hrTemp = m_elemStack.Top()->AddChild(pxElem);
  81. }
  82. else
  83. {
  84. if(FAILED(hrTemp))
  85. {
  86. hr = hrTemp;
  87. }
  88. }
  89. pxElem->Release_Ref();
  90. }
  91. return hr;
  92. }
  93. HRESULT CMarsXMLFactory::Error(IXMLNodeSource *pSource,
  94. HRESULT hrErrorCode, USHORT cNumRecs,
  95. XML_NODE_INFO **apNodeInfo)
  96. {
  97. // break out of the xmlparser->Run(-1) with error message E_INVALIDARG
  98. // on any xml syntax erros
  99. return E_INVALIDARG;
  100. }
  101. HRESULT CMarsXMLFactory::CreateNode(IXMLNodeSource *pSource,
  102. PVOID pNodeParent, USHORT cNumRecs,
  103. XML_NODE_INFO **apNodeInfo)
  104. {
  105. // This call is made when a opening tag is encoutered, ie
  106. // <data>... or <data/> (an empty tag) apNodeInfo is an array of
  107. // node infos; the first is the name of the tag, the rest are a
  108. // series of attributes and other such things which were bundled
  109. // in the tag, ie <data size="100">
  110. // We only recognize attributes;
  111. // SetElementAttributes handles those
  112. HRESULT hr = S_OK;
  113. ATLASSERT(cNumRecs > 0);
  114. switch (apNodeInfo[0]->dwType)
  115. {
  116. case XML_ELEMENT:
  117. {
  118. CXMLElement *pxElem;
  119. hr = CreateElement(apNodeInfo[0]->pwcText, apNodeInfo[0]->ulLen, &pxElem);
  120. if (hr == S_OK)
  121. {
  122. hr = SetElementAttributes(pxElem, apNodeInfo + 1, cNumRecs - 1);
  123. if (SUCCEEDED(hr))
  124. {
  125. m_elemStack.Push(pxElem); // the stack holds our Ref
  126. }
  127. else
  128. {
  129. pxElem->Release_Ref();
  130. }
  131. }
  132. break;
  133. }
  134. case XML_PCDATA:
  135. case XML_CDATA:
  136. {
  137. // since this is the first node in the node-info, this must be the
  138. // inner text in a tag (<name>Johhny</name> - we're talking about the
  139. // string "Johhny" for example).
  140. if (! m_elemStack.IsEmpty())
  141. {
  142. hr = m_elemStack.Top()->SetInnerXMLText(apNodeInfo[0]->pwcText,
  143. apNodeInfo[0]->ulLen);
  144. }
  145. break;
  146. }
  147. default:
  148. {
  149. // ignore all other types of nodes (whitespace, comment, and unknown)
  150. break;
  151. }
  152. }
  153. return hr;
  154. }
  155. HRESULT CMarsXMLFactory::SetElementAttributes(CXMLElement *pxElem,
  156. XML_NODE_INFO **apNodeInfo,
  157. ULONG cInfoLen)
  158. // apNodeInfo is the beginning of XML_NODE_INFO attributes: the first node is an
  159. // XML_ATTRIBUTE with the name of an attribute, the second node is an XML_PCDATA with
  160. // the value, and then the 3rd and 4th are similar, if they exist, and so on.
  161. // pElement's SetAttribute method is called for all the attribute name/value pairs,
  162. // the return result is S_OK, E_OUTOFMEMORY, or S_FALSE (xml symantic err)
  163. {
  164. ULONG i;
  165. HRESULT hr = S_OK;
  166. i = 0;
  167. while (SUCCEEDED(hr) && (i < cInfoLen))
  168. {
  169. if (apNodeInfo[i]->dwType == XML_ATTRIBUTE)
  170. {
  171. // move to the next ap node to get the value of the attribute
  172. i++;
  173. if ((i < cInfoLen) && (apNodeInfo[i]->dwType == XML_PCDATA))
  174. {
  175. // Set attribute should return S_OK for success, S_FALSE for
  176. // unexpected attribute, and may return critical errors such as
  177. // E_OUTOFMEMORY
  178. hr = pxElem->SetAttribute(apNodeInfo[i-1]->pwcText,
  179. apNodeInfo[i-1]->ulLen,
  180. apNodeInfo[i]->pwcText,
  181. apNodeInfo[i]->ulLen);
  182. }
  183. else
  184. {
  185. continue;
  186. }
  187. }
  188. i++;
  189. }
  190. return hr;
  191. }
  192. HRESULT CMarsXMLFactory::Run(IStream *pisDoc)
  193. {
  194. if (!m_ptiaTags)
  195. return E_UNEXPECTED; // EPC
  196. if (!pisDoc)
  197. return E_INVALIDARG; // EPC
  198. HRESULT hr;
  199. CComPtr<IXMLParser> spParser;
  200. hr = spParser.CoCreateInstance(CLSID_XMLParser);
  201. if (SUCCEEDED(hr))
  202. {
  203. CComPtr<IUnknown> spUnk;
  204. hr = pisDoc->QueryInterface(IID_IUnknown, (void **)&spUnk);
  205. if (SUCCEEDED(hr))
  206. {
  207. hr = spParser->SetInput(spUnk);
  208. if (SUCCEEDED(hr))
  209. {
  210. hr = spParser->SetFactory(this);
  211. if (SUCCEEDED(hr))
  212. {
  213. hr = spParser->Run(-1);
  214. ATLASSERT(hr != E_PENDING);
  215. if (FAILED(hr))
  216. hr = spParser->GetLastError();
  217. }
  218. }
  219. }
  220. else
  221. hr = E_UNEXPECTED;
  222. }
  223. return hr;
  224. }
  225. void CMarsXMLFactory::SetTagInformation(TagInformation **ptiaTags)
  226. {
  227. m_ptiaTags = ptiaTags;
  228. }
  229. void CMarsXMLFactory::SetLParam(LONG lParamNew)
  230. {
  231. m_lParamArgument = lParamNew;
  232. }
  233. HRESULT CMarsXMLFactory::CreateElement(LPCWSTR wzTagName, ULONG cLen, CXMLElement **ppxElem)
  234. {
  235. // Look in m_ptiaTags for a name that matches wzTagName, and call upon the corresponding
  236. // creation function once found
  237. // REturns S_FALSE if the tag is not found
  238. ATLASSERT(ppxElem);
  239. HRESULT hr = S_FALSE;
  240. int i;
  241. *ppxElem = NULL;
  242. if (m_ptiaTags)
  243. {
  244. for (i = 0; m_ptiaTags[i]; i++)
  245. {
  246. // if m_ptiaTags[i]->wzTagName is ever NULL, we will consider this
  247. // the "default" action and call "Create"
  248. #ifdef DEBUG
  249. // TODO: for now, we assert that the generic element is VT_BSTR, but
  250. // it would be cool to have a "Generic number" element, "Generic Time", etc...
  251. if (m_ptiaTags[i]->wzTagName == NULL)
  252. ATLASSERT(m_ptiaTags[i]->vt == VT_BSTR);
  253. #endif
  254. if ((m_ptiaTags[i]->wzTagName == NULL)
  255. || (StrEqlNToSZ(wzTagName, cLen, m_ptiaTags[i]->wzTagName)))
  256. {
  257. *ppxElem = m_ptiaTags[i]->funcCreate(m_ptiaTags[i]->wzTagName, m_ptiaTags[i]->vt,
  258. m_ptiaTags[i]->ptiaChildren,
  259. m_ptiaTags[i]->paiaAttributes,
  260. m_lParamArgument);
  261. hr = *ppxElem ? S_OK : E_OUTOFMEMORY;
  262. break;
  263. }
  264. }
  265. }
  266. if (hr == S_FALSE)
  267. {
  268. SpewUnrecognizedString(wzTagName, cLen, L"Tag name not recognized and being ignored, ");
  269. }
  270. return hr;
  271. }
  272. /////////////////////////////////////////////
  273. // CXMLElement
  274. /////////////////////////////////////////////
  275. HRESULT CXMLElement::OnNodeComplete()
  276. {
  277. return S_FALSE;
  278. }
  279. HRESULT CXMLElement::AddChild(CXMLElement *pxeChild)
  280. {
  281. ATLASSERT(pxeChild);
  282. return S_FALSE;
  283. }
  284. HRESULT CXMLElement::SetAttribute(LPCWSTR wzName, ULONG cLenName, LPCWSTR pwzValue, ULONG cLenValue)
  285. {
  286. SpewUnrecognizedString(wzName, cLenName, L"Base class SetAttribute called, attribute name ");
  287. return S_FALSE;
  288. }
  289. HRESULT CXMLElement::SetInnerXMLText(LPCWSTR pwzText, ULONG cLen)
  290. {
  291. return S_FALSE;
  292. }
  293. HRESULT CXMLElement::GetAttribute(LPCWSTR wzName, VARIANT *pvarOut)
  294. {
  295. if (pvarOut)
  296. {
  297. VariantInit(pvarOut);
  298. }
  299. return E_INVALIDARG;
  300. }
  301. HRESULT CXMLElement::GetContent(VARIANT *pvarOut)
  302. {
  303. if (pvarOut)
  304. {
  305. VariantInit(pvarOut);
  306. }
  307. return E_INVALIDARG;
  308. }
  309. void CXMLElement::FirstChild()
  310. {
  311. }
  312. void CXMLElement::NextChild()
  313. {
  314. }
  315. CXMLElement *CXMLElement::CurrentChild()
  316. {
  317. return NULL;
  318. }
  319. CXMLElement *CXMLElement::DetachCurrentChild()
  320. {
  321. return NULL;
  322. }
  323. BOOL CXMLElement::IsDoneChild()
  324. {
  325. return TRUE;
  326. }
  327. LPCWSTR CXMLElement::GetName()
  328. {
  329. return NULL;
  330. }
  331. struct CAttributeStruct
  332. {
  333. int m_iArrayIndex;
  334. CComVariant m_Variant;
  335. // NOTE: This is only set when m_iArrayIndex is "-1"
  336. CComBSTR m_bstrAttribName;
  337. CAttributeStruct(int iArrayIndex, VARTYPE vt, LPCWSTR wzVal, ULONG cLen,
  338. LPCWSTR pszAttribName = NULL)
  339. {
  340. // must set iArrayIndex to -1 in order to pass in bstrAttribName
  341. ATLASSERT( ((iArrayIndex >= 0) && !pszAttribName)
  342. || pszAttribName);
  343. m_iArrayIndex = iArrayIndex;
  344. if (pszAttribName)
  345. // copy
  346. m_bstrAttribName = pszAttribName;
  347. HRESULT hr;
  348. // We don't call VariantChangeType 'cause wzVal is not null-terminated
  349. switch (vt)
  350. {
  351. case VT_I4:
  352. hr = StrToLongNW(wzVal, cLen, &m_Variant.lVal);
  353. if (SUCCEEDED(hr))
  354. m_Variant.vt = VT_I4;
  355. else
  356. m_Variant.vt = VT_NULL;
  357. break;
  358. case VT_BSTR:
  359. m_Variant = SysAllocStringLen(wzVal, cLen);
  360. break;
  361. case VT_BOOL:
  362. m_Variant = StrToIsTrueNW(wzVal, cLen);
  363. ATLASSERT(m_Variant.vt == VT_BOOL);
  364. break;
  365. default:
  366. ATLASSERT(FALSE);
  367. m_Variant.vt = VT_NULL;
  368. break;
  369. }
  370. }
  371. };
  372. /////////////////////////////////////////////
  373. // CXMLGenericElement
  374. /////////////////////////////////////////////
  375. CXMLGenericElement::CXMLGenericElement(LPCWSTR wzName,
  376. VARTYPE vt,
  377. TagInformation **ptiaChildren,
  378. AttributeInformation **paiaAttributes)
  379. {
  380. m_paiaAttributes = paiaAttributes;
  381. m_ptiaChildren = ptiaChildren;
  382. m_vtData = vt;
  383. m_varData.vt = VT_EMPTY;
  384. m_bstrName = wzName;
  385. ATLASSERT(! m_psnodeAttributes);
  386. // The header node is a member variable.
  387. m_psnodeChildrenFirst = &m_snodeChildrenFirst;
  388. m_psnodeChildrenFirst->m_pvData = NULL;
  389. m_psnodeChildrenFirst->m_psnodeNext = NULL;
  390. m_psnodeChildrenEnd = m_psnodeChildrenFirst;
  391. ATLASSERT(! m_psnodeChildrenIter);
  392. }
  393. CXMLGenericElement::~CXMLGenericElement()
  394. {
  395. CAttributeStruct *pattStruct;
  396. CXMLElement *pxElem;
  397. CSimpleNode *psnodeTemp;
  398. while (m_psnodeAttributes)
  399. {
  400. pattStruct = (CAttributeStruct *) m_psnodeAttributes->m_pvData;
  401. psnodeTemp = m_psnodeAttributes;
  402. m_psnodeAttributes = m_psnodeAttributes->m_psnodeNext;
  403. delete pattStruct;
  404. delete psnodeTemp;
  405. }
  406. // Don't delete the header - a statically allocated member
  407. m_psnodeChildrenFirst = m_psnodeChildrenFirst->m_psnodeNext;
  408. while (m_psnodeChildrenFirst)
  409. {
  410. pxElem = (CXMLElement *) m_psnodeChildrenFirst->m_pvData;
  411. psnodeTemp = m_psnodeChildrenFirst;
  412. m_psnodeChildrenFirst = m_psnodeChildrenFirst->m_psnodeNext;
  413. pxElem->Release_Ref();
  414. delete psnodeTemp;
  415. }
  416. }
  417. HRESULT CXMLGenericElement::SetInnerXMLText(LPCWSTR pwzText, ULONG cLen)
  418. {
  419. HRESULT hr = S_OK;
  420. BOOL fAppend = FALSE;
  421. if ((m_varData.vt != VT_EMPTY) &&
  422. (m_varData.vt != VT_NULL))
  423. {
  424. fAppend = TRUE;
  425. }
  426. m_varData.vt = m_vtData;
  427. switch (m_vtData)
  428. {
  429. case VT_I4:
  430. {
  431. ATLASSERT(!fAppend);
  432. LONG lVal;
  433. hr = StrToLongNW(pwzText, cLen, &lVal);
  434. if (SUCCEEDED(hr))
  435. {
  436. m_varData = lVal;
  437. // this assignment should never fail; any possible errors are unexpected
  438. ATLASSERT(m_varData.vt != VT_ERROR);
  439. }
  440. else
  441. {
  442. SpewUnrecognizedString(pwzText, cLen, L"StrToLongNW failed in SetInnerXMLText, ");
  443. hr = S_FALSE;
  444. }
  445. break;
  446. }
  447. case VT_BSTR:
  448. {
  449. if (fAppend)
  450. {
  451. BSTR bstrOld = m_varData.bstrVal;
  452. UINT cb_bstrOld = SysStringLen(m_varData.bstrVal);
  453. m_varData.bstrVal = SysAllocStringLen(bstrOld, cb_bstrOld + cLen);
  454. if (m_varData.bstrVal)
  455. {
  456. StrCpyN(m_varData.bstrVal + cb_bstrOld, pwzText, cLen + 1);
  457. hr = S_OK;
  458. }
  459. else
  460. {
  461. hr = E_OUTOFMEMORY;
  462. }
  463. SysFreeString(bstrOld);
  464. }
  465. else
  466. {
  467. m_varData.bstrVal = SysAllocStringLen(pwzText, cLen);
  468. if (!m_varData.bstrVal)
  469. hr = E_OUTOFMEMORY;
  470. }
  471. break;
  472. }
  473. case VT_NULL:
  474. case VT_EMPTY:
  475. break;
  476. default:
  477. m_varData = VT_EMPTY;
  478. hr = S_FALSE;
  479. break;
  480. }
  481. return hr;
  482. }
  483. HRESULT CXMLGenericElement::SetAttribute(const WCHAR *pwzName, ULONG cNameLen,
  484. const WCHAR *pwzText, ULONG cTextLen)
  485. {
  486. // It is expected that the number of attributes is small
  487. // Hence we use a simple linked list with O(1) insertions and O(n)queries
  488. // No syntax checking (ie, dups) is done
  489. HRESULT hr = S_FALSE;
  490. int i;
  491. LPCWSTR pszAttribName = NULL;
  492. if (m_paiaAttributes)
  493. {
  494. for (i = 0; m_paiaAttributes[i]; i++)
  495. {
  496. // wzAttName NULL is the "default" attribute
  497. if (m_paiaAttributes[i]->wzAttName == NULL)
  498. {
  499. pszAttribName = pwzName;
  500. break;
  501. }
  502. else if (StrEqlNToSZ(pwzName, cNameLen, m_paiaAttributes[i]->wzAttName))
  503. {
  504. break;
  505. }
  506. }
  507. if (m_paiaAttributes[i])
  508. {
  509. CAttributeStruct *pattStruct;
  510. if (pszAttribName)
  511. {
  512. pattStruct = new CAttributeStruct(-1, m_paiaAttributes[i]->vt,
  513. pwzText, cTextLen, pszAttribName);
  514. }
  515. else
  516. {
  517. pattStruct = new CAttributeStruct(i, m_paiaAttributes[i]->vt,
  518. pwzText, cTextLen, pszAttribName);
  519. }
  520. if (pattStruct)
  521. {
  522. CSimpleNode *psnode = new CSimpleNode();
  523. if (psnode)
  524. {
  525. // add to front of list
  526. psnode->m_psnodeNext = m_psnodeAttributes;
  527. psnode->m_pvData = pattStruct;
  528. m_psnodeAttributes = psnode;
  529. hr = S_OK;
  530. }
  531. else
  532. {
  533. hr = E_OUTOFMEMORY;
  534. delete pattStruct;
  535. }
  536. }
  537. else
  538. {
  539. hr = E_OUTOFMEMORY;
  540. }
  541. }
  542. }
  543. if (hr == S_FALSE)
  544. {
  545. SpewUnrecognizedString(pwzName, cNameLen,
  546. L"Trying to set unrecognized attribute in SetAttribute, ");
  547. }
  548. return hr;
  549. }
  550. HRESULT CXMLGenericElement::GetContent(VARIANT *pvarOut)
  551. {
  552. // Returns S_OK on attribute found, E_INVALIDARG on not.
  553. // ppvarOut can be NULL; if it is not, then it is a pointer to the content VARIANT
  554. HRESULT hr = E_INVALIDARG;
  555. if ((m_varData.vt != VT_EMPTY) && (m_varData.vt != VT_NULL))
  556. {
  557. if (pvarOut)
  558. {
  559. VariantInit(pvarOut);
  560. hr = VariantCopy(pvarOut, &m_varData);
  561. }
  562. }
  563. else
  564. {
  565. if (pvarOut)
  566. {
  567. VariantInit(pvarOut);
  568. }
  569. }
  570. return hr;
  571. }
  572. HRESULT CXMLGenericElement::GetAttribute(LPCWSTR wzName, VARIANT *pvarOut)
  573. {
  574. // Returns S_OK on attribute found, E_INVALIDARG if not.
  575. // ppvarOut can be NULL; if it is not, then it is a pointer to the attribute value VARIANT
  576. // It is expected that the number of attributes is small
  577. // Hence we use a simple linked list with O(1) insertions and O(n)queries
  578. // No syntax checking (ie, dups) is done
  579. HRESULT hr = E_INVALIDARG;
  580. CSimpleNode *psnode = m_psnodeAttributes;
  581. CAttributeStruct *pattStruct;
  582. while (psnode)
  583. {
  584. pattStruct = (CAttributeStruct *) psnode->m_pvData;
  585. if (((pattStruct->m_iArrayIndex < 0) &&
  586. StrEql(wzName, pattStruct->m_bstrAttribName))
  587. || (StrEql(m_paiaAttributes[pattStruct->m_iArrayIndex]->wzAttName, wzName)))
  588. {
  589. hr = S_OK;
  590. if (pvarOut)
  591. {
  592. VariantInit(pvarOut);
  593. VariantCopy(pvarOut, &(pattStruct->m_Variant));
  594. }
  595. break;
  596. }
  597. psnode = psnode->m_psnodeNext;
  598. }
  599. if (!psnode)
  600. {
  601. // don't fire a trace message if our caller is just pinging us
  602. // to see if we have the attribute
  603. if (pvarOut)
  604. {
  605. VariantInit(pvarOut);
  606. }
  607. }
  608. return hr;
  609. }
  610. void CXMLGenericElement::FirstChild()
  611. {
  612. m_psnodeChildrenIter = m_psnodeChildrenFirst->m_psnodeNext;
  613. }
  614. void CXMLGenericElement::NextChild()
  615. {
  616. if (m_psnodeChildrenIter)
  617. {
  618. m_psnodeChildrenIter = m_psnodeChildrenIter->m_psnodeNext;
  619. }
  620. else
  621. {
  622. ATLASSERT(FALSE);
  623. }
  624. }
  625. CXMLElement *CXMLGenericElement::CurrentChild()
  626. {
  627. CXMLElement *pxeReturn;
  628. if (m_psnodeChildrenIter && (m_psnodeChildrenIter != m_psnodeChildrenFirst))
  629. {
  630. pxeReturn = (CXMLElement *) m_psnodeChildrenIter->m_pvData;
  631. }
  632. else
  633. {
  634. ATLASSERT(FALSE);
  635. pxeReturn = NULL;
  636. }
  637. return pxeReturn;
  638. }
  639. // caller gets our ref to the CXMLElement
  640. CXMLElement *CXMLGenericElement::DetachCurrentChild()
  641. {
  642. CXMLElement *pxeReturn;
  643. if (m_psnodeChildrenIter)
  644. {
  645. pxeReturn = (CXMLElement *) m_psnodeChildrenIter->m_pvData;
  646. CSimpleNode *psnodeHack = m_psnodeChildrenFirst;
  647. while (psnodeHack->m_psnodeNext != m_psnodeChildrenIter)
  648. {
  649. psnodeHack = psnodeHack->m_psnodeNext;
  650. // If this assertion is broken, then m_psnodeChildrenIter is not
  651. // in the list
  652. ATLASSERT(psnodeHack);
  653. }
  654. // here psnodeHack=>m_psnodeChildrenIter=>...=>m_psnodeChildrenEnd
  655. // update the end of the list
  656. if (psnodeHack->m_psnodeNext == m_psnodeChildrenEnd)
  657. {
  658. m_psnodeChildrenEnd = psnodeHack;
  659. }
  660. // delete the current NODE (but not the data in the node) and set the iterator
  661. // to the previous node (psnodeHack)
  662. psnodeHack->m_psnodeNext = psnodeHack->m_psnodeNext->m_psnodeNext;
  663. delete m_psnodeChildrenIter;
  664. m_psnodeChildrenIter = psnodeHack;
  665. }
  666. else
  667. {
  668. ATLASSERT(FALSE);
  669. pxeReturn = NULL;
  670. }
  671. return pxeReturn;
  672. }
  673. HRESULT CXMLGenericElement::AddChild(CXMLElement *pxeChild)
  674. {
  675. HRESULT hr = S_FALSE;
  676. LPCWSTR pwzName = pxeChild->GetName();
  677. int i;
  678. if (m_ptiaChildren)
  679. {
  680. for (i = 0; m_ptiaChildren[i]; i++)
  681. {
  682. if (StrEql(m_ptiaChildren[i]->wzTagName, pwzName))
  683. {
  684. break;
  685. }
  686. }
  687. if (m_ptiaChildren[i])
  688. {
  689. CSimpleNode *psnode;
  690. psnode = new CSimpleNode;
  691. if (psnode)
  692. {
  693. pxeChild->Add_Ref();
  694. psnode->m_pvData = (void *) pxeChild;
  695. psnode->m_psnodeNext = NULL;
  696. m_psnodeChildrenEnd->m_psnodeNext = psnode;
  697. m_psnodeChildrenEnd = psnode;
  698. // S_OK to indicate we're taking ownership of the child
  699. hr = S_OK;
  700. }
  701. else
  702. {
  703. hr = E_OUTOFMEMORY;
  704. }
  705. }
  706. }
  707. return hr;
  708. }
  709. BOOL CXMLGenericElement::IsDoneChild()
  710. {
  711. return !(m_psnodeChildrenIter && (m_psnodeChildrenIter != m_psnodeChildrenFirst));
  712. }
  713. CXMLElement *CXMLGenericElement::CreateInstance(LPCWSTR wzName,
  714. VARTYPE vt,
  715. TagInformation **ptiaChildren,
  716. AttributeInformation **paiaAttributes,
  717. LONG)
  718. {
  719. return new CXMLGenericElement(wzName, vt, ptiaChildren, paiaAttributes);
  720. }
  721. LPCWSTR CXMLGenericElement::GetName()
  722. {
  723. return m_bstrName;
  724. }
  725. HRESULT CXMLGenericElement::OnNodeComplete()
  726. {
  727. return S_OK;
  728. }
  729. /////////////////////////////////////////////
  730. // Global Helper functions
  731. /////////////////////////////////////////////
  732. BOOL StrEqlNToSZ(const WCHAR *wzN, int n, const WCHAR *wzSZ)
  733. {
  734. int i;
  735. for (i = 0; i < n; i++)
  736. {
  737. if (wzN[i] != wzSZ[i])
  738. {
  739. return FALSE;
  740. }
  741. }
  742. // make sure the zero terminated string is ending here
  743. return (wzSZ[n] == L'\0');
  744. }
  745. bool StrToIsTrueNW(const WCHAR *wz, ULONG cLen)
  746. {
  747. if (cLen == 4 &&
  748. (StrEqlNToSZ(wz, cLen, L"true") ||
  749. StrEqlNToSZ(wz, cLen, L"TRUE")))
  750. {
  751. return true;
  752. }
  753. else
  754. {
  755. return false;
  756. }
  757. }
  758. #ifndef IS_DIGITW
  759. #ifndef InRange
  760. #define InRange(id, idFirst, idLast) ((UINT)((id)-(idFirst)) <= (UINT)((idLast)-(idFirst)))
  761. #endif
  762. #define IS_DIGITW(ch) InRange(ch, L'0', L'9')
  763. #endif
  764. // convert a wide string to a long, assuming the string has a max of cLen characters.
  765. // L'\0' is recognized to stop earlier, but any other non-digit will cause a return
  766. // of E_INVALIDARG
  767. HRESULT StrToLongNW(const WCHAR *wzString, ULONG cLen, LONG *plong)
  768. {
  769. HRESULT hr = S_OK;
  770. ATLASSERT(plong);
  771. *plong = 0;
  772. UINT i = 0;
  773. BOOL bNeg = FALSE;
  774. if ((i < cLen) && wzString[i] == L'-')
  775. {
  776. bNeg = TRUE;
  777. i++;
  778. }
  779. while ((i < cLen) && IS_DIGITW(wzString[i]))
  780. {
  781. *plong *= 10;
  782. *plong += wzString[i] - L'0';
  783. i++;
  784. }
  785. if ((i < cLen) && (wzString[i] != L'\0'))
  786. {
  787. *plong = 0;
  788. hr = E_INVALIDARG;
  789. }
  790. else
  791. {
  792. if (bNeg)
  793. *plong = -(*plong);
  794. }
  795. return hr;
  796. }