looseprs.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 39k
Category:

Symbian

Development Platform:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxcom.h"
  36. #include "hxtypes.h"
  37. #include "hxstrutl.h"
  38. #include "hxmap.h"
  39. #include "xmlencod.h"
  40. #include "looseprs.h"
  41. #include <ctype.h>
  42. #include "hxheap.h"
  43. #ifdef _DEBUG
  44. #undef HX_THIS_FILE
  45. static const char HX_THIS_FILE[] = __FILE__;
  46. #endif
  47. static const int MAX_ERROR_LEN = 80;
  48. XMLParser::XMLParser(BOOL bStrictCompliance, const char* pEncoding,
  49.      BOOL bAllowNonXMLComments):
  50.     m_bStrictCompliance(bStrictCompliance),
  51.     m_bAllowNonXMLComments(bAllowNonXMLComments),
  52.     m_bCommentWasFound(FALSE),
  53.     m_bXMLandSMIL10FullCompliance(FALSE),
  54.     m_ulCurrentLine(1),
  55.     m_ulCurrentCol(1),
  56.     m_ulTagStartLine(1),
  57.     m_ulTagStartCol(1),
  58.     m_pLastError(0)
  59.     , m_bStoreErrors(FALSE)
  60. {
  61.     m_pCurrentFrame = new XMLFrame;
  62.     m_comment_state = 0;
  63.     m_comment_get_arg = 0;
  64.     m_comment_pos = 0;
  65.     if(pEncoding)
  66.     {
  67. m_pEncoding = new_string(pEncoding);
  68.     }
  69.     else
  70.     {
  71. m_pEncoding = new_string("US-ASCII"); // default encoding
  72.     }
  73. }
  74. XMLParser::~XMLParser()
  75. {
  76.     HX_DELETE(m_pLastError);
  77.     HX_VECTOR_DELETE(m_pEncoding);
  78.     delete m_pCurrentFrame;
  79. }
  80. void
  81. XMLParser::Reset(void)
  82. {
  83.     if (m_pCurrentFrame != NULL) delete m_pCurrentFrame;
  84.     m_pCurrentFrame = NULL;
  85. }
  86. // class function to get version/encoding of XML content
  87. HX_RESULT
  88. XMLParser::GetPrologInfo(const char* pBuf,
  89.  UINT32 ulBufLen,
  90.  char*& pVersion,
  91.  char*& pEncoding)
  92. {
  93.     HX_RESULT rc = HXR_FAIL;
  94.     const char* pCh = pBuf;
  95.     enum { VERSION, ENCODING } nPrologAttribute = VERSION;
  96.     char quoteType = '"';
  97.     BOOL bDone = FALSE;
  98.     BOOL bInComment = FALSE;
  99.     int state = 0;
  100.     const char* pValueStart = NULL;
  101.     while(!bDone &&
  102.         pCh < pBuf + ulBufLen)
  103.     {
  104.         switch(state)
  105.         {
  106.             case 0: // looking for either a comment open
  107.                     // or a prolog
  108.             {
  109.                 if(*pCh == '<')
  110.                 {
  111.                     if(*(pCh + 1) == '!' &&
  112.                        *(pCh + 2) == '-' &&
  113.                        *(pCh + 3) == '-')
  114.                     {
  115.                         if(bInComment)
  116.                         {
  117.                             bDone = TRUE;   // no nested comments
  118.                         }
  119.                         pCh += 4;   // skip over
  120.                         bInComment = TRUE;
  121.                         state = 1;
  122.                     }
  123.                     else if(*(pCh + 1) == '?' &&
  124.                             *(pCh + 2) == 'x' &&
  125.                             *(pCh + 3) == 'm' &&
  126.                             *(pCh + 4) == 'l')
  127.                     {
  128.                         pCh += 5;   // skip over 
  129.                         state = 2;
  130.                     }
  131.                     else
  132.                     {
  133.                         bDone = TRUE;   // no prolog
  134.                     }
  135.                 }
  136.                 else if(isspace(*pCh))
  137.                 {
  138.                     pCh++;
  139.                 }
  140.                 else
  141.                 {
  142.                     bDone = TRUE;   // can't find prolog
  143.                 }
  144.             }
  145.             break;
  146.             case 1: // comment end
  147.             {
  148.                 if(*pCh == '-' &&
  149.                    *(pCh + 1) == '-' &&
  150.                    *(pCh + 2) == '>')
  151.                 {
  152.                     pCh += 3;
  153.                     bInComment = FALSE;
  154.                     state = 0;
  155.                 }
  156.                 else
  157.                 {
  158.                     pCh++;
  159.                 }
  160.             }
  161.             break;
  162.             case 2: // known attribute in prolog
  163.             {
  164.                 if(strncmp(pCh, "version", 7) == 0)
  165.                 {
  166.                     pCh += 7;
  167.                     nPrologAttribute = VERSION;
  168.                     state = 3;
  169.                 }
  170.                 else if(strncmp(pCh, "encoding", 8) == 0)
  171.                 {
  172.                     pCh += 8;
  173.                     nPrologAttribute = ENCODING;
  174.                     state = 3;
  175.                 }
  176.                 else
  177.                 {
  178.                     pCh++;
  179.                 }
  180.             }
  181.             break;
  182.             case 3: // '='
  183.             {
  184.                 if(*pCh == '=')
  185.                 {
  186.                     state = 4;
  187.                 }
  188.                 pCh++;
  189.             }
  190.             break;
  191.             case 4: // quote type
  192.             {
  193.                 if(*pCh == '"')
  194.                 {
  195.                     quoteType = '"';
  196.                     pValueStart = pCh + 1;
  197.                     state = 5;
  198.                 }
  199.                 else if(*pCh == ''')
  200.                 {
  201.                     quoteType = ''';
  202.                     pValueStart = pCh + 1;
  203.                     state = 5;
  204.                 }
  205.                 else
  206.                 {
  207.                     bDone = TRUE;   // badly formed
  208.                 }
  209.                 pCh++;
  210.             }
  211.             break;
  212.             case 5: // get value
  213.             {
  214.                 if(*pCh == quoteType)
  215.                 {
  216.                     if (pValueStart)
  217.                     {
  218.                         INT32 lValLen = pCh - pValueStart;
  219.                         if (lValLen > 0)
  220.                         {
  221.                             char* pTmp = new char [lValLen + 1];
  222.                             if (pTmp)
  223.                             {
  224.                                 strncpy(pTmp, pValueStart, lValLen);
  225.                                 pTmp[lValLen] = '';
  226.                                 if(nPrologAttribute == VERSION)
  227.                                 {
  228.                                     pVersion = pTmp;
  229.                                 }
  230.                                 else if(nPrologAttribute == ENCODING)
  231.                                 {
  232.                                     pEncoding = pTmp;
  233.                                 }
  234.                                 rc = HXR_OK;    // got one!
  235.                                 // reset for next string
  236.                                 state = 2;
  237.                             }
  238.                         }
  239.                     }
  240.                 }
  241.                 pCh++;
  242.             }
  243.             break;
  244.         }
  245.     }
  246.     return rc;
  247. }
  248. char
  249. XMLParser::GetEscapeMacro(const char*& ptr, const char* end)
  250. {
  251.     char returnCh;
  252.     if(*ptr != '&')
  253.     {
  254. returnCh = *ptr;
  255.     }
  256.     else
  257.     {
  258. int maxLen = end - ptr;
  259. if((maxLen > 5) && strncmp(ptr, "&apos;", 6) == 0)
  260. {
  261.     returnCh = ''';
  262.     ptr += 6;
  263. }
  264. else if((maxLen > 5) && strncmp(ptr, "&quot;", 6) == 0)
  265. {
  266.     returnCh = '"';
  267.     ptr += 6;
  268. }
  269. else if((maxLen > 3) && strncmp(ptr, "&lt;", 4) == 0)
  270. {
  271.     returnCh = '<';
  272.     ptr += 4;
  273. }
  274. else if((maxLen > 3) && strncmp(ptr, "&gt;", 4) == 0)
  275. {
  276.     returnCh = '>';
  277.     ptr += 4;
  278. }
  279. else if((maxLen > 4) && strncmp(ptr, "&amp;", 5) == 0)
  280. {
  281.     returnCh = '&';
  282.     ptr += 5;
  283. }
  284. else
  285. {
  286.     returnCh = '&';
  287.     ptr++;
  288. }
  289.     }
  290.     return returnCh;
  291. }
  292. GetStringResult
  293. XMLParser::GetString(const char*& ptr, const char* end, 
  294.       char*& val, UINT32 type)
  295. {
  296.     GetStringResult retval = GSInvalid;
  297.     CHXXMLEncode xmlStr(m_pEncoding, (BYTE*)ptr, end - ptr);
  298.     UINT16 uLen = 0;
  299.     ptr = (const char*)xmlStr.GetNextChar(uLen);
  300.     while(isspace(*ptr) && ptr < end)
  301.     {
  302. ptr = (const char*)xmlStr.GetNextChar(uLen);
  303.     }
  304.     if((const char*)ptr >= end)
  305.     {
  306. return GSNoValue;
  307.     }
  308.     if(*ptr == '>')
  309.     {
  310. ptr = (const char*)xmlStr.GetNextChar(uLen);
  311. return GSNoValue;
  312.     }
  313.     if(*ptr == '/' && *(ptr + 1) == '>')
  314.     {
  315. xmlStr += 2;
  316. ptr = (const char*)xmlStr++;
  317. return GSNoValue;
  318.     }
  319.     // temp buffer to copy string value
  320.     char* pVal = new char[end - ptr + 1];
  321.     char* pValPtr = pVal;
  322.     char* pValStartPtr = pVal;
  323.     switch(type)
  324.     {
  325. case TagType:
  326. {
  327.     // The main tag name, delimited by space
  328.     if(*ptr == '/')
  329.     {
  330. retval = GSEndTag;
  331. pValStartPtr++;
  332.     }
  333.     while(!isspace(*ptr) && *ptr != '>' && ptr < end)
  334.     {
  335. *pValPtr++ = *ptr;
  336. if(uLen == 2)
  337. {
  338.     *pValPtr++ = *(ptr + 1);
  339. }
  340. ptr = (const char*)xmlStr.GetNextChar(uLen);
  341.     }
  342.     break;
  343. }
  344. case AttributeName:
  345. {
  346.     // Delimited by whitespace or =
  347.     while(!isspace(*ptr) && *ptr != '=' && *ptr != '>' && ptr < end)
  348.     {
  349. *pValPtr++ = *ptr;
  350. if(uLen == 2)
  351. {
  352.     *pValPtr++ = *(ptr + 1);
  353. }
  354. ptr = (const char*)xmlStr.GetNextChar(uLen);
  355.     }
  356.     BOOL foundequals = FALSE;
  357.     if(ptr < end)
  358.     {
  359. // Set the ptr to past the =
  360. while((isspace(*ptr) || *ptr == '=') && ptr < end)
  361. {
  362.     if(*ptr == '=')
  363. foundequals=TRUE;
  364.     ptr = (const char*)xmlStr.GetNextChar(uLen);
  365. }
  366.     }
  367.     if(!foundequals)
  368.     {
  369. retval = GSValueOnly;
  370.     }
  371.     break;
  372. }
  373. case AttributeValue:
  374. case AttributeValueNoQuote:
  375. case AttributeValueDirective:
  376. {
  377.     if(*ptr == '"')
  378.     {
  379. ptr = (const char*)xmlStr.GetNextChar(uLen);
  380. while(ptr<end && *ptr != '"')
  381. {
  382.     if(*ptr == '&')
  383.     {
  384. *pValPtr = GetEscapeMacro(ptr, end);
  385. pValPtr++;
  386. xmlStr.SetCurrent((BYTE*)ptr);
  387.     }
  388.     else
  389.     {
  390. *pValPtr++ = *ptr;
  391. if(uLen == 2)
  392. {
  393.     *pValPtr++ = *(ptr + 1);
  394. }
  395.     }
  396.     ptr = (const char*)xmlStr.GetNextChar(uLen);
  397. }
  398. if(*ptr != '"')
  399. {
  400.     return GSMissingQuote;
  401. }
  402. /* Skip the quote */
  403. ptr = (const char*)xmlStr.GetNextChar(uLen);
  404. //Fixes 28799 (which is really an XML authoring error)
  405. // if m_bXMLandSMIL10FullCompliance is FALSE:
  406. if (m_bXMLandSMIL10FullCompliance  &&
  407. !isspace(*ptr)  &&  '>' != *ptr  &&
  408. (('/' != *ptr  &&  '?' != *ptr)
  409. ||  '>' != *(ptr+1)) )
  410. {
  411.     //[SMIL 1.0 Compliance] Fixes PR 23995.  Junk following a
  412.     // name="value" construct should be treated as an error,
  413.     // e.g., the comma should be treated as an error in the
  414.     // following: <region height="10", width="20"/>
  415.     return GSInvalid;
  416. }
  417.     }
  418.     else if(*ptr == ''')
  419.     {
  420. ptr = (const char*)xmlStr.GetNextChar(uLen);
  421. while(*ptr != ''' && ptr < end)
  422. {
  423.     if(*ptr == '&')
  424.     {
  425. *pValPtr = GetEscapeMacro(ptr, end);
  426. pValPtr++;
  427. xmlStr.SetCurrent((BYTE*)ptr);
  428.     }
  429.     else
  430.     {
  431. *pValPtr++ = *ptr;
  432. if(uLen == 2)
  433. {
  434.     *pValPtr++ = *(ptr + 1);
  435. }
  436.     }
  437.     ptr = (const char*)xmlStr.GetNextChar(uLen);
  438. }
  439. if(*ptr != ''')
  440. {
  441.     delete [] pVal;
  442.     return GSMissingQuote;
  443. }
  444. /* Skip the quote */
  445. ptr = (const char*)xmlStr.GetNextChar(uLen);
  446.     }
  447.     else if(*ptr == '[' && type == AttributeValueDirective)
  448.     {
  449. ptr = (const char*)xmlStr.GetNextChar(uLen);
  450. while(*ptr != ']' && ptr < end)
  451. {
  452.     *pValPtr++ = *ptr;
  453.     if(uLen == 2)
  454.     {
  455. *pValPtr++ = *(ptr + 1);
  456.     }
  457.     ptr = (const char*)xmlStr.GetNextChar(uLen);
  458. }
  459. if(*ptr != ']')
  460. {
  461.     delete[] pVal;
  462.     return GSMissingQuote;
  463. }
  464. /* skip the ']' */
  465. ptr = (const char*)xmlStr.GetNextChar(uLen);
  466.     }
  467.     else
  468.     {
  469. if(m_bStrictCompliance && 
  470.    type != AttributeValueNoQuote &&
  471.    type != AttributeValueDirective)
  472. {
  473.     /* error - value must be quoted */
  474.     delete [] pVal;
  475.     return GSMissingQuote;
  476. }
  477. else
  478. {
  479.     /* don't care!!! */
  480.     while(!isspace(*ptr) && *ptr != '>' && ptr < end)
  481.     {
  482. *pValPtr++ = *ptr;
  483. if(uLen == 2)
  484. {
  485.     *pValPtr++ = *(ptr + 1);
  486. }
  487. ptr = (const char*)xmlStr.GetNextChar(uLen);
  488.     }
  489. }
  490.     }
  491.     break;
  492. }
  493.     }
  494.     *pValPtr = '';
  495.     val = new_string(pValStartPtr);
  496.     delete [] pVal;
  497.     if(retval == GSInvalid)
  498. return GSFoundExpected;
  499.     else
  500. return retval;
  501. }
  502. void
  503. XMLParser::FindCommentClose(const char*& buf, const char* start,
  504.     const char* end)
  505. {
  506.     BOOL   bResult  = FALSE;
  507.     UINT16 nCommentDepth = 1;
  508.     CHXXMLEncode xmlStr(m_pEncoding, (BYTE*)start, end - start);
  509.     UINT16 uLen = 0;
  510.     const char* pos = (const char*)xmlStr.GetNextChar(uLen);
  511.     while(pos < end && m_comment_state > 0)
  512.     {
  513. switch(m_comment_state)
  514. {
  515.     case 1:
  516. if(*pos == '-')
  517.     m_comment_state = 2;
  518. else if (*pos == '<')
  519.     m_comment_state = 4;
  520. else if (*pos == '>' && m_bAllowNonXMLComments)
  521. {
  522.     nCommentDepth--;
  523.     if (nCommentDepth == 0)
  524.     {
  525. m_comment_state = 0;
  526. buf = (const char*)xmlStr.GetNextChar(uLen);
  527.     }
  528.     else
  529. m_comment_state = 1;
  530. }
  531. else if(m_comment_start)
  532. {
  533.     if(*pos == '#')
  534.     {
  535. if(end - pos < 8)
  536. {
  537.     buf = pos;
  538.     return;
  539. }
  540. pos = (const char*)xmlStr.GetNextChar(uLen);
  541. if(strncasecmp(pos, "include", 7) == 0)
  542. {
  543.     pos += 7;
  544.     m_comment_get_arg = 1;
  545.     m_comment_pos = 0;
  546.     strcpy(m_comment_command, "include");
  547. }
  548.     }
  549. }
  550. break;
  551.     case 2:
  552. if(*pos == '-')
  553.     m_comment_state = 3;
  554. else
  555.     m_comment_state = 1;
  556. break;
  557.     case 3:
  558. if(*pos == '>')
  559. {
  560.     nCommentDepth--;
  561.     if (nCommentDepth == 0)
  562.     {
  563. m_comment_state = 0;
  564. buf = (const char*)xmlStr.GetNextChar(uLen);
  565.     }
  566.     else
  567. m_comment_state = 1;
  568. }
  569. else
  570.     m_comment_state = 1;
  571. break;
  572.     case 4:
  573. // Ignore nested comments while looking for our end tag
  574. if (*pos == '!')
  575.     m_comment_state = 5;
  576. else
  577.     m_comment_state = 1;
  578. break;
  579.     case 5:
  580. if (*pos == '-')
  581.     m_comment_state = 6;
  582. else
  583.     m_comment_state = 1;
  584. break;
  585.     case 6:
  586. if (*pos == '-')
  587. {
  588.     nCommentDepth++;
  589. }
  590. m_comment_state = 1;
  591. break;
  592. }
  593. if(m_comment_state > 0)
  594. {
  595.     switch(m_comment_get_arg)
  596.     {
  597. case 1:
  598.     if(*pos != '"' && !isspace(*pos))
  599. m_comment_get_arg = 0;
  600.     else if(*pos == '"')
  601. m_comment_get_arg = 2;
  602.     break;
  603. case 2:
  604.     if(*pos != '"')
  605. if (m_comment_pos < 1023) m_comment_arg[m_comment_pos++] = *pos;
  606.     else
  607.     {
  608. if (m_comment_pos < 1024) m_comment_arg[m_comment_pos] = 0;
  609. m_comment_get_arg = 3;
  610.     }
  611.     break;
  612. default:
  613.     break;
  614.     }
  615. }
  616. pos = (const char*)xmlStr.GetNextChar(uLen);
  617.     }
  618. }
  619. XMLParseResult
  620. XMLParser::Parse(const char*& buf, UINT32 len, XMLTag*& tag, BOOL bIsFinal)
  621. {
  622.     const char* open;
  623.     const char* close;
  624.     const char* cur;
  625.     const char* afterclose;
  626.     
  627.     tag = NULL;
  628.     if(m_comment_state > 0)
  629.     {
  630. FindCommentClose(buf, buf, buf+len);
  631. if(m_comment_state != 0)
  632. {
  633.     SetError(m_pLastError, XMLErrorNoClose, 0, 0, buf, len, 0);
  634.     return XMLPNoClose;
  635. }
  636. else if(m_comment_get_arg != 3)
  637. {
  638.     tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  639.     tag->new_attribute()->value = new_string("");   // dummy tag
  640.     return XMLPComment;
  641. }
  642. // Got a comment command
  643. tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  644. tag->new_attribute()->value = new_string(m_comment_arg);
  645. tag->m_cur_attribute->name = new_string(m_comment_command);
  646. return XMLPComment;
  647.     }
  648.     if(*buf != '<')
  649.     {
  650. // If there isn't a tag right away, tell the user there's just plain
  651. // text here.
  652. UINT32 ulLine = 0;
  653. UINT32 ulCol = 0;
  654. const char* errPos = NULL;
  655. UINT32 errLen = 0;
  656. cur = buf;
  657. while(((UINT32)(cur - buf) < len) && (*cur != '<'))
  658. {
  659.     if(*cur == 'n')
  660.     {
  661. m_ulCurrentLine++;
  662. m_ulCurrentCol = 1;
  663.     }
  664.     else
  665.     {
  666. m_ulCurrentCol++;
  667.     }
  668.     if (m_bStoreErrors)
  669.     {
  670. // check for ]]>
  671. // validate refferences.
  672. if (cur - buf > 3 && *cur == ']' && *(cur+1) == ']' &&
  673.     *(cur+2) == '>' && !errPos)
  674. {
  675.     ulLine = m_ulCurrentLine;
  676.     ulCol = m_ulCurrentCol;
  677.     errPos = buf;
  678.     errLen = len;
  679. }
  680.     }
  681.     cur++;
  682. }
  683. tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  684. char* pText = new char[cur - buf + 1];
  685. strncpy(pText, buf, cur - buf); /* Flawfinder: ignore */
  686. pText[cur - buf] = '';
  687. tag->new_attribute()->value = new_string(pText);
  688. if (errPos)
  689. {
  690.     XMLError* err = NULL;
  691.     SetError(err, XMLErrorInvalidGTafter2RSQB, 
  692. ulLine, ulCol, errPos, errLen, 0);
  693.     tag->m_errs->Add(err);
  694. }
  695. delete [] pText;
  696. buf = cur;
  697. return XMLPPlainText;
  698.     }
  699.     open = buf;
  700.     CHXXMLEncode xmlStr(m_pEncoding, (BYTE*)open, len);
  701.     UINT16 uLen = 0;
  702.     m_ulTagStartLine = m_ulCurrentLine;
  703.     m_ulTagStartCol = m_ulCurrentCol;
  704.     BOOL   bInDoubleQuote = FALSE;
  705.     BOOL   bInSingleQuote = FALSE;
  706.     BOOL   bInComment   = FALSE;
  707.     BOOL   bInDeclaration = FALSE;
  708.     UINT16 nCommentDepth  = 0;
  709.     
  710.     UINT32 ulLine = 0;
  711.     UINT32 ulCol = 0;
  712.     const char* errPos = NULL;
  713.     UINT32 errLen = 0;
  714.     if(*(open+1) && *(open+1) == '!' &&
  715.        *(open+2) && *(open+2) == '-' && 
  716.        *(open+3) && *(open+3) == '-')
  717.     {
  718. // '<!--' starts a comment
  719. bInComment = TRUE;
  720.     }
  721.     for(close = (const char*)xmlStr.GetNextChar(uLen); close < buf+len; close = (const char*)xmlStr.GetNextChar(uLen))
  722.     {
  723. if(*close == 'n')
  724. {
  725.     m_ulCurrentLine++;
  726.     m_ulCurrentCol = 1;
  727. }
  728. else
  729. {
  730.     m_ulCurrentCol++;
  731. }
  732. if(*close == '"' && !bInComment)
  733. {
  734.     if(!bInSingleQuote)
  735.     {
  736. if(bInDoubleQuote)
  737. {
  738.     bInDoubleQuote = FALSE;
  739. }
  740. else
  741. {
  742.     bInDoubleQuote = TRUE;
  743. }
  744.     }
  745. }
  746. else if(*close == ''' && !bInComment)
  747. {
  748.     if(!bInDoubleQuote)
  749.     {
  750. if(bInSingleQuote)
  751. {
  752.     bInSingleQuote = FALSE;
  753. }
  754. else
  755. {
  756.     bInSingleQuote = TRUE;
  757. }
  758.     }
  759. }
  760. else if(*close == '[' && !bInDeclaration)
  761. {
  762.     bInDeclaration = TRUE;
  763. }
  764. else if(*close == ']' && bInDeclaration)
  765. {
  766.     bInDeclaration = FALSE;
  767. }
  768. // Increase the depth if we find a comment within a comment
  769. else if(*(close) == '<' && bInComment)
  770. {
  771.     if(*(close+1) && *(close+1) == '!' &&
  772.        *(close+2) && *(close+2) == '-' && 
  773.        *(close+3) && *(close+3) == '-')
  774.     {
  775. // '<!--' starts a comment
  776. nCommentDepth++;
  777.     }
  778. }
  779. else if(*close == '>')
  780. {
  781.     // If we are in a comment, we should only stop at a comment end
  782.     // (Comments must end with "-->")
  783.     if (bInComment)
  784.     {
  785. if ((!m_bAllowNonXMLComments &&
  786.      (close - open) > 5      && 
  787.      *(close-1) == '-'       && 
  788.      *(close-2) == '-')          ||
  789.     (m_bAllowNonXMLComments  &&
  790.      (close - open) > 3))
  791. {
  792.     nCommentDepth--;
  793.     if (!nCommentDepth)
  794.     {
  795. break;
  796.     }
  797. }
  798.     }
  799.     else
  800.     {
  801. if (!bInDoubleQuote && !bInSingleQuote && !bInDeclaration)
  802. {
  803.     break;
  804. }
  805.     }
  806. }
  807. if (m_bStoreErrors && bInComment && !errPos)
  808. {
  809.     if (*close == '-' && *(close+1) == '-' 
  810. && *(close + 2) != '>' && (close - open > 4))
  811.     {
  812. ulLine = m_ulCurrentLine;
  813. ulCol = m_ulCurrentCol;
  814. errPos = buf;
  815. errLen = len;
  816.     }
  817. }
  818.     }
  819.     if( (close<=buf+len) && *close != '>')
  820.     {
  821. if(!bIsFinal)
  822. {
  823.     return XMLPNotDone;
  824. }
  825. SetError(m_pLastError, XMLErrorNoClose, 0, 0, buf, len, 0);
  826. buf = open;
  827. return XMLPNoClose;
  828.     }
  829.     afterclose = close+1;
  830.     if(*(open+1) == '!')
  831.     {
  832. if(*(open+2) == '-' && *(open+3) == '-')
  833. {
  834.     // '<!--' starts a comment
  835.     m_comment_state = 1;
  836.     m_comment_start = TRUE;
  837.     m_bCommentWasFound = TRUE;
  838.     FindCommentClose(buf, open+4, buf + len);
  839.     if(m_comment_state != 0)
  840.     {
  841. SetError(m_pLastError, XMLErrorNoClose, 0, 0, buf, len, 0);
  842. return XMLPNoClose;
  843.     }
  844.     else if(m_comment_get_arg != 3)
  845.     {
  846. tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  847. const char* pBeginComment = open + 4;
  848. int commentLen = buf - pBeginComment - 3;
  849. tag->new_attribute()->value = new_string(pBeginComment, commentLen);
  850. if (errPos)
  851. {
  852.     XMLError* err = NULL;
  853.     SetError(err, XMLErrorTwoDashNotAllowed, ulLine,
  854. ulCol, errPos, errLen, 0);
  855.     tag->m_errs->Add(err);
  856. }
  857. return XMLPComment;
  858.     }
  859.     // Got a comment command
  860.     tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  861.     tag->new_attribute()->value = new_string(m_comment_arg);
  862.     tag->m_cur_attribute->name = new_string(m_comment_command);
  863.     return XMLPComment;
  864. }
  865. XMLParseResult rc = ParseTag(open+1, close, XMLDirectiveTag, tag);
  866. if(XMLPTag == rc)
  867. {
  868.     // TODO - Scan Directive 
  869.     buf = afterclose;
  870.     return XMLPDirective;
  871. }
  872. else if(XMLPAttributeValueNotQuoted == rc)
  873. {
  874.     SetError(m_pLastError, XMLErrorMissingQuote, 0, 0, buf, len, 0);
  875. }
  876. else
  877. {
  878.     SetError(m_pLastError, XMLErrorNoClose, 0, 0, buf, len, 0);
  879. }
  880. buf = afterclose;
  881. return XMLPBadDirective;
  882.     }
  883.     
  884.     if(*(open + 1) == '?')
  885.     {
  886. // A Processing Instruction
  887. XMLParseResult rc = ParseTag(open+1, close, XMLProcInstTag, tag);
  888. if(XMLPTag == rc)
  889. {
  890.     buf = afterclose;
  891.     if (m_bStrictCompliance)
  892.     {
  893. //[SMIL 1.0 Compliance] Fixes PR 9862.  No comment can
  894. // precede a processor instruction (xml prolog):
  895. if (m_bCommentWasFound  &&  m_bXMLandSMIL10FullCompliance)
  896. {
  897.     SetError(m_pLastError, XMLErrorCommentBeforeProcInst,
  898.     0, 0, buf, len, 0);
  899.     return XMLPCommentBeforeProcInst;
  900. }
  901. if (m_bStoreErrors)
  902. {
  903.     XMLError* err = NULL;
  904.     SetError(err, XMLErrorCommentBeforeProcInst,
  905.     0, 0, buf, len, 0);
  906.     tag->m_errs->Add(err);
  907. }
  908.     }
  909.     if (m_bStoreErrors)
  910.     {
  911. ScanTag(open+1, close, tag);
  912.     }
  913.     
  914.     return XMLPProcInst;
  915. }
  916.         SetError(m_pLastError, XMLErrorNoClose, 0, 0, buf, len, 0);
  917. return XMLPBadProcInst;
  918.     }
  919.     // just a plain old tag
  920.     XMLParseResult rc = ParseTag(open, close, XMLPlainTag, tag);
  921.     if(XMLPTag == rc)
  922.     {
  923. buf = afterclose;
  924. if (m_bStoreErrors)
  925. {
  926.     ScanTag(open, close, tag);
  927. }
  928. return XMLPTag;
  929.     }
  930.     else if(XMLPBadEndTag == rc)
  931.     {
  932. if(m_pCurrentFrame && m_pCurrentFrame->name)
  933. {
  934.     SetError(m_pLastError, XMLErrorBadEndTag, 0, 0, buf, len, m_pCurrentFrame->name);
  935. }
  936. else
  937. {
  938.     SetError(m_pLastError, XMLErrorBadEndTag, 0, 0, buf, len, 0);
  939. }
  940.     }
  941.     else if(XMLPBadAttribute == rc)
  942.     {
  943. SetError(m_pLastError, XMLErrorBadAttribute, 0, 0, buf, len, 0);
  944.     }
  945.     else if(XMLPAttributeValueNotQuoted == rc)
  946.     {
  947. SetError(m_pLastError, XMLErrorMissingQuote, 0, 0, buf, len, 0);
  948.     }
  949.     else if(XMLPDupAttribute == rc)
  950.     {
  951. SetError(m_pLastError, XMLErrorDupAttribute, 0, 0, buf, len, 0);
  952.     }
  953.     else
  954.     {
  955. SetError(m_pLastError, XMLUnknownError, 0, 0, buf, len, 0);
  956.     }
  957.     return rc;
  958. }
  959. XMLParseResult
  960. XMLParser::ParseTag(const char* open, const char* close, XMLTagType tType, XMLTag*& tag)
  961. {
  962.     const char* cur = open+1;
  963.     const char* afterclose = close+1;
  964.     BOOL bHasAttributeNames = TRUE;
  965.     BOOL bUseNonQuotedValues = FALSE;
  966.     BOOL bHasDirectives = FALSE;
  967.     tag = new XMLTag(m_bStrictCompliance, m_bStoreErrors);
  968.     switch(tType)
  969.     {
  970. case XMLPlainTag:
  971. {
  972.     if(*(close - 1) == '/')
  973.     {
  974. tag->m_need_close = FALSE;
  975. close--;
  976.     }
  977. }
  978. break;
  979. case XMLProcInstTag:
  980. {
  981.     tag->m_need_close = FALSE;
  982.     if(*(close - 1) == '?')
  983.     {
  984. close--;
  985.     }
  986. }
  987. break;
  988. case XMLDirectiveTag:
  989. {
  990.     bHasAttributeNames = FALSE;
  991.     bUseNonQuotedValues = TRUE;
  992.     bHasDirectives = TRUE;
  993.     tag->m_need_close = FALSE;
  994. }
  995. break;
  996. default:
  997. {
  998.     tag->m_need_close = FALSE;
  999. }
  1000. break;
  1001.     }
  1002.     tag->m_type = tType;
  1003.     GetStringResult res = GetString(cur, close, tag->m_name, TagType);
  1004.     if(res == GSEndTag)
  1005.     {
  1006. tag->m_type = XMLEndTag;
  1007. tag->m_need_close = FALSE;
  1008. if(!m_pCurrentFrame ||
  1009.     !m_pCurrentFrame->name)
  1010. {
  1011.     return XMLPBadEndTag;
  1012. }
  1013. if(m_bStrictCompliance)
  1014. {
  1015.     if(strcmp(tag->m_name, m_pCurrentFrame->name) != 0)
  1016.     {
  1017. return XMLPBadEndTag;
  1018.     }
  1019. }
  1020. else
  1021. {
  1022.     if(strcasecmp(tag->m_name, m_pCurrentFrame->name) != 0)
  1023.     {
  1024. return XMLPBadEndTag;
  1025.     }
  1026. }
  1027. tag->elem = m_pCurrentFrame->elemcount;
  1028. if(m_pCurrentFrame)
  1029.     delete m_pCurrentFrame;
  1030. m_pCurrentFrame = (XMLFrame*)m_pStack.Pop();
  1031. return XMLPTag;
  1032.     }
  1033.     else if(res == GSMissingQuote)
  1034.     {
  1035. delete tag;
  1036. tag = NULL;
  1037. return XMLPAttributeValueNotQuoted;
  1038.     }
  1039.     else if(tag->m_name && tag->m_need_close)
  1040.     {
  1041. tag->elem = m_pCurrentFrame->elemcount++;
  1042. XMLFrame* frame = new XMLFrame;
  1043. frame->elemcount = 0;
  1044. frame->name = new_string(tag->m_name);
  1045. m_pStack.Push(m_pCurrentFrame);
  1046. m_pCurrentFrame = frame;
  1047.     }
  1048.     else
  1049.     {
  1050. tag->elem = m_pCurrentFrame->elemcount++;
  1051.     }
  1052.     if(GSFoundExpected != res)
  1053.     {
  1054. delete tag;
  1055. tag = NULL;
  1056. return XMLPNoTagType;
  1057.     }
  1058.     else
  1059.     {
  1060. while(cur < close)
  1061. {
  1062.     if(bHasAttributeNames)
  1063.     {
  1064. GetStringResult res = GetString(cur, close, 
  1065. tag->new_attribute()->name,
  1066. AttributeName);
  1067. if(res == GSNoValue)
  1068. {
  1069.     delete tag->m_cur_attribute;
  1070.     tag->m_numAttributes--;
  1071.     break;
  1072. }
  1073. switch(res)
  1074. {
  1075.     case GSValueOnly:
  1076. // The user of this parser will fill in the name of this
  1077. // attribute
  1078. tag->m_cur_attribute->value = tag->m_cur_attribute->name;
  1079. tag->m_cur_attribute->name = NULL;
  1080. continue;
  1081.     case GSFoundExpected:
  1082. break;
  1083.     default:
  1084. delete tag;
  1085. tag = NULL;
  1086. return XMLPBadAttribute;
  1087. }
  1088.     }
  1089.     else
  1090.     {
  1091. tag->new_attribute()->name = 0;
  1092.     }
  1093.     if(bUseNonQuotedValues)
  1094.     {
  1095. if(bHasDirectives)
  1096. {
  1097.     res = GetString(cur, close,
  1098.     tag->m_cur_attribute->value,
  1099.     AttributeValueDirective);
  1100. }
  1101. else
  1102. {
  1103.     res = GetString(cur, close,
  1104.     tag->m_cur_attribute->value,
  1105.     AttributeValueNoQuote);
  1106. }
  1107.     }
  1108.     else
  1109.     {
  1110. res = GetString(cur, close,
  1111. tag->m_cur_attribute->value,
  1112. AttributeValue);
  1113.     }
  1114.     if(res == GSMissingQuote)
  1115.     {
  1116. delete tag;
  1117. tag = NULL;
  1118. return XMLPAttributeValueNotQuoted;
  1119.     }
  1120.     else if(res != GSFoundExpected)
  1121.     {
  1122. delete tag;
  1123. tag = NULL;
  1124. return XMLPBadAttribute;
  1125.     }
  1126. }
  1127.     }
  1128.     if(m_bStrictCompliance)
  1129.     {
  1130. // error on duplicate attributes
  1131. CHXMapStringToOb dupMap;
  1132. BOOL bDupFound = FALSE;
  1133. XMLAttribute* pAttr = NULL;
  1134. for(UINT32 i=0;i<tag->m_numAttributes;++i)
  1135. {
  1136.     pAttr = tag->attribute(i);
  1137.     void* pLookupValue = NULL;
  1138.     if(pAttr->name)
  1139.     {
  1140. if(dupMap.Lookup(pAttr->name, pLookupValue))
  1141. {
  1142.     bDupFound = TRUE;
  1143.     break;
  1144. }
  1145. else
  1146. {
  1147.     dupMap.SetAt(pAttr->name, NULL);
  1148. }
  1149.     }
  1150. }
  1151. if(bDupFound)
  1152. {
  1153. #if defined(XXXEH_CHECK_THIS_IN_AFTER_U2_RELEASE)
  1154.     return XMLPDupAttribute;
  1155. #else /* XXXEH- Back out BAB's fix for PR 9172 because it breaks a lot of
  1156.        * old content (this rebreaks PR 9172 and fixes PR 12447)
  1157.        */
  1158.     HX_ASSERT(1); //line exists only for setting a breakpoint.
  1159. #endif
  1160. }
  1161.     }
  1162.     return XMLPTag;
  1163. }
  1164. XMLParseResult
  1165. XMLParser::ScanTag(const char* open, const char* close, XMLTag* tag)
  1166. {
  1167.     const char* cur = open+1;
  1168.     const char* afterclose = close+1;
  1169.     char cQuote = '"';
  1170.     CHXXMLEncode xmlStr(m_pEncoding, (BYTE*)cur, close - cur);
  1171.     UINT16 uLen = 0;
  1172.     const char* ptr = (const char*)xmlStr.GetNextChar(uLen);
  1173.     //tag->m_need_close
  1174.     //tag->m_type;
  1175.     // check the spacing....
  1176.     switch (tag->m_type)
  1177.     {
  1178.     case XMLEndTag:
  1179. {
  1180.     // scan name...
  1181.     if (!xmlStr.IsNameValid((const BYTE*)tag->m_name, strlen(tag->m_name)))
  1182.     {
  1183. XMLError* err = NULL;
  1184. SetError(err, XMLErrorInvalidName, m_ulTagStartLine, m_ulTagStartCol, 
  1185.     tag->m_name, strlen(tag->m_name), 0);
  1186. tag->m_errs->Add(err);
  1187.     }
  1188. }
  1189. break;
  1190.     case XMLPlainTag:
  1191.     case XMLProcInstTag:
  1192. {
  1193.     // scan tag
  1194.     if (!xmlStr.IsNameValid((const BYTE*)tag->m_name, strlen(tag->m_name)))
  1195.     {
  1196. XMLError* err = NULL;
  1197. SetError(err, XMLErrorInvalidName, m_ulTagStartLine, m_ulTagStartCol, 
  1198.     tag->m_name, strlen(tag->m_name), 0);
  1199. tag->m_errs->Add(err);
  1200.     }
  1201.     // check PI name
  1202.     //if (!xmlStr.IsPINameValid(tag->m_name, strlen(tag->m_name)))
  1203.     //{
  1204. // XMLError* err = NULL;
  1205. // SetError(err, XMLErrorInvalidPITarget, m_ulTagStartLine, m_ulTagStartCol, 
  1206. //     tag->m_name, strlen(tag->m_name), 0);
  1207. // tag->m_errs->Add(err);
  1208.   //  }
  1209.     // check the spacing.
  1210.     enum { InTagName, InTag, InBeginAttributeName, InAttributeName, 
  1211. InEndAttributeName, InBeginAttributeValue, InAttributeValue, Done } state;
  1212.     state = InTagName;
  1213.     
  1214.     for (const char* pos = cur; *pos && pos < close && state != Done;
  1215. pos = (const char*)xmlStr.GetNextChar(uLen))
  1216.     {
  1217. switch (state)
  1218. {
  1219. case InTagName:
  1220.     {
  1221. // go to first white space
  1222. if ( isspace(*pos) )
  1223. {
  1224.     state = InBeginAttributeName;
  1225. }
  1226. else if ( *pos == '>' )
  1227. {
  1228.     // done
  1229.     state = Done;
  1230. }
  1231.     }
  1232.     break;
  1233. case InTag:
  1234.     {
  1235. if ( *pos == '>' || (*pos == '/' && 
  1236.     *(pos+1) == '>'))
  1237. {
  1238.     // done.
  1239.     state = Done;
  1240. }
  1241. else
  1242. {
  1243.     // grab the first char... keep it and switch states.
  1244.     // it should be a space... 
  1245.     state = InBeginAttributeName;
  1246.     if (!isspace(*pos))
  1247.     {
  1248. XMLError* err = NULL;
  1249. SetError(err, XMLErrorMissingReqSpace, m_ulTagStartLine, m_ulTagStartCol, 
  1250.     tag->m_name, strlen(tag->m_name), 0);
  1251. tag->m_errs->Add(err);
  1252.     }
  1253. }
  1254.     }
  1255.     break;
  1256. case InBeginAttributeName:
  1257.     {
  1258. if ( isspace(*pos) )
  1259. {
  1260.     // continue...
  1261. }
  1262. else if ( *pos == '=' )
  1263. {
  1264.     XMLError* err = NULL;
  1265.     SetError(err, XMLErrorMissingEquals, m_ulTagStartLine, m_ulTagStartCol, 
  1266. tag->m_name, strlen(tag->m_name), 0);
  1267.     tag->m_errs->Add(err);
  1268.     state = InBeginAttributeValue;
  1269. }
  1270. else if ( *pos == '>' || (*pos == '/' 
  1271.     && *(pos+1) == '>'))
  1272. {
  1273.     // done
  1274.     state = Done;
  1275. }
  1276. else
  1277. {
  1278.     state = InAttributeName;
  1279. }
  1280.     }
  1281.     break;
  1282. case InAttributeName:
  1283.     {
  1284. if ( isspace(*pos) )
  1285. {
  1286.     state = InEndAttributeName;
  1287. }
  1288. else if ( *pos == '=' )
  1289. {
  1290.     state = InBeginAttributeValue;
  1291. }
  1292. else if ( *pos == '>' )
  1293. {
  1294.     XMLError* err = NULL;
  1295.     SetError(err, XMLErrorMissingEquals, m_ulTagStartLine, m_ulTagStartCol, 
  1296. tag->m_name, strlen(tag->m_name), 0);
  1297.     
  1298.     tag->m_errs->Add(err);
  1299.     // done
  1300.     state = Done;
  1301. }
  1302. else if (*pos == ''' || *pos == '"')
  1303. {
  1304.     XMLError* err = NULL;
  1305.     SetError(err, XMLErrorBadAttribute, m_ulTagStartLine, m_ulTagStartCol, 
  1306. tag->m_name, strlen(tag->m_name), 0);
  1307.     tag->m_errs->Add(err);
  1308.     cQuote = *pos;
  1309.     state = InAttributeValue;
  1310. }
  1311.     }
  1312.     break;
  1313. case InEndAttributeName:
  1314.     {
  1315. if ( isspace(*pos) )
  1316. {
  1317.     // continue..
  1318. }
  1319. else if ( *pos == '=' )
  1320. {
  1321.     state = InBeginAttributeValue;
  1322. }
  1323. else if ( *pos == '>' )
  1324. {
  1325.     XMLError* err = NULL;
  1326.     SetError(err, XMLErrorMissingEquals, m_ulTagStartLine, m_ulTagStartCol, 
  1327. tag->m_name, strlen(tag->m_name), 0);
  1328.     tag->m_errs->Add(err);
  1329.     state = Done;
  1330. }
  1331. else
  1332. {
  1333.     // hmm. we got a non whitespace before the =
  1334.     //First, let's see if we have a ["] or a [']
  1335.     // (i.e., an attribute value start) in which
  1336.     // case the author must have forgotten to
  1337.     // put an '=' between the name/value pair.
  1338.     // In this case, we need to keep the renderers
  1339.     // from firing off an error with old bad content,
  1340.     // so we pretend we're in the "InAttributeValue"
  1341.     // state:
  1342.     if ( *pos == ''' )
  1343.     {
  1344. XMLError* err = NULL;
  1345. SetError(err, XMLErrorBadAttribute, m_ulTagStartLine, m_ulTagStartCol, 
  1346.     tag->m_name, strlen(tag->m_name), 0);
  1347. tag->m_errs->Add(err);
  1348. cQuote = *pos;
  1349. state = InAttributeValue;
  1350.     }
  1351.     else if ( *pos == '"' )
  1352.     {
  1353. XMLError* err = NULL;
  1354. SetError(err, XMLErrorBadAttribute, m_ulTagStartLine, m_ulTagStartCol, 
  1355.     tag->m_name, strlen(tag->m_name), 0);
  1356. tag->m_errs->Add(err);
  1357. cQuote = *pos;
  1358. state = InAttributeValue;
  1359.     }
  1360.     else
  1361.     {
  1362. XMLError* err = NULL;
  1363. SetError(err, XMLErrorBadAttribute, m_ulTagStartLine, m_ulTagStartCol, 
  1364. tag->m_name, strlen(tag->m_name), 0);
  1365. tag->m_errs->Add(err);
  1366. // lets go back to the attribute name state.
  1367. state = InAttributeName;
  1368.     }
  1369. }
  1370.     }
  1371.     break;
  1372. case InBeginAttributeValue:
  1373.     {
  1374. if ( isspace(*pos) )
  1375. {
  1376. }
  1377. else if ( *pos == ''' || *pos == '"')
  1378. {
  1379.     cQuote = *pos;
  1380.     state = InAttributeValue;
  1381. }
  1382. else if ( *pos == '>' )
  1383. {
  1384.     XMLError* err = NULL;
  1385.     SetError(err, XMLErrorMissingEquals, m_ulTagStartLine, m_ulTagStartCol, 
  1386. tag->m_name, strlen(tag->m_name), 0);
  1387.     tag->m_errs->Add(err);
  1388.     // done
  1389.     state = Done;
  1390. }
  1391.     }
  1392.     break;
  1393. case InAttributeValue:
  1394.     {
  1395. if ( *pos == cQuote )
  1396. {
  1397.     state = InTag;
  1398. }
  1399.     }
  1400.     break;
  1401. }
  1402.     }
  1403. }
  1404. break;
  1405.     case XMLCommentTag:
  1406. {
  1407.     // we will not scan...
  1408. }
  1409. break;
  1410.     case XMLDirectiveTag:
  1411. {
  1412.     // TODO: scan Directive.
  1413. }
  1414. break;
  1415.     }
  1416.     // error on duplicate attributes
  1417.     // also validate the names and attributes.
  1418.     CHXMapStringToOb dupMap;
  1419.     BOOL bDupFound = FALSE;
  1420.     XMLAttribute* pAttr = NULL;
  1421.     const char* name = NULL;
  1422.     for(UINT32 i=0;i<tag->m_numAttributes;++i)
  1423.     {
  1424. pAttr = tag->attribute(i);
  1425. if (!xmlStr.IsNameValid((const BYTE*)pAttr->name, strlen(pAttr->name)))
  1426. {
  1427.     XMLError* err = NULL;
  1428.     SetError(err, XMLErrorInvalidName, m_ulTagStartLine, m_ulTagStartCol, 
  1429.     pAttr->name, strlen(pAttr->name), 0);
  1430.     tag->m_errs->Add(err);
  1431. }
  1432. if (!xmlStr.IsAttValueValid((const BYTE*)pAttr->value, strlen(pAttr->value)))
  1433. {
  1434.     XMLError* err = NULL;
  1435.     SetError(err, XMLErrorInvalidCharInDoc, m_ulTagStartLine, m_ulTagStartCol, 
  1436.     pAttr->value, strlen(pAttr->value), 0);
  1437.     tag->m_errs->Add(err);
  1438. }
  1439. void* pLookupValue = NULL;
  1440. if(pAttr->name)
  1441. {
  1442.     if(dupMap.Lookup(pAttr->name, pLookupValue))
  1443.     {
  1444. name = pAttr->name;
  1445. bDupFound = TRUE;
  1446. break;
  1447.     }
  1448.     else
  1449.     {
  1450. dupMap.SetAt(pAttr->name, NULL);
  1451.     }
  1452. }
  1453.     }
  1454.     if (bDupFound)
  1455.     {
  1456. XMLError* err = NULL;
  1457. SetError(err, XMLErrorDupAttribute, m_ulTagStartLine, m_ulTagStartCol, 
  1458. name, strlen(name), 0);
  1459. tag->m_errs->Add(err);
  1460.     }
  1461.     return XMLPTag;
  1462. }
  1463.     
  1464. void XMLParser::SetEncoding(const char* pszEncoding)
  1465. {
  1466.     if (pszEncoding)
  1467.     {
  1468.         INT32 lLen = strlen(pszEncoding);
  1469.         if (lLen > 0)
  1470.         {
  1471.             HX_VECTOR_DELETE(m_pEncoding);
  1472.             m_pEncoding = new char [lLen + 1];
  1473.             if (m_pEncoding)
  1474.             {
  1475.                 strcpy(m_pEncoding, pszEncoding);
  1476.             }
  1477.         }
  1478.     }
  1479. }
  1480. HX_RESULT XMLParser::GetEncoding(REF(char*) rpszEncoding)
  1481. {
  1482.     HX_RESULT retVal = HXR_FAIL;
  1483.     if (m_pEncoding)
  1484.     {
  1485.         HX_VECTOR_DELETE(rpszEncoding);
  1486.         rpszEncoding = new char [strlen(m_pEncoding) + 1];
  1487.         if (rpszEncoding)
  1488.         {
  1489.             strcpy(rpszEncoding, m_pEncoding);
  1490.             retVal = HXR_OK;
  1491.         }
  1492.     }
  1493.     return retVal;
  1494. }
  1495. void
  1496. XMLParser::SetError(REF(XMLError*) pErr, XMLErrorTag tag, INT32 lLine,
  1497.     INT32 lPos, const char* pErrorText, INT32 lErrorTextLen,
  1498.     const char* pFrameText)
  1499. {
  1500.     HX_DELETE(m_pLastError);
  1501.     INT32 lTextLen = 
  1502. (lErrorTextLen > MAX_ERROR_LEN) ? MAX_ERROR_LEN: lErrorTextLen;
  1503.     char tmpBuf[MAX_ERROR_LEN * 2]; // overdo it a bit...
  1504.     // convert control characters to spaces
  1505.     INT32 j = 0;
  1506.     for(INT32 i = 0; i < lTextLen; ++i)
  1507.     {
  1508. if(iscntrl(pErrorText[i]))
  1509. {
  1510.     tmpBuf[j++] = ' ';
  1511. }
  1512. else
  1513. {
  1514.     tmpBuf[j++] = pErrorText[i];
  1515. }
  1516.     }
  1517.     tmpBuf[j] = 0;
  1518.     pErr = new XMLError(tag, lLine, lPos, tmpBuf, pFrameText);
  1519. }
  1520. XMLTag::XMLTag(BOOL bStrictCompliance, BOOL bStoreErrors):
  1521.     m_bStrictCompliance(bStrictCompliance)
  1522. {
  1523.     m_numAttributes = 0;
  1524.     m_name = NULL;
  1525.     m_type = XMLPlainTag;
  1526.     m_need_close = TRUE;
  1527.     m_errs = NULL;
  1528.     if (bStoreErrors)
  1529.     {
  1530. m_errs = new CHXPtrArray();
  1531.     }
  1532. }
  1533. XMLTag::~XMLTag()
  1534. {
  1535.     UINT32 i;
  1536.     for(i = 0; i < m_numAttributes; i++)
  1537.     {
  1538. delete (XMLAttribute*)m_attributes[(int)i];
  1539.     }
  1540.     HX_VECTOR_DELETE(m_name);
  1541.     if (m_errs)
  1542.     {
  1543. UINT32 size = m_errs->GetSize();
  1544. for(i = 0; i < size; i++)
  1545. {
  1546.     delete (XMLError*)(*m_errs)[(int)i];
  1547. }
  1548. HX_DELETE(m_errs);
  1549.     }
  1550. }
  1551. XMLAttribute*
  1552. XMLTag::new_attribute()
  1553. {
  1554.     m_cur_attribute = new XMLAttribute;
  1555.     
  1556.     m_attributes.SetAtGrow((int)m_numAttributes, m_cur_attribute);
  1557.     m_numAttributes++;
  1558.     return m_cur_attribute;
  1559. }
  1560. const char*
  1561. XMLTag::get_attribute(const char* name)
  1562. {
  1563.     for(UINT32 i = 0; i < m_numAttributes; i++)
  1564.     {
  1565. if(((XMLAttribute*)m_attributes[(int)i])->name)
  1566. {
  1567.     if(m_bStrictCompliance)
  1568.     {
  1569. if(strcmp(((XMLAttribute*)m_attributes[(int)i])->name, name) == 0)
  1570. {
  1571.     return (const char*)((XMLAttribute*)m_attributes[(int)i])->value;
  1572. }
  1573.     }
  1574.     else
  1575.     {
  1576. if(strcasecmp(((XMLAttribute*)m_attributes[(int)i])->name, name) == 0)
  1577. {
  1578.     return (const char*)((XMLAttribute*)m_attributes[(int)i])->value;
  1579. }
  1580.     }
  1581. }
  1582.     }
  1583.     return NULL;
  1584. }
  1585. /*
  1586.  * XMLError methods
  1587.  */
  1588. XMLError::XMLError(XMLErrorTag errorTag,
  1589.    INT32 lLineNumber,
  1590.    INT32 lLinePosition,
  1591.    const char* pErrorString,
  1592.    const char* pFrameString):
  1593.     m_errorTag(errorTag),
  1594.     m_lLineNumber(lLineNumber),
  1595.     m_lLinePosition(lLinePosition),
  1596.     m_pErrorString(0),
  1597.     m_pFrameString(0)
  1598. {
  1599.     if(pErrorString)
  1600.     {
  1601. m_pErrorString = new_string(pErrorString);
  1602.     }
  1603.     if(pFrameString)
  1604.     {
  1605. m_pFrameString = new_string(pFrameString);
  1606.     }
  1607. }
  1608. XMLError::~XMLError()
  1609. {
  1610.     delete[] m_pErrorString;
  1611.     delete[] m_pFrameString;
  1612. }