387 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			387 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright (C)2005-2019 Haxe Foundation
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Permission is hereby granted, free of charge, to any person obtaining a
							 | 
						||
| 
								 | 
							
								 * copy of this software and associated documentation files (the "Software"),
							 | 
						||
| 
								 | 
							
								 * to deal in the Software without restriction, including without limitation
							 | 
						||
| 
								 | 
							
								 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
							 | 
						||
| 
								 | 
							
								 * and/or sell copies of the Software, and to permit persons to whom the
							 | 
						||
| 
								 | 
							
								 * Software is furnished to do so, subject to the following conditions:
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * The above copyright notice and this permission notice shall be included in
							 | 
						||
| 
								 | 
							
								 * all copies or substantial portions of the Software.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
							 | 
						||
| 
								 | 
							
								 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
							 | 
						||
| 
								 | 
							
								 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
							 | 
						||
| 
								 | 
							
								 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
							 | 
						||
| 
								 | 
							
								 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
							 | 
						||
| 
								 | 
							
								 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
							 | 
						||
| 
								 | 
							
								 * DEALINGS IN THE SOFTWARE.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef EPPC
							 | 
						||
| 
								 | 
							
								#include <memory>
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#include <memory.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef HX_WINDOWS
							 | 
						||
| 
								 | 
							
								#  include <strings.h>
							 | 
						||
| 
								 | 
							
								#  undef strcmpi
							 | 
						||
| 
								 | 
							
								#  define strcmpi(a,b) strcasecmp(a,b)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#   include <string.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// -------------- parsing --------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum STATE {
							 | 
						||
| 
								 | 
							
								   IGNORE_SPACES,
							 | 
						||
| 
								 | 
							
								   BEGIN,
							 | 
						||
| 
								 | 
							
								   BEGIN_NODE,
							 | 
						||
| 
								 | 
							
								   TAG_NAME,
							 | 
						||
| 
								 | 
							
								   BODY,
							 | 
						||
| 
								 | 
							
								   ATTRIB_NAME,
							 | 
						||
| 
								 | 
							
								   EQUALS,
							 | 
						||
| 
								 | 
							
								   ATTVAL_BEGIN,
							 | 
						||
| 
								 | 
							
								   ATTRIB_VAL,
							 | 
						||
| 
								 | 
							
								   CHILDS,
							 | 
						||
| 
								 | 
							
								   CLOSE,
							 | 
						||
| 
								 | 
							
								   WAIT_END,
							 | 
						||
| 
								 | 
							
								   WAIT_END_RET,
							 | 
						||
| 
								 | 
							
								   PCDATA,
							 | 
						||
| 
								 | 
							
								   HEADER,
							 | 
						||
| 
								 | 
							
								   COMMENT,
							 | 
						||
| 
								 | 
							
								   DOCTYPE,
							 | 
						||
