looseprs.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:40k
源码类别:

Symbian

开发平台:

Visual C++

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