Update Files
This commit is contained in:
386
Kha/Tools/linux_x64/std/cpp/NativeXmlImport.cpp
Normal file
386
Kha/Tools/linux_x64/std/cpp/NativeXmlImport.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user