| 
								 | 
							
								   CDATA,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void xml_error( const char *xml, const char *inWhere, int *line, String msg ) {
							 | 
						||
| 
								 | 
							
								   String b = HX_CSTRING("Xml parse error : ") + msg + HX_CSTRING(" at line ") + String(*line) + HX_CSTRING(" : ");
							 | 
						||
| 
								 | 
							
								   String where(inWhere);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   int l = where.length;
							 | 
						||
| 
								 | 
							
								   int nchars = 30;
							 | 
						||
| 
								 | 
							
								   if( inWhere != xml )
							 | 
						||
| 
								 | 
							
								      b += HX_CSTRING("...");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if (where.length==0)
							 | 
						||
| 
								 | 
							
								      b+= HX_CSTRING("<eof>");
							 | 
						||
| 
								 | 
							
								   else if (where.length<nchars)
							 | 
						||
| 
								 | 
							
								      b+= where;
							 | 
						||
| 
								 | 
							
								   else
							 | 
						||
| 
								 | 
							
								      b+= where.substr(0,nchars) + HX_CSTRING("...");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   hx::Throw(b);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ERRORSTR(msg)   xml_error(xml,p,line,msg);
							 | 
						||
| 
								 | 
							
								#define ERROR(msg)   xml_error(xml,p,line,HX_CSTRING(msg));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool is_valid_char( int c ) {
							 | 
						||
| 
								 | 
							
								   return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || c == ':' || c == '.' || c == '_' || c == '-';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void do_parse_xml( const char *xml, const char **lp, int *line, cpp::NativeXmlState callb, String parentname )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   STATE state = BEGIN;
							 | 
						||
| 
								 | 
							
								   STATE next = BEGIN;
							 | 
						||
| 
								 | 
							
								   String aname;
							 | 
						||
| 
								 | 
							
								   hx::Anon attribs;
							 | 
						||
| 
								 | 
							
								   String nodename;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   const char *start = NULL;
							 | 
						||
| 
								 | 
							
								   const char *p = *lp;
							 | 
						||
| 
								 | 
							
								   char c = *p;
							 | 
						||
| 
								 | 
							
								   int nsubs = 0, nbrackets = 0;
							 | 
						||
| 
								 | 
							
								   while( c ) {
							 | 
						||
| 
								 | 
							
								      switch( state ) {
							 | 
						||
| 
								 | 
							
								      case IGNORE_SPACES:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '\n':
							 | 
						||
| 
								 | 
							
								         case '\r':
							 | 
						||
| 
								 | 
							
								         case '\t':
							 | 
						||
| 
								 | 
							
								         case ' ':
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            state = next;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case BEGIN:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '<':
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = BEGIN_NODE;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            start = p;
							 | 
						||
| 
								 | 
							
								            state = PCDATA;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case PCDATA:
							 | 
						||
| 
								 | 
							
								         if( c == '<' ) {
							 | 
						||
| 
								 | 
							
								            callb->pcdata(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								            nsubs++;
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = BEGIN_NODE;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case CDATA:
							 | 
						||
| 
								 | 
							
								         if( c == ']' && p[1] == ']' && p[2] == '>' ) {
							 | 
						||
| 
								 | 
							
								            callb->cdata(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								            nsubs++;
							 | 
						||
| 
								 | 
							
								            p += 2;
							 | 
						||
| 
								 | 
							
								            state = BEGIN;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case BEGIN_NODE:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '!':
							 | 
						||
| 
								 | 
							
								            if( p[1] == '[' ) {
							 | 
						||
| 
								 | 
							
								               p += 2;
							 | 
						||
| 
								 | 
							
								               if( (p[0] != 'C' && p[0] != 'c') ||
							 | 
						||
| 
								 | 
							
								                  (p[1] != 'D' && p[1] != 'd') ||
							 | 
						||
| 
								 | 
							
								                  (p[2] != 'A' && p[2] != 'a') ||
							 | 
						||
| 
								 | 
							
								                  (p[3] != 'T' && p[3] != 't') ||
							 | 
						||
| 
								 | 
							
								                  (p[4] != 'A' && p[4] != 'a') ||
							 | 
						||
| 
								 | 
							
								                  (p[5] != '[') )
							 | 
						||
| 
								 | 
							
								                  ERROR("Expected <![CDATA[");
							 | 
						||
| 
								 | 
							
								               p += 5;
							 | 
						||
| 
								 | 
							
								               state = CDATA;
							 | 
						||
| 
								 | 
							
								               start = p + 1;
							 | 
						||
| 
								 | 
							
								               break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if( p[1] == 'D' || p[1] == 'd' ) {
							 | 
						||
| 
								 | 
							
								               if( (p[2] != 'O' && p[2] != 'o') ||
							 | 
						||
| 
								 | 
							
								                  (p[3] != 'C' && p[3] != 'c') ||
							 | 
						||
| 
								 | 
							
								                  (p[4] != 'T' && p[4] != 't') ||
							 | 
						||
| 
								 | 
							
								                  (p[5] != 'Y' && p[5] != 'y') ||
							 | 
						||
| 
								 | 
							
								                  (p[6] != 'P' && p[6] != 'p') ||
							 | 
						||
| 
								 | 
							
								                  (p[7] != 'E' && p[7] != 'e') )
							 | 
						||
| 
								 | 
							
								                  ERROR("Expected <!DOCTYPE");
							 | 
						||
| 
								 | 
							
								               p += 7;
							 | 
						||
| 
								 | 
							
								               state = DOCTYPE;
							 | 
						||
| 
								 | 
							
								               start = p + 1;
							 | 
						||
| 
								 | 
							
								               break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if( p[1] != '-' || p[2] != '-' )
							 | 
						||
| 
								 | 
							
								               ERROR("Expected <!--");
							 | 
						||
| 
								 | 
							
								            p += 2;
							 | 
						||
| 
								 | 
							
								            state = COMMENT;
							 | 
						||
| 
								 | 
							
								            start = p + 1;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case '?':
							 | 
						||
| 
								 | 
							
								            state = HEADER;
							 | 
						||
| 
								 | 
							
								            start = p;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case '/':
							 | 
						||
| 
								 | 
							
								            if( parentname.length==0 )
							 | 
						||
| 
								 | 
							
								               ERROR("Expected node name");
							 | 
						||
| 
								 | 
							
								            start = p + 1;
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = CLOSE;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            state = TAG_NAME;
							 | 
						||
| 
								 | 
							
								            start = p;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case TAG_NAME:
							 | 
						||
| 
								 | 
							
								         if( !is_valid_char(c) ) {
							 | 
						||
| 
								 | 
							
								            if( p == start )
							 | 
						||
| 
								 | 
							
								               ERROR("Expected node name");
							 | 
						||
| 
								 | 
							
								            nodename = String(start,p-start).dup();
							 | 
						||
| 
								 | 
							
								            attribs = hx::Anon_obj::Create();
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = BODY;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case BODY:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '/':
							 | 
						||
| 
								 | 
							
								            state = WAIT_END;
							 | 
						||
| 
								 | 
							
								            nsubs++;
							 | 
						||
| 
								 | 
							
								            callb->xml(nodename,attribs);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case '>':
							 | 
						||
| 
								 | 
							
								            state = CHILDS;
							 | 
						||
| 
								 | 
							
								            nsubs++;
							 | 
						||
| 
								 | 
							
								            callb->xml(nodename,attribs);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            state = ATTRIB_NAME;
							 | 
						||
| 
								 | 
							
								            start = p;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case ATTRIB_NAME:
							 | 
						||
| 
								 | 
							
								         if( !is_valid_char(c) ) {
							 | 
						||
| 
								 | 
							
								            if( start == p )
							 | 
						||
| 
								 | 
							
								               ERROR("Expected attribute name");
							 | 
						||
| 
								 | 
							
								            aname = String(start,p-start).dup();
							 | 
						||
| 
								 | 
							
								            if( attribs->__Field(aname,hx::paccDynamic) != null() )
							 | 
						||
| 
								 | 
							
								               ERROR("Duplicate attribute");
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = EQUALS;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case EQUALS:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '=':
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = ATTVAL_BEGIN;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            ERROR("Expected =");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case ATTVAL_BEGIN:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '"':
							 | 
						||
| 
								 | 
							
								         case '\'':
							 | 
						||
| 
								 | 
							
								            state = ATTRIB_VAL;
							 | 
						||
| 
								 | 
							
								            start = p;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            ERROR("Expected \"");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case ATTRIB_VAL:
							 | 
						||
| 
								 | 
							
								         if( c == *start ) {
							 | 
						||
| 
								 | 
							
								            attribs->Add( aname, String(start+1,p-start-1).dup() );
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = BODY;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case CHILDS:
							 | 
						||
| 
								 | 
							
								         *lp = p;
							 | 
						||
| 
								 | 
							
								         do_parse_xml(xml,lp,line,callb,nodename);
							 | 
						||
| 
								 | 
							
								         p = *lp;
							 | 
						||
| 
								 | 
							
								         start = p;
							 | 
						||
| 
								 | 
							
								         state = BEGIN;
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case WAIT_END:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '>':
							 | 
						||
| 
								 | 
							
								            callb->done();
							 | 
						||
| 
								 | 
							
								            state = BEGIN;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         default :
							 | 
						||
| 
								 | 
							
								            ERROR("Expected >");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case WAIT_END_RET:
							 | 
						||
| 
								 | 
							
								         switch( c ) {
							 | 
						||
| 
								 | 
							
								         case '>':
							 | 
						||
| 
								 | 
							
								            if( nsubs == 0 )
							 | 
						||
| 
								 | 
							
								               callb->pcdata(HX_CSTRING(""));
							 | 
						||
| 
								 | 
							
								            *lp = p;
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								         default :
							 | 
						||
| 
								 | 
							
								            ERROR("Expected >");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case CLOSE:
							 | 
						||
| 
								 | 
							
								         if( !is_valid_char(c) ) {
							 | 
						||
| 
								 | 
							
								            if( start == p )
							 | 
						||
| 
								 | 
							
								               ERROR("Expected node name");
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               String v = String(start,p - start).dup();
							 | 
						||
| 
								 | 
							
								               if( strcmpi(parentname.__s,v.__s) != 0 ) {
							 | 
						||
| 
								 | 
							
								                  ERRORSTR(HX_CSTRING("Expected </") + parentname + HX_CSTRING(">"));
							 | 
						||
| 
								 | 
							
								               }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            state = IGNORE_SPACES;
							 | 
						||
| 
								 | 
							
								            next = WAIT_END_RET;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case COMMENT:
							 | 
						||
| 
								 | 
							
								         if( c == '-' && p[1] == '-' && p[2] == '>' ) {
							 | 
						||
| 
								 | 
							
								            callb->comment(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								            p += 2;
							 | 
						||
| 
								 | 
							
								            state = BEGIN;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case DOCTYPE:
							 | 
						||
| 
								 | 
							
								         if( c == '[' )
							 | 
						||
| 
								 | 
							
								            nbrackets++;
							 | 
						||
| 
								 | 
							
								         else if( c == ']' )
							 | 
						||
| 
								 | 
							
								            nbrackets--;
							 | 
						||
| 
								 | 
							
								         else if( c == '>' && nbrackets == 0 ) {
							 | 
						||
| 
								 | 
							
								            callb->doctype(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								            state = BEGIN;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      case HEADER:
							 | 
						||
| 
								 | 
							
								         if( c == '?' && p[1] == '>' ) {
							 | 
						||
| 
								 | 
							
								            p++;
							 | 
						||
| 
								 | 
							
								            callb->comment(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								            state = BEGIN;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      c = *++p;
							 | 
						||
| 
								 | 
							
								      if( c == '\n' )
							 | 
						||
| 
								 | 
							
								         (*line)++;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if( state == BEGIN ) {
							 | 
						||
| 
								 | 
							
								      start = p;
							 | 
						||
| 
								 | 
							
								      state = PCDATA;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if( parentname.__s == 0 && state == PCDATA ) {
							 | 
						||
| 
								 | 
							
								      if( p != start || nsubs == 0 )
							 | 
						||
| 
								 | 
							
								         callb->pcdata(String(start,p-start).dup());
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   ERROR("Unexpected end");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ----------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								   <doc>
							 | 
						||
| 
								 | 
							
								   <h1>Xml</h1>
							 | 
						||
| 
								 | 
							
								   <p>
							 | 
						||
| 
								 | 
							
								   The standard event-driven XML parser.
							 | 
						||
| 
								 | 
							
								   </p>
							 | 
						||
| 
								 | 
							
								   </doc>
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								   parse_xml : xml:string -> events:object -> void
							 | 
						||
| 
								 | 
							
								   <doc>
							 | 
						||
| 
								 | 
							
								   The [parse_xml] parse a string and for each parsed element call the
							 | 
						||
| 
								 | 
							
								   corresponding object method in [events] :
							 | 
						||
| 
								 | 
							
								   <ul>
							 | 
						||
| 
								 | 
							
								   <li>[void xml( name : string, attribs : object)] when an XML node is found</li>
							 | 
						||
| 
								 | 
							
								   <li>[void done()] when an XML node is closed</li>
							 | 
						||
| 
								 | 
							
								   <li>[void pcdata(string)] when PCData chars found</li>
							 | 
						||
| 
								 | 
							
								   <li>[void cdata(string)] when a CData session is found</li>
							 | 
						||
| 
								 | 
							
								   <li>[void comment(string)] when some comment or special header is found</li>
							 | 
						||
| 
								 | 
							
								   </ul>
							 | 
						||
| 
								 | 
							
								   You can then implement the events so they build the appropriate XML data
							 | 
						||
| 
								 | 
							
								   structure needed by your language.
							 | 
						||
| 
								 | 
							
								   </doc>
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								static void parse_xml( String str, cpp::NativeXmlState state )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   int line = 0;
							 | 
						||
| 
								 | 
							
								   const char *p = str.__s;
							 | 
						||
| 
								 | 
							
								   // skip BOM
							 | 
						||
| 
								 | 
							
								   if( p[0] == (char)0xEF && p[1] == (char)0xBB && p[2] == (char)0xBF )
							 | 
						||
| 
								 | 
							
								      p += 3;
							 | 
						||
| 
								 | 
							
								   do_parse_xml(p,&p,&line,state,String());
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 |