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.

1449 lines
40 KiB

  1. /////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // fusion\xmlparser\xmlparser.cxx
  4. // just commend "SysFreeString" and SysAllocString()
  5. //
  6. /////////////////////////////////////////////////////////////////////////////////
  7. #include "stdinc.h"
  8. #include "core.hxx"
  9. #include "xmlhelper.hxx"
  10. #pragma hdrstop
  11. #include "xmlparser.hxx"
  12. #include "xmlstream.hxx"
  13. #include <objbase.h>
  14. #define CRITICALSECTIONLOCK CSLock lock(&_cs);
  15. const USHORT STACK_INCREMENT=10;
  16. #define PUSHNODEINFO(pNodeInfo)\
  17. if (_cNodeInfoAllocated == _cNodeInfoCurrent)\
  18. {\
  19. checkhr2(GrowNodeInfo());\
  20. }\
  21. _paNodeInfo[_cNodeInfoCurrent++] = _pCurrent;
  22. //////////////////////////////////////////////////////////////////
  23. class CSLock
  24. {
  25. public:
  26. CSLock(CRITICAL_SECTION * pcs);
  27. ~CSLock();
  28. private:
  29. CRITICAL_SECTION * _pcs;
  30. };
  31. CSLock::CSLock(CRITICAL_SECTION * pcs){
  32. _pcs = pcs;
  33. ::EnterCriticalSection(pcs);
  34. }
  35. CSLock::~CSLock(){
  36. ::LeaveCriticalSection(_pcs);
  37. }
  38. /////////////////////////////////////////////////////////////////////////////
  39. XMLParser::XMLParser()
  40. : _pDownloads(1), _pStack(STACK_INCREMENT)
  41. {
  42. ctorInit();
  43. }
  44. /////////////////////////////////////////////////////////////////////////////
  45. void
  46. XMLParser::ctorInit()
  47. {
  48. InitializeCriticalSection(&_cs);
  49. _pTokenizer = NULL;
  50. _pCurrent = NULL;
  51. _lCurrentElement = 0;
  52. _paNodeInfo = NULL;
  53. _cNodeInfoAllocated = _cNodeInfoCurrent = 0;
  54. _pdc = NULL;
  55. _usFlags = 0;
  56. _fCaseInsensitive = false;
  57. _bstrError = NULL;
  58. // _fTokenizerChanged = false;
  59. _fRunEntryCount = 0;
  60. _pszSecureBaseURL = NULL;
  61. _pszCurrentURL = NULL;
  62. _pszBaseURL = NULL;
  63. //_fInLoading = false;
  64. _fInsideRun = false;
  65. //_fFoundDTDAttribute = false;
  66. _cAttributes = 0;
  67. _pRoot = NULL;
  68. //_fAttemptedURL = NULL;
  69. _fLastError = S_OK;
  70. _fStopped = false;
  71. _fSuspended = false;
  72. _fStarted = false;
  73. _fWaiting = false;
  74. _fIgnoreEncodingAttr = false;
  75. _dwSafetyOptions = 0;
  76. // rest of initialization done in the init() method.
  77. //EnableTag(tagParserCallback, TRUE);
  78. //EnableTag(tagParserError, TRUE);
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. XMLParser::~XMLParser()
  82. {
  83. {
  84. CRITICALSECTIONLOCK;
  85. Reset();
  86. // Cleanup tagname buffers in context for good this time...
  87. for (long i = _pStack.size()-1; i>=0; i--)
  88. {
  89. MY_XML_NODE_INFO* pNodeInfo = _pStack[i];
  90. if (pNodeInfo->_pwcTagName != NULL)
  91. {
  92. delete [] pNodeInfo->_pwcTagName;
  93. pNodeInfo->_pwcTagName = NULL;
  94. pNodeInfo->_ulBufLen = 0;
  95. }
  96. // NULL out the node pointer in case it point's to a GC'd object :-)
  97. pNodeInfo->pNode = NULL;
  98. }
  99. delete _pszSecureBaseURL;
  100. delete _pszCurrentURL;
  101. delete[] _paNodeInfo;
  102. }
  103. DeleteCriticalSection(&_cs);
  104. }
  105. /////////////////////////////////////////////////////////////////////////////
  106. HRESULT STDMETHODCALLTYPE
  107. XMLParser::QueryInterface(REFIID riid, void ** ppvObject)
  108. {
  109. //STACK_ENTRY; // xiaoyu : what it for?
  110. // Since this one class implements both IXMLNodeSource and
  111. // IXMLParser, we must override QueryInterface since the
  112. // IUnknown template doesn't know about the IXMLNodeSource
  113. // interface.
  114. HRESULT hr = S_OK;
  115. if (riid == IID_IXMLNodeSource || riid == IID_Parser)
  116. {
  117. *ppvObject = static_cast<IXMLNodeSource*>(this);
  118. AddRef();
  119. }
  120. else
  121. {
  122. hr = _unknown<IXMLParser, &IID_IXMLParser>::QueryInterface(riid, ppvObject);
  123. }
  124. return hr;
  125. }
  126. /////////////////////////////////////////////////////////////////////////////
  127. ULONG STDMETHODCALLTYPE
  128. XMLParser::AddRef(void)
  129. {
  130. //STACK_ENTRY;
  131. return _unknown<IXMLParser, &IID_IXMLParser>::AddRef();
  132. }
  133. /////////////////////////////////////////////////////////////////////////////
  134. ULONG STDMETHODCALLTYPE
  135. XMLParser::Release(void)
  136. {
  137. // STACK_ENTRY;
  138. return _unknown<IXMLParser, &IID_IXMLParser>::Release();
  139. }
  140. /////////////////////////////////////////////////////////////////////////////
  141. HRESULT STDMETHODCALLTYPE
  142. XMLParser::SetInput(IUnknown *pStm)
  143. {
  144. if (pStm == NULL)
  145. return E_INVALIDARG;
  146. //STACK_ENTRY_MODEL(_reThreadModel);
  147. CRITICALSECTIONLOCK;
  148. if (_pDownloads.used() == 0)
  149. init();
  150. HRESULT hr = S_OK;
  151. //checkhr2(PushTokenizer(NULL));
  152. checkhr2(PushTokenizer());
  153. // Get the url path
  154. // Continue even if we cannot get it
  155. // STATSTG stat;
  156. IStream * pStream = NULL;
  157. // memset(&stat, 0, sizeof(stat));
  158. hr = pStm->QueryInterface(IID_IStream, (void**)&pStream);
  159. if (SUCCEEDED(hr))
  160. {
  161. hr = PushStream(pStream, false);
  162. pStream->Release();
  163. }
  164. return hr;
  165. }
  166. /////////////////////////////////////////////////////////////////////////////
  167. HRESULT STDMETHODCALLTYPE
  168. XMLParser::PushData(
  169. /* [in] */ const char __RPC_FAR *pData,
  170. /* [in] */ ULONG ulChars,
  171. /* [in] */ BOOL fLastBuffer)
  172. {
  173. //STACK_ENTRY_MODEL(_reThreadModel);
  174. CRITICALSECTIONLOCK;
  175. HRESULT hr;
  176. if ((NULL == pData) && (ulChars != 0))
  177. {
  178. return E_INVALIDARG;
  179. }
  180. if (_pTokenizer == NULL)
  181. {
  182. init();
  183. //checkhr2(PushTokenizer(NULL));
  184. checkhr2(PushTokenizer());
  185. }
  186. return _pTokenizer->AppendData((const BYTE*)pData, ulChars, fLastBuffer);
  187. }
  188. /////////////////////////////////////////////////////////////////////////////
  189. HRESULT STDMETHODCALLTYPE
  190. XMLParser::SetFactory(IXMLNodeFactory __RPC_FAR *pNodeFactory)
  191. {
  192. //STACK_ENTRY;
  193. CRITICALSECTIONLOCK;
  194. _pFactory = pNodeFactory;
  195. return S_OK;
  196. }
  197. /////////////////////////////////////////////////////////////////////////////
  198. HRESULT STDMETHODCALLTYPE
  199. XMLParser::GetFactory(IXMLNodeFactory** ppNodeFactory)
  200. {
  201. if (ppNodeFactory == NULL) return E_INVALIDARG;
  202. if (_pFactory)
  203. {
  204. *ppNodeFactory = _pFactory;
  205. (*ppNodeFactory)->AddRef();
  206. }
  207. else
  208. {
  209. *ppNodeFactory = NULL;
  210. }
  211. return S_OK;
  212. }
  213. /////////////////////////////////////////////////////////////////////////////
  214. HRESULT STDMETHODCALLTYPE
  215. XMLParser::Run(long lChars)
  216. {
  217. HRESULT hr = NOERROR;
  218. FN_TRACE_HR(hr);
  219. //STACK_ENTRY_MODEL(_reThreadModel);
  220. CRITICALSECTIONLOCK;
  221. XML_NODE_INFO info;
  222. XML_NODE_INFO* aNodeInfo[1];
  223. USHORT numRecs;
  224. bool fIsAttribute = false;
  225. bool stop = false;
  226. if (_fSuspended)
  227. _fSuspended = FALSE; // caller must want to resume.
  228. if (_pFactory == NULL)
  229. {
  230. ::FusionpDbgPrintEx(
  231. FUSION_DBG_LEVEL_ERROR,
  232. "SXS.DLL: XMLParser::Run() failing because _pFactory is NULL\n");
  233. hr = E_FAIL;
  234. goto Exit;
  235. }
  236. if (_fStopped)
  237. {
  238. ::FusionpDbgPrintEx(
  239. FUSION_DBG_LEVEL_ERROR,
  240. "SXS.DLL: XMLParser::Run() failing because _fStopped is set\n");
  241. hr = XML_E_STOPPED;
  242. goto Exit;
  243. }
  244. if (_pTokenizer == NULL)
  245. {
  246. if (_fLastError != S_OK)
  247. {
  248. ::FusionpDbgPrintEx(
  249. FUSION_DBG_LEVEL_ERROR,
  250. "SXS.DLL: XMLParser::Run() failing because _pTokenizer == NULL and _fLastError != S_OK (== 0x%08lx)\n", _fLastError);
  251. hr = _fLastError;
  252. goto Exit;
  253. }
  254. else
  255. {
  256. ::FusionpDbgPrintEx(
  257. FUSION_DBG_LEVEL_ERROR,
  258. "SXS.DLL: XMLParser::Run() failing because _pTokenizer == NULL and _fLastError == S_OK\n");
  259. // must be _fStarted == false
  260. hr = XMLPARSER_IDLE;
  261. goto Exit;
  262. }
  263. }
  264. // Check for recurrsive entry and whether caller actually
  265. // wants anything parsed.
  266. if (_fInsideRun || lChars == 0)
  267. {
  268. ::FusionpDbgPrintEx(
  269. FUSION_DBG_LEVEL_ERROR,
  270. "SXS.DLL: XMLParser::Run() failing because _fInsideRun is set or lChars == 0\n");
  271. hr = E_PENDING;
  272. goto Exit;
  273. }
  274. {
  275. BoolLock flock(&_fInsideRun);
  276. if (_fLastError != 0)
  277. {
  278. // one more chance to cleanup the parser stack.
  279. hr = _fLastError;
  280. goto cleanup_stack;
  281. }
  282. if (! _fStarted)
  283. {
  284. _fStarted = true;
  285. hr = _pFactory->NotifyEvent(this, XMLNF_STARTDOCUMENT);
  286. if (_fStopped){ // watch for onReadyStateChange handlers
  287. hr = S_OK; // fussing with the parser state.
  288. goto Exit;
  289. }
  290. }
  291. _fWaiting = false;
  292. if (_fPendingBeginChildren)
  293. {
  294. _fPendingBeginChildren = false;
  295. hr = _pFactory->BeginChildren(this, (XML_NODE_INFO*)_pCurrent);
  296. }
  297. if (_fPendingEndChildren)
  298. {
  299. _fPendingEndChildren = false;
  300. hr = _pFactory->EndChildren(this, TRUE, (XML_NODE_INFO*)_pCurrent);
  301. if (FAILED(hr))
  302. hr = pop(); // no match needed
  303. }
  304. info.dwSize = sizeof(XML_NODE_INFO);
  305. info.dwType = XMLStream::XML_PENDING;
  306. info.dwSubType = 0;
  307. info.pwcText = NULL;
  308. info.ulLen = 0;
  309. info.ulNsPrefixLen = 0;
  310. info.pNode = NULL;
  311. info.pReserved = NULL;
  312. aNodeInfo[0] = &info;
  313. more:
  314. _fRunEntryCount++; // count of callers inside this loop...
  315. while (hr == 0 && ! _fSuspended)
  316. {
  317. info.dwSubType = 0;
  318. // The XMLStream error codes have been aligned with the
  319. // XMLParser error code so no mapping is necessary.
  320. hr = _pTokenizer->GetNextToken(&info.dwType, (const WCHAR **)&info.pwcText, (long*)&info.ulLen, (long*)&info.ulNsPrefixLen);
  321. if (hr == E_PENDING)
  322. {
  323. _fWaiting = true;
  324. break;
  325. }
  326. if (! _fFoundNonWS &&
  327. info.dwType != XMLStream::XML_PENDING &&
  328. info.dwType != XML_WHITESPACE &&
  329. info.dwType != XML_XMLDECL)
  330. {
  331. _fFoundNonWS = true;
  332. }
  333. // Now the NodeType is the same as the XMLToken value. We set
  334. // this up by aligning the two enums.
  335. switch (info.dwType)
  336. {
  337. case 0:
  338. if (hr == XML_E_INVALIDSWITCH && _fIgnoreEncodingAttr)
  339. {
  340. hr = 0; // ignore it and continue on.
  341. }
  342. break;
  343. // --------- Container Nodes -------------------
  344. case XML_XMLDECL:
  345. //if (_fFoundNonWS && ! _fIE4Mode) // IE4 allowed this...
  346. if (_fFoundNonWS)
  347. {
  348. hr = XML_E_BADXMLDECL;
  349. break;
  350. }
  351. // _fFoundNonWS = true;
  352. goto containers;
  353. case XML_ATTRIBUTE:
  354. fIsAttribute = true;
  355. goto containers;
  356. case XML_VERSION:
  357. info.dwSubType = info.dwType;
  358. info.dwType = XML_ATTRIBUTE;
  359. _fGotVersion = true;
  360. fIsAttribute = true;
  361. goto containers;
  362. case XML_STANDALONE:
  363. case XML_ENCODING:
  364. if (! _fGotVersion && _pDownloads.used() == 1)
  365. {
  366. hr = XML_E_EXPECTING_VERSION;
  367. break;
  368. }
  369. if (info.dwType == XML_STANDALONE)
  370. {
  371. if (_pDownloads.used() > 1)
  372. {
  373. hr = XML_E_UNEXPECTED_STANDALONE;
  374. break;
  375. }
  376. }
  377. info.dwSubType = info.dwType;
  378. info.dwType = XML_ATTRIBUTE;
  379. fIsAttribute = true;
  380. goto containers;
  381. // fall through
  382. case XML_ELEMENT:
  383. containers:
  384. if (_fRootLevel)
  385. {
  386. // Special rules apply for root level tags.
  387. if (info.dwType == XML_ELEMENT)
  388. {
  389. // This is a root level element.
  390. if (! _fFoundRoot)
  391. {
  392. _fFoundRoot = true;
  393. }
  394. else
  395. {
  396. ::FusionpDbgPrintEx(
  397. FUSION_DBG_LEVEL_ERROR,
  398. "SXS.DLL: XML Parser has found multiple roots in the document which is an error.\n");
  399. hr = XML_E_MULTIPLEROOTS;
  400. break;
  401. }
  402. }
  403. else if (info.dwType != XML_PI &&
  404. info.dwType != XML_XMLDECL &&
  405. info.dwType != XML_DOCTYPE)
  406. {
  407. ::FusionpDbgPrintEx(
  408. FUSION_DBG_LEVEL_ERROR,
  409. "SXS.DLL: XML Parser has found an initial element which is not valid at the root level.\n");
  410. hr = XML_E_INVALIDATROOTLEVEL;
  411. break;
  412. }
  413. }
  414. info.fTerminal = FALSE;
  415. if (fIsAttribute)
  416. {
  417. breakhr( pushAttribute(info));
  418. fIsAttribute = false;
  419. }
  420. else
  421. {
  422. breakhr( push(info));
  423. }
  424. break;
  425. case XML_PCDATA:
  426. case XML_CDATA:
  427. terminals:
  428. // Special rules apply for root level tags.
  429. if (_fRootLevel)
  430. {
  431. ::FusionpDbgPrintEx(
  432. FUSION_DBG_LEVEL_ERROR,
  433. "SXS.DLL: XML Parser has found PCDATA at the root level which is not valid XML.\n");
  434. hr = XML_E_INVALIDATROOTLEVEL;
  435. break;
  436. }
  437. // fall through
  438. case XML_COMMENT:
  439. case XML_WHITESPACE:
  440. tcreatenode:
  441. info.fTerminal = TRUE;
  442. if (_cAttributes != 0)
  443. {
  444. // We are inside the attribute list, so we need to push this.
  445. hr = pushAttributeValue(info);
  446. break;
  447. }
  448. hr = _pFactory->CreateNode(this, _pNode, 1, aNodeInfo);
  449. info.pNode = NULL;
  450. break;
  451. case XML_ENTITYREF:
  452. if (_fRootLevel)
  453. {
  454. hr = XML_E_INVALIDATROOTLEVEL;
  455. break;
  456. }
  457. // We handle builtin entities and char entities in xmlstream
  458. // so these must be user defined entity, so treat it like a regular terminal node.
  459. goto terminals;
  460. break;
  461. case XMLStream::XML_BUILTINENTITYREF:
  462. case XMLStream::XML_HEXENTITYREF:
  463. case XMLStream::XML_NUMENTITYREF:
  464. // pass real entityref type as subtype so we can publish these
  465. // subtypes eventually.
  466. info.dwSubType = info.dwType; // XML_ENTITYREF;
  467. info.dwType = XML_PCDATA;
  468. if (_cAttributes == 0)
  469. {
  470. goto tcreatenode;
  471. }
  472. // We are inside the attribute list, so we need to push this.
  473. info.fTerminal = TRUE;
  474. hr = pushAttributeValue(info);
  475. if (SUCCEEDED(hr))
  476. {
  477. hr = CopyText(_pCurrent);
  478. }
  479. break;
  480. case XMLStream::XML_TAGEND: // ">"
  481. numRecs = 1+_cAttributes;
  482. if (_cAttributes != 0) // this is safe because _rawstack does NOT reclaim
  483. { // the popped stack entries.
  484. popAttributes();
  485. }
  486. hr = _pFactory->CreateNode(this, _pNode, numRecs, (XML_NODE_INFO **)&_paNodeInfo[_lCurrentElement]);
  487. _pNode = _pCurrent->pNode;
  488. if (FAILED(hr))
  489. {
  490. _fPendingBeginChildren = true;
  491. break;
  492. }
  493. breakhr( _pFactory->BeginChildren(this, (XML_NODE_INFO*)_pCurrent));
  494. break;
  495. // The ENDXMLDECL is like EMPTYENDTAGs since we've been
  496. // buffering up their attributes, and we have still got to call CreateNode.
  497. case XMLStream::XML_ENDXMLDECL:
  498. _fGotVersion = false; // reset back to initial state.
  499. // fall through.
  500. case XMLStream::XML_EMPTYTAGEND:
  501. numRecs = 1+_cAttributes;
  502. if (_cAttributes != 0)
  503. {
  504. popAttributes();
  505. }
  506. hr = _pFactory->CreateNode(this, _pNode, numRecs, (XML_NODE_INFO **)&_paNodeInfo[_lCurrentElement]);
  507. if (FAILED(hr))
  508. {
  509. _fPendingEndChildren = true;
  510. break;
  511. }
  512. breakhr(_pFactory->EndChildren(this, TRUE, (XML_NODE_INFO*)_pCurrent));
  513. breakhr(pop()); // no match needed
  514. break;
  515. case XMLStream::XML_ENDTAG: // "</"
  516. if (_pStack.used() == 0)
  517. {
  518. ::FusionpDbgPrintEx(
  519. FUSION_DBG_LEVEL_ERROR,
  520. "SXS.DLL: XML Parser has found an unexpected end tag.\n");
  521. hr = XML_E_UNEXPECTEDENDTAG;
  522. }
  523. else
  524. {
  525. XML_NODE_INFO* pCurrent = (XML_NODE_INFO*)_pCurrent; // save current record
  526. breakhr(pop(info.pwcText, info.ulLen)); // check tag/match
  527. breakhr(_pFactory->EndChildren(this, FALSE, (XML_NODE_INFO*)pCurrent));
  528. }
  529. break;
  530. case XMLStream::XML_ENDPROLOG:
  531. // For top level document only, (not for DTD's or
  532. // entities), call EndProlog on the node factory.
  533. if (_fRootLevel && ! _pdc->_fEntity && ! _pdc->_fDTD)
  534. breakhr( _pFactory->NotifyEvent(this, XMLNF_ENDPROLOG));
  535. break;
  536. default:
  537. hr = E_FAIL;
  538. break; // break from switch()
  539. }
  540. }
  541. _fRunEntryCount--;
  542. stop = false;
  543. if (hr == XML_E_ENDOFINPUT)
  544. {
  545. hr = S_OK;
  546. bool inDTD = _pdc->_fDTD;
  547. bool inEntity = _pdc->_fEntity;
  548. bool inPEReference = _pdc->_fPEReference;
  549. if (inEntity && _pdc->_fDepth != _pStack.used())
  550. {
  551. ::FusionpDbgPrintEx(
  552. FUSION_DBG_LEVEL_ERROR,
  553. "SXS.DLL: XML Parser found unclosed tags at the end of the input stream.\n");
  554. // Entity itself was unbalanced.
  555. hr = ReportUnclosedTags(_pdc->_fDepth);
  556. }
  557. else if (PopDownload() == S_OK)
  558. {
  559. // then we must have just finished a DTD and we still have more to do
  560. // BUGBUG -- need to check that entity is well formed, i.e. no tags
  561. // left open.
  562. if (!inPEReference)
  563. {
  564. if (inEntity)
  565. {
  566. hr = _pFactory->NotifyEvent(this, XMLNF_ENDENTITY);
  567. }
  568. else if (inDTD)
  569. {
  570. hr = _pFactory->NotifyEvent(this, XMLNF_ENDDTD);
  571. }
  572. }
  573. if (FAILED(hr))
  574. {
  575. goto cleanup_stack;
  576. }
  577. // In a synchronous DTD download, there is another parser
  578. // parser Run() call on the stack above us, so let's return
  579. // back to that Run method so we don't complete the parsing
  580. // out from under it.
  581. if (_fRunEntryCount > 0){
  582. hr = S_OK;
  583. goto Exit;
  584. }
  585. if (_fStopped){
  586. hr = S_OK;
  587. goto Exit;
  588. }
  589. goto more;
  590. }
  591. else
  592. {
  593. if (_pStack.used() > 0)
  594. {
  595. hr = ReportUnclosedTags(0);
  596. }
  597. else if (! _fFoundRoot)
  598. {
  599. ::FusionpDbgPrintEx(
  600. FUSION_DBG_LEVEL_ERROR,
  601. "SXS.DLL: XML Parser has found no root in the document.\n");
  602. hr = XML_E_MISSINGROOT;
  603. }
  604. stop = true;
  605. }
  606. }
  607. cleanup_stack:
  608. if (hr != S_OK && hr != E_PENDING)
  609. {
  610. stop = true;
  611. _fLastError = hr;
  612. // Pass all the XML_NODE_INFO structs to the Error function so the client
  613. // gets a chance to cleanup the PVOID pNode fields.
  614. HRESULT edr = _pFactory->Error(this, hr,
  615. (USHORT)(_paNodeInfo ? _lCurrentElement+1 : 0), (XML_NODE_INFO**)_paNodeInfo);
  616. if (edr != 0)
  617. _fLastError = hr;
  618. }
  619. if (stop && ! _fStopped)
  620. {
  621. //TraceTag((tagParserError, "Parser stopping with hr %x", hr));
  622. _fLastError = hr;
  623. _fStopped = true;
  624. _fStarted = false;
  625. HRESULT edr;
  626. edr = _pFactory->NotifyEvent(this, XMLNF_ENDDOCUMENT);
  627. if (edr != 0)
  628. {
  629. hr = edr; // allow factory to change error code (except to S_OK)
  630. if (S_OK == _fLastError)
  631. {
  632. // Make sure the node factory always finds out about errors.
  633. edr = _pFactory->Error(this, hr, 0, NULL);
  634. if (edr != 0)
  635. hr = edr;
  636. }
  637. _fLastError = hr;
  638. }
  639. }
  640. }
  641. Exit:
  642. return hr;
  643. }
  644. /////////////////////////////////////////////////////////////////////////////
  645. HRESULT
  646. XMLParser::popAttributes()
  647. {
  648. // Now I pop all the attributes that were pushed for this tag.
  649. // I know we have at least one attribute.
  650. while (_cAttributes > 0)
  651. {
  652. popAttribute(); // no match needed
  653. }
  654. Assert(_pStack.used() == _lCurrentElement+1);
  655. return S_OK;
  656. }
  657. /////////////////////////////////////////////////////////////////////////////
  658. HRESULT STDMETHODCALLTYPE
  659. XMLParser::GetParserState(void)
  660. {
  661. CRITICALSECTIONLOCK;
  662. if (_fLastError != 0)
  663. return static_cast<HRESULT>(XMLPARSER_ERROR);
  664. if (_fStopped)
  665. return static_cast<HRESULT>(XMLPARSER_STOPPED);
  666. if (_fSuspended)
  667. return static_cast<HRESULT>(XMLPARSER_SUSPENDED);
  668. if (! _fStarted)
  669. return static_cast<HRESULT>(XMLPARSER_IDLE);
  670. if (_fWaiting)
  671. return static_cast<HRESULT>(XMLPARSER_WAITING);
  672. return static_cast<HRESULT>(XMLPARSER_BUSY);
  673. }
  674. /////////////////////////////////////////////////////////////////////////////
  675. HRESULT STDMETHODCALLTYPE
  676. XMLParser::Abort(
  677. /* [in] */ BSTR bstrErrorInfo)
  678. {
  679. //STACK_ENTRY_MODEL(_reThreadModel);
  680. // Have to set these before Critical Section to notify Run()
  681. _fStopped = true;
  682. _fSuspended = true; // force Run to terminate...
  683. CRITICALSECTIONLOCK;
  684. //TraceTag((tagParserError, "Parser aborted - %ls", bstrErrorInfo));
  685. //BUGBUG: may need to check bstrErrorInfo is NULL or not
  686. // and the returned result so that we can report
  687. // E_OUTOFMEMORY error
  688. //if (_bstrError) ::SysFreeString(_bstrError);
  689. //_bstrError = ::SysAllocString(bstrErrorInfo);
  690. // abort all downloads
  691. /* for (int i=_pDownloads.used()-1; i>=0; --i)
  692. {
  693. URLStream* stm = _pDownloads[i]->_pURLStream;
  694. if (stm)
  695. stm->Abort();
  696. }
  697. */
  698. return S_OK;
  699. }
  700. /////////////////////////////////////////////////////////////////////////////
  701. HRESULT STDMETHODCALLTYPE
  702. XMLParser::Suspend( void)
  703. {
  704. _fSuspended = true; // force Run to suspend
  705. return S_OK;
  706. }
  707. /////////////////////////////////////////////////////////////////////////////
  708. HRESULT STDMETHODCALLTYPE
  709. XMLParser::Reset( void)
  710. {
  711. // STACK_ENTRY;
  712. CRITICALSECTIONLOCK;
  713. init();
  714. delete _pszCurrentURL;
  715. _pszCurrentURL = NULL;
  716. delete _pszBaseURL;
  717. _pszBaseURL = NULL;
  718. _pRoot = NULL;
  719. _pFactory = NULL;
  720. _pNode = NULL;
  721. //if (_bstrError != NULL) ::SysFreeString(_bstrError);
  722. _bstrError = NULL;
  723. //if (_fAttemptedURL != NULL) ::SysFreeString(_fAttemptedURL);
  724. //_fAttemptedURL = NULL;
  725. return S_OK;
  726. }
  727. /////////////////////////////////////////////////////////////////////////////
  728. ULONG STDMETHODCALLTYPE
  729. XMLParser::GetLineNumber(void)
  730. {
  731. CRITICALSECTIONLOCK;
  732. if (_pTokenizer) return _pTokenizer->GetLine();
  733. else return 0;
  734. }
  735. /////////////////////////////////////////////////////////////////////////////
  736. ULONG STDMETHODCALLTYPE
  737. XMLParser::GetLinePosition( void)
  738. {
  739. CRITICALSECTIONLOCK;
  740. if (_pTokenizer) return _pTokenizer->GetLinePosition();
  741. else return 0;
  742. }
  743. /////////////////////////////////////////////////////////////////////////////
  744. ULONG STDMETHODCALLTYPE
  745. XMLParser::GetAbsolutePosition( void)
  746. {
  747. CRITICALSECTIONLOCK;
  748. if (_pTokenizer) return _pTokenizer->GetInputPosition();
  749. else return 0;
  750. }
  751. /////////////////////////////////////////////////////////////////////////////
  752. HRESULT STDMETHODCALLTYPE
  753. XMLParser::GetLineBuffer(
  754. /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf,
  755. /* [out] */ ULONG __RPC_FAR *pulLen,
  756. /* [out] */ ULONG __RPC_FAR *pulStartPos)
  757. {
  758. if (pulLen == NULL || pulStartPos == NULL) return E_INVALIDARG;
  759. //STACK_ENTRY;
  760. CRITICALSECTIONLOCK;
  761. if (_pTokenizer)
  762. {
  763. return _pTokenizer->GetLineBuffer(ppwcBuf, pulLen, pulStartPos);
  764. }
  765. *ppwcBuf = NULL;
  766. *pulLen = 0;
  767. return S_OK;
  768. }
  769. /////////////////////////////////////////////////////////////////////////////
  770. HRESULT STDMETHODCALLTYPE
  771. XMLParser::GetLastError( void)
  772. {
  773. return _fLastError;
  774. }
  775. //------------ PRIVATE METHODS --------------------------------------------------
  776. HRESULT
  777. //XMLParser::PushTokenizer(
  778. // URLStream* stream)
  779. XMLParser::PushTokenizer()
  780. {
  781. _pTokenizer = NEW (XMLStream(this));
  782. if (_pTokenizer == NULL)
  783. return E_OUTOFMEMORY;
  784. _pTokenizer->SetFlags(_usFlags);
  785. // _fTokenizerChanged = true;
  786. //HRESULT hr= PushDownload(stream, _pTokenizer);
  787. HRESULT hr= PushDownload(_pTokenizer);
  788. if (FAILED(hr))
  789. {
  790. delete _pTokenizer;
  791. _pTokenizer = NULL;
  792. return hr;
  793. }
  794. return S_OK;
  795. }
  796. /////////////////////////////////////////////////////////////////////////////
  797. HRESULT
  798. //XMLParser::PushDownload(URLStream* stream, XMLStream* tokenizer)
  799. XMLParser::PushDownload(XMLStream* tokenizer)
  800. {
  801. // NOTE: tokenizer can be null, in the case of a parameter entity download.
  802. _pdc = _pDownloads.push();
  803. if (_pdc == NULL)
  804. {
  805. return E_OUTOFMEMORY;
  806. }
  807. if (_pDownloads.used() > 1)
  808. _fRootLevel = false;
  809. _pdc->_pTokenizer = tokenizer;
  810. _pdc->_fDTD = false;
  811. _pdc->_fEntity = false;
  812. _pdc->_fAsync = false;
  813. _pdc->_fFoundNonWS = _fFoundNonWS;
  814. _pdc->_fFoundRoot = _fFoundRoot;
  815. _pdc->_fRootLevel = _fRootLevel;
  816. _pdc->_fDepth = _pStack.used();
  817. _fFoundNonWS = false;
  818. _fFoundRoot = false;
  819. _fRootLevel = (_pStack.used() == 0 && _pDownloads.used() == 1);
  820. HRESULT hr = S_OK;
  821. return hr;
  822. }
  823. /////////////////////////////////////////////////////////////////////////////
  824. HRESULT
  825. XMLParser::PushStream(IStream* pStm, bool fpe)
  826. {
  827. EncodingStream* stream = (EncodingStream*)EncodingStream::newEncodingStream(pStm); // refcount = 1
  828. if (stream == NULL)
  829. return E_OUTOFMEMORY;
  830. /*
  831. if (_usFlags & XMLFLAG_RUNBUFFERONLY)
  832. stream->setReadStream(false);
  833. */
  834. _pdc->_pEncodingStream = stream;
  835. stream->Release(); // Smart pointer is holding a ref
  836. HRESULT hr = _pTokenizer->PushStream(stream, fpe);
  837. if (hr == E_PENDING)
  838. {
  839. _fWaiting = true;
  840. }
  841. return hr;
  842. }
  843. /////////////////////////////////////////////////////////////////////////////
  844. HRESULT
  845. XMLParser::PopDownload()
  846. {
  847. // NOTE: tokenizer can be null, in the case of a parameter entity download.
  848. HRESULT hr = S_OK;
  849. if (_pdc != NULL)
  850. {
  851. if (_pdc->_pTokenizer)
  852. {
  853. _pdc->_pTokenizer->Reset();
  854. delete _pdc->_pTokenizer;
  855. _pdc->_pTokenizer = NULL;
  856. }
  857. _pdc->_pEncodingStream = NULL;
  858. /*
  859. if (_pdc->_pURLStream)
  860. _pdc->_pURLStream->Reset();
  861. _pdc->_pURLStream = NULL;
  862. */
  863. // restore saved value of foundnonws.
  864. _fFoundNonWS = _pdc->_fFoundNonWS;
  865. _pdc = _pDownloads.pop();
  866. }
  867. if (_pdc != NULL)
  868. {
  869. if (_pdc->_pTokenizer != NULL)
  870. {
  871. _pTokenizer = _pdc->_pTokenizer;
  872. }
  873. /*
  874. if (_pdc->_pURLStream != NULL)
  875. {
  876. hr = SetCurrentURL(_pdc->_pURLStream->GetURL()->getResolved());
  877. }
  878. */
  879. }
  880. else
  881. {
  882. _pTokenizer = NULL;
  883. hr = S_FALSE;
  884. }
  885. if (_pStack.used() == 0 && _pDownloads.used() == 1)
  886. _fRootLevel = true;
  887. return hr;
  888. }
  889. /////////////////////////////////////////////////////////////////////////////
  890. HRESULT
  891. XMLParser::GrowNodeInfo()
  892. {
  893. USHORT newsize = _cNodeInfoAllocated + STACK_INCREMENT;
  894. MY_XML_NODE_INFO** pNewArray = NEW (PMY_XML_NODE_INFO[newsize]);
  895. if (pNewArray == NULL)
  896. return E_OUTOFMEMORY;
  897. // Now since STACK_INCREMENT is the same for _pStack then _pStack
  898. // has also re-allocated. Therefore we need to re-initialize all
  899. // the pointers in this array - since they point into the _pStack's memory.
  900. for (int i = _pStack.used() - 1; i >= 0; i--)
  901. {
  902. pNewArray[i] = _pStack[i];
  903. }
  904. delete[] _paNodeInfo;
  905. _paNodeInfo = pNewArray;
  906. _cNodeInfoAllocated = newsize;
  907. return S_OK;
  908. }
  909. /////////////////////////////////////////////////////////////////////////////
  910. HRESULT
  911. XMLParser::GrowBuffer(PMY_XML_NODE_INFO pNodeInfo, long newlen)
  912. {
  913. delete [] pNodeInfo->_pwcTagName;
  914. pNodeInfo->_pwcTagName = NULL;
  915. // add 50 characters to avoid too many reallocations.
  916. pNodeInfo->_pwcTagName = NEW (WCHAR[ newlen ]);
  917. if (pNodeInfo->_pwcTagName == NULL)
  918. return E_OUTOFMEMORY;
  919. pNodeInfo->_ulBufLen = newlen;
  920. return S_OK;
  921. }
  922. /////////////////////////////////////////////////////////////////////////////
  923. HRESULT
  924. XMLParser::push(XML_NODE_INFO& info)
  925. {
  926. HRESULT hr;
  927. _lCurrentElement = _pStack.used();
  928. _pCurrent = _pStack.push();
  929. if (_pCurrent == NULL)
  930. return E_OUTOFMEMORY;
  931. *((XML_NODE_INFO*)_pCurrent) = info;
  932. PUSHNODEINFO(_pCurrent);
  933. _fRootLevel = false;
  934. // Save the tag name into the private buffer so it sticks around until the
  935. // close tag </foo> which could be anywhere down the road after the
  936. // BufferedStream been overwritten
  937. // THIS CODE IS OPTIMIZED FOR PERFORMANCE WHICH IS WHY IT IS NOT
  938. // CALLING THE CopyText METHOD.
  939. if (_pCurrent->_ulBufLen < info.ulLen+1)
  940. {
  941. checkhr2(GrowBuffer(_pCurrent, info.ulLen + 50));
  942. }
  943. Assert(info.ulLen >= 0);
  944. ::memcpy(_pCurrent->_pwcTagName, info.pwcText, info.ulLen*sizeof(WCHAR));
  945. _pCurrent->_pwcTagName[info.ulLen] = L'\0';
  946. // And make the XML_NODE_INFO point to private buffer.
  947. _pCurrent->pwcText = _pCurrent->_pwcTagName;
  948. return S_OK;
  949. }
  950. /////////////////////////////////////////////////////////////////////////////
  951. HRESULT
  952. XMLParser::pushAttribute(XML_NODE_INFO& info)
  953. {
  954. HRESULT hr;
  955. if (_cAttributes != 0)
  956. {
  957. // Attributes are special in that they are supposed to be unique.
  958. // So here we actually check this.
  959. for (long i = _pStack.used()-1; i > _lCurrentElement; i--)
  960. {
  961. XML_NODE_INFO* ptr = _pStack[i];
  962. if (ptr->dwType != XML_ATTRIBUTE)
  963. continue; // ignore attribute values.
  964. if (ptr->ulLen != info.ulLen)
  965. {
  966. continue; // we're ok with this one
  967. }
  968. // Optimized for the normal case where there is no match
  969. if (::memcmp(ptr->pwcText, info.pwcText, info.ulLen*sizeof(WCHAR)) == 0)
  970. {
  971. if (! _fCaseInsensitive)
  972. {
  973. ::FusionpDbgPrintEx(
  974. FUSION_DBG_LEVEL_ERROR,
  975. "SXS.DLL: XML Parser found a duplicate attribute\n");
  976. return XML_E_DUPLICATEATTRIBUTE;
  977. }
  978. //else if (StrCmpNI(ptr->pwcText, info.pwcText, info.ulLen) == 0)
  979. else if (::FusionpCompareStrings(ptr->pwcText, ::wcslen(ptr->pwcText), info.pwcText, info.ulLen, true) == 0)
  980. {
  981. ::FusionpDbgPrintEx(
  982. FUSION_DBG_LEVEL_ERROR,
  983. "SXS.DLL: XML Parser found a duplicate attribute (#2)\n");
  984. // Duplicate attributes are allowed in IE4 mode!!
  985. // But only the latest one shows up
  986. // So we have to delete the previous duplication
  987. return XML_E_DUPLICATEATTRIBUTE;
  988. }
  989. }
  990. }
  991. }
  992. _cAttributes++;
  993. _pCurrent = _pStack.push();
  994. if (_pCurrent == NULL)
  995. return E_OUTOFMEMORY;
  996. *((XML_NODE_INFO*)_pCurrent) = info;
  997. PUSHNODEINFO(_pCurrent);
  998. return S_OK;
  999. }
  1000. /////////////////////////////////////////////////////////////////////////////
  1001. HRESULT
  1002. XMLParser::pushAttributeValue(XML_NODE_INFO& info)
  1003. {
  1004. HRESULT hr;
  1005. // Attributes are saved in the BufferedStream so we can point to the
  1006. // real text in the buffered stream instead of copying it !!
  1007. _pCurrent = _pStack.push();
  1008. if (_pCurrent == NULL)
  1009. return E_OUTOFMEMORY;
  1010. // store attribute value quote character in the pReserved field.
  1011. info.pReserved = (PVOID)_pTokenizer->getAttrValueQuoteChar();
  1012. *((XML_NODE_INFO*)_pCurrent) = info;
  1013. PUSHNODEINFO(_pCurrent);
  1014. // this is really the count of nodes on the stack, not just attributes.
  1015. _cAttributes++;
  1016. return S_OK;
  1017. }
  1018. /////////////////////////////////////////////////////////////////////////////
  1019. HRESULT
  1020. XMLParser::pop(const WCHAR* tag, ULONG len)
  1021. {
  1022. HRESULT hr = S_OK;
  1023. if (_pCurrent == NULL || _pStack.used() == 0)
  1024. {
  1025. ::FusionpDbgPrintEx(
  1026. FUSION_DBG_LEVEL_ERROR,
  1027. "SXS.DLL: XML Parser found an unexpected end tag.\n");
  1028. hr = XML_E_UNEXPECTEDENDTAG;
  1029. goto Cleanup;
  1030. }
  1031. if (len != 0)
  1032. {
  1033. if (_pCurrent->ulLen != len)
  1034. {
  1035. ::FusionpDbgPrintEx(
  1036. FUSION_DBG_LEVEL_ERROR,
  1037. "SXS.DLL: XML Parser found an end tag mismatch\n");
  1038. hr = XML_E_ENDTAGMISMATCH;
  1039. }
  1040. // Optimized for the normal case where there is no match
  1041. else if (::memcmp(_pCurrent->pwcText, tag, len*sizeof(WCHAR)) != 0)
  1042. {
  1043. if (! _fCaseInsensitive)
  1044. {
  1045. ::FusionpDbgPrintEx(
  1046. FUSION_DBG_LEVEL_ERROR,
  1047. "SXS.DLL: XML Parser found an end tag mismatch.\n");
  1048. hr = XML_E_ENDTAGMISMATCH;
  1049. }
  1050. //else if ( XML_StrCmpNI(_pCurrent->pwcText, tag, len) != 0 )
  1051. else if (::FusionpCompareStrings(_pCurrent->pwcText, len, tag, len, true) != 0)
  1052. {
  1053. hr = XML_E_ENDTAGMISMATCH;
  1054. }
  1055. }
  1056. if (FAILED(hr))
  1057. {
  1058. /*
  1059. TRY
  1060. {
  1061. String* s = Resources::FormatMessage(hr, String::newString(_pCurrent->pwcText, 0, _pCurrent->ulLen),
  1062. String::newString(tag, 0, len), NULL);
  1063. _bstrError = s->getBSTR();
  1064. }
  1065. CATCH
  1066. {
  1067. hr = ERESULT;
  1068. }
  1069. ENDTRY
  1070. */
  1071. goto Cleanup;
  1072. }
  1073. }
  1074. // We don't delete the fTagName because we're going to reuse this field
  1075. // later to avoid lots of memory allocations.
  1076. _pCurrent = _pStack.pop();
  1077. _cNodeInfoCurrent--;
  1078. if (_pCurrent == 0)
  1079. {
  1080. _pNode = _pRoot;
  1081. if (_pDownloads.used() == 1)
  1082. _fRootLevel = true;
  1083. }
  1084. else
  1085. {
  1086. _pNode = _pCurrent->pNode;
  1087. }
  1088. Cleanup:
  1089. return hr;
  1090. }
  1091. /////////////////////////////////////////////////////////////////////////////
  1092. HRESULT XMLParser::pop()
  1093. {
  1094. // We don't delete the fTagName because we're going to reuse this field
  1095. // later to avoid lots of memory allocations.
  1096. _pCurrent = _pStack.pop();
  1097. _cNodeInfoCurrent--;
  1098. if (_pCurrent == 0)
  1099. {
  1100. _pNode = _pRoot;
  1101. if (_pDownloads.used() == 1)
  1102. _fRootLevel = true;
  1103. }
  1104. else
  1105. {
  1106. _pNode = _pCurrent->pNode;
  1107. }
  1108. return S_OK;
  1109. }
  1110. /////////////////////////////////////////////////////////////////////////////
  1111. void XMLParser::popAttribute()
  1112. {
  1113. Assert(_pStack.used() > 0);
  1114. _pCurrent = _pStack.pop();
  1115. _cNodeInfoCurrent--;
  1116. Assert(_pCurrent != 0);
  1117. _cAttributes--;
  1118. }
  1119. /////////////////////////////////////////////////////////////////////////////
  1120. HRESULT
  1121. XMLParser::CopyText(PMY_XML_NODE_INFO pNodeInfo)
  1122. {
  1123. HRESULT hr = S_OK;
  1124. if (pNodeInfo->_pwcTagName != pNodeInfo->pwcText)
  1125. {
  1126. ULONG len = pNodeInfo->ulLen;
  1127. // Copy the current text into the buffer.
  1128. if (pNodeInfo->_ulBufLen < len+1)
  1129. {
  1130. checkhr2(GrowBuffer(pNodeInfo, len + 50));
  1131. }
  1132. if (len > 0)
  1133. {
  1134. ::memcpy(pNodeInfo->_pwcTagName, pNodeInfo->pwcText, len*sizeof(WCHAR));
  1135. }
  1136. pNodeInfo->_pwcTagName[len] = L'\0';
  1137. // And make the XML_NODE_INFO point to private buffer.
  1138. pNodeInfo->pwcText = pNodeInfo->_pwcTagName;
  1139. }
  1140. return S_OK;
  1141. }
  1142. /////////////////////////////////////////////////////////////////////////////
  1143. HRESULT
  1144. XMLParser::CopyContext()
  1145. {
  1146. // For performance reasons we try not to copy the data for attributes
  1147. // and their values when we push them on the stack. We can do this
  1148. // because the tokenizer tries to freeze the internal buffers while
  1149. // parsing attributes and thereby guarentee that the pointers stay
  1150. // good. But occasionally the BufferedStream has to reallocate when
  1151. // the attributes are right at the end of the buffer.
  1152. long last = _pStack.used();
  1153. for (long i = _cAttributes; i > 0 ; i--)
  1154. {
  1155. long index = last - i;
  1156. MY_XML_NODE_INFO* ptr = _pStack[index];
  1157. CopyText(ptr);
  1158. }
  1159. return S_OK;
  1160. }
  1161. /////////////////////////////////////////////////////////////////////////////
  1162. HRESULT XMLParser::ReportUnclosedTags(int start)
  1163. {
  1164. HRESULT hr = XML_E_UNCLOSEDTAG;
  1165. // Build a string containing the list of unclosed tags and format an error
  1166. // message containing this text.
  1167. int tags = _pStack.used();
  1168. WCHAR* buffer = NULL;
  1169. WCHAR* msgbuf = NULL;
  1170. unsigned long size = 0;
  1171. unsigned long used = 0;
  1172. for (long i = start; i < tags; i++)
  1173. {
  1174. XML_NODE_INFO* ptr = _pStack[i];
  1175. if (ptr->dwType == XML_ATTRIBUTE)
  1176. break;
  1177. if (used + ptr->ulLen + 3 > size) // +3 for '<','>' and '\0'
  1178. {
  1179. long newsize = used + ptr->ulLen + 500;
  1180. WCHAR* newbuf = NEW (WCHAR[newsize]);
  1181. if (newbuf == NULL)
  1182. {
  1183. goto nomem;
  1184. }
  1185. if (buffer != NULL)
  1186. {
  1187. ::memcpy(newbuf, buffer, used);
  1188. delete[] buffer;
  1189. }
  1190. size = newsize;
  1191. buffer = newbuf;
  1192. }
  1193. if (i > start)
  1194. {
  1195. buffer[used++] = ',';
  1196. buffer[used++] = ' ';
  1197. }
  1198. ::memcpy(&buffer[used], ptr->pwcText, sizeof(WCHAR) * ptr->ulLen);
  1199. used += ptr->ulLen;
  1200. buffer[used] = '\0';
  1201. }
  1202. goto cleanup;
  1203. //xiaoyu : SysAllocString and SysFreeString are commended off.
  1204. // msgbuf = ::FormatMessageInternal(g_hInstance, XML_E_UNCLOSEDTAG, buffer, NULL);
  1205. /*
  1206. TRY
  1207. {
  1208. String* s = Resources::FormatMessage(XML_E_UNCLOSEDTAG,
  1209. String::newString(buffer), NULL);
  1210. _bstrError = s->getBSTR();
  1211. goto cleanup;
  1212. }
  1213. CATCH
  1214. {
  1215. hr = ERESULT;
  1216. goto done;
  1217. }
  1218. ENDTRY
  1219. if (msgbuf == NULL)
  1220. goto nomem;
  1221. if (_bstrError) ::SysFreeString(_bstrError);
  1222. _bstrError = ::SysAllocString(msgbuf);
  1223. if (_bstrError == NULL)
  1224. goto nomem;
  1225. goto cleanup;
  1226. */
  1227. nomem:
  1228. hr = E_OUTOFMEMORY;
  1229. cleanup:
  1230. delete [] buffer;
  1231. delete [] msgbuf;
  1232. return hr;
  1233. }
  1234. /////////////////////////////////////////////////////////////////////////////
  1235. HRESULT XMLParser::init()
  1236. {
  1237. CRITICALSECTIONLOCK;
  1238. _fLastError = 0;
  1239. _fStopped = false;
  1240. _fSuspended = false;
  1241. _pNode = _pRoot;
  1242. _fStarted = false;
  1243. _fStopped = false;
  1244. _fWaiting = false;
  1245. _fFoundRoot = false;
  1246. _fFoundNonWS = false;
  1247. _pTokenizer = NULL;
  1248. _fGotVersion = false;
  1249. _fRootLevel = true;
  1250. _cAttributes = 0;
  1251. _fPendingBeginChildren = false;
  1252. _fPendingEndChildren = false;
  1253. while (_pCurrent != NULL)
  1254. {
  1255. _pCurrent = _pStack.pop();
  1256. }
  1257. _cNodeInfoCurrent = 0;
  1258. _lCurrentElement = 0;
  1259. // cleanup downloads
  1260. while (_pdc != NULL)
  1261. {
  1262. PopDownload();
  1263. }
  1264. _pCurrent = NULL;
  1265. return S_OK;
  1266. }
  1267. /////////////////////////////////////////////////////////////////////////////
  1268. HRESULT
  1269. XMLParser::ErrorCallback(HRESULT hr)
  1270. {
  1271. Assert(hr == XMLStream::XML_DATAAVAILABLE ||
  1272. hr == XMLStream::XML_DATAREALLOCATE);
  1273. if (hr == XMLStream::XML_DATAREALLOCATE)
  1274. {
  1275. // This is more serious. We have to actually save away the
  1276. // context because the buffers are about to be reallocated.
  1277. checkhr2(CopyContext());
  1278. }
  1279. checkhr2(_pFactory->NotifyEvent(this, XMLNF_DATAAVAILABLE));
  1280. return hr;
  1281. }