mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-39124 XMLTYPE: allow only well-formed XML.
Necessary checks added to the XMLTYPE.
This commit is contained in:
@@ -40,6 +40,13 @@ extern "C" {
|
||||
*/
|
||||
#define MY_XML_FLAG_SKIP_TEXT_NORMALIZATION 2
|
||||
|
||||
/*
|
||||
A flag if parsing should fail when XML is not
|
||||
Well Formed as it's described in standards.
|
||||
Like having exactly one root element an <?xml on top.
|
||||
*/
|
||||
#define MY_XML_FLAG_ASSERT_WELL_FORMED 4
|
||||
|
||||
enum my_xml_node_type
|
||||
{
|
||||
MY_XML_NODE_TAG, /* can have TAG, ATTR and TEXT children */
|
||||
@@ -52,6 +59,15 @@ typedef struct xml_stack_st
|
||||
int flags;
|
||||
enum my_xml_node_type current_node_type;
|
||||
char errstr[128];
|
||||
int root_node_counter;
|
||||
|
||||
/*
|
||||
Counts some items to verify that the possible
|
||||
<?xml..?> instruction is first in the document.
|
||||
It counts all the root items and some nested that
|
||||
are easier to count than to detect if they're on the root.
|
||||
*/
|
||||
int item_counter;
|
||||
|
||||
struct {
|
||||
char static_buffer[128];
|
||||
@@ -68,6 +84,10 @@ typedef struct xml_stack_st
|
||||
int (*enter)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
int (*value)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
int (*leave_xml)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
|
||||
int (*processing_instruction)(struct xml_stack_st *st,
|
||||
const char *target, size_t target_len,
|
||||
const char *value, size_t value_len);
|
||||
} MY_XML_PARSER;
|
||||
|
||||
void my_xml_parser_create(MY_XML_PARSER *st);
|
||||
@@ -83,6 +103,8 @@ void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *,
|
||||
void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *,
|
||||
const char *,
|
||||
size_t len));
|
||||
void my_xml_set_processing_instruction_handler(MY_XML_PARSER *st,
|
||||
int (*)(MY_XML_PARSER *, const char *, size_t, const char *, size_t));
|
||||
void my_xml_set_user_data(MY_XML_PARSER *st, void *);
|
||||
|
||||
size_t my_xml_error_pos(MY_XML_PARSER *st);
|
||||
|
||||
@@ -5267,9 +5267,9 @@ DROP TABLE t1,t2;
|
||||
#
|
||||
# MDEV-18205 Assertion `str_length < len' failed in Binary_string::realloc_raw
|
||||
#
|
||||
SELECT GROUP_CONCAT( UpdateXML( '<a>new year</a>', '/a', '2019-01-01 00:00:00' ), ENCODE('text','pass') ) AS f;
|
||||
SELECT GROUP_CONCAT( UpdateXML( '<a>new year</a>', '/a', '<z>2019-01-01 00:00:00</z>' ), ENCODE('text','pass') ) AS f;
|
||||
f
|
||||
2019-01-01 00:00:00F}^i
|
||||
<z>2019-01-01 00:00:00</z>F}^i
|
||||
#
|
||||
# MDEV-31184 Remove parser tokens DECODE_MARIADB_SYM and DECODE_ORACLE_SYM
|
||||
#
|
||||
|
||||
@@ -2314,7 +2314,7 @@ DROP TABLE t1,t2;
|
||||
--echo # MDEV-18205 Assertion `str_length < len' failed in Binary_string::realloc_raw
|
||||
--echo #
|
||||
|
||||
SELECT GROUP_CONCAT( UpdateXML( '<a>new year</a>', '/a', '2019-01-01 00:00:00' ), ENCODE('text','pass') ) AS f;
|
||||
SELECT GROUP_CONCAT( UpdateXML( '<a>new year</a>', '/a', '<z>2019-01-01 00:00:00</z>' ), ENCODE('text','pass') ) AS f;
|
||||
|
||||
|
||||
--echo #
|
||||
|
||||
@@ -236,7 +236,9 @@ select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"');
|
||||
#
|
||||
select updatexml('<div><div><span>1</span><span>2</span></div></div>',
|
||||
'/','<tr><td>1</td><td>2</td></tr>') as upd1;
|
||||
--disable_warnings
|
||||
select updatexml('', '/', '') as upd2;
|
||||
--enable_warnings
|
||||
|
||||
#
|
||||
# Bug#16234 XML: Crash if ExtractValue()
|
||||
@@ -707,7 +709,9 @@ SELECT UPDATEXML(CONVERT('' USING swe7), TRUNCATE('',1), 0);
|
||||
--echo #
|
||||
--echo # Bug#12375190: UPDATEXML CRASHES ON SIMPLE INPUTS
|
||||
--echo #
|
||||
--disable_warnings
|
||||
SELECT UPDATEXML('','(a)/a','');
|
||||
--enable_warnings
|
||||
SELECT UPDATEXML('<a><a>x</a></a>','(a)/a','<b />');
|
||||
SELECT UPDATEXML('<a><c><a>x</a></c></a>','(a)/a','<b />');
|
||||
SELECT UPDATEXML('<a><c><a>x</a></c></a>','(a)//a','<b />');
|
||||
|
||||
@@ -134,10 +134,10 @@ t1 CREATE TABLE `t1` (
|
||||
`x` xmltype DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
|
||||
DROP TABLE t1;
|
||||
CREATE FUNCTION xmi(id int) RETURNS xmltype RETURN 'aaa';
|
||||
CREATE FUNCTION xmi(id int) RETURNS xmltype RETURN '<a></a>';
|
||||
SELECT xmi(1);
|
||||
xmi(1)
|
||||
aaa
|
||||
<a></a>
|
||||
CREATE TABLE t1 SELECT xmi(10) as x;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
@@ -226,4 +226,29 @@ t1 CREATE TABLE `t1` (
|
||||
`x` xmltype CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a XMLTYPE);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
ERROR HY000: Cannot cast 'int' as 'xmltype' in assignment of `test`.`t1`.`a`
|
||||
INSERT INTO t1 VALUES(11.2);
|
||||
ERROR HY000: Cannot cast 'decimal' as 'xmltype' in assignment of `test`.`t1`.`a`
|
||||
INSERT INTO t1 VALUES(11e-2);
|
||||
ERROR HY000: Cannot cast 'double' as 'xmltype' in assignment of `test`.`t1`.`a`
|
||||
INSERT INTO t1 VALUES("one");
|
||||
ERROR 22007: Incorrect XML value: 'one'
|
||||
INSERT INTO t1 VALUES("<a><b></b>");
|
||||
ERROR 22007: Incorrect XML value: '<a><b></b>'
|
||||
INSERT INTO t1 VALUES("<a><b></b></a>");
|
||||
INSERT INTO t1 VALUES("<to>JOHN</to><from></from>");
|
||||
ERROR 22007: Incorrect XML value: '<to>JOHN</to><from></from>'
|
||||
INSERT INTO t1 VALUES('<note><to>JOHN</to><from></from></note>');
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <note><to>JOHN</to><from></from></note>');
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <?xml?> <note><to>JOHN</to><from></from></note>');
|
||||
ERROR 22007: Incorrect XML value: '<?xml version="1.0" ?> <?xml?> <note><to>JOHN</to><from></from></note>'
|
||||
INSERT INTO t1 VALUES('<note><to>JOHN</to><from></from></note> <?xml version="1.0" ?> ');
|
||||
ERROR 22007: Incorrect XML value: '<note><to>JOHN</to><from></from></note> <?xml version="1.0" ?> '
|
||||
INSERT INTO t1 VALUES('<?somePI pi content ?> <?xml version="1.0" ?> <note><from>Lisa</from></note>');
|
||||
ERROR 22007: Incorrect XML value: '<?somePI pi content ?> <?xml version="1.0" ?> <note><from>Lisa</from></note>'
|
||||
INSERT INTO t1 VALUES('<?somePI pi content ?> <note><from>Lisa</from></note>');
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <note><?somePI pi content ?><from>Lisa</from></note>');
|
||||
DROP TABLE t1;
|
||||
# End of 11.8 tests
|
||||
|
||||
@@ -81,7 +81,7 @@ ALTER TABLE t1 ADD COLUMN x xmltype;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE FUNCTION xmi(id int) RETURNS xmltype RETURN 'aaa';
|
||||
CREATE FUNCTION xmi(id int) RETURNS xmltype RETURN '<a></a>';
|
||||
|
||||
SELECT xmi(1);
|
||||
CREATE TABLE t1 SELECT xmi(10) as x;
|
||||
@@ -155,5 +155,36 @@ CREATE TABLE t1 AS SELECT UpdateXML('<a><b>ccc</b><d></d></a>', '/a', '<e>fff</e
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1(a XMLTYPE);
|
||||
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
|
||||
INSERT INTO t1 VALUES(1);
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
|
||||
INSERT INTO t1 VALUES(11.2);
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
|
||||
INSERT INTO t1 VALUES(11e-2);
|
||||
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES("one");
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES("<a><b></b>");
|
||||
|
||||
INSERT INTO t1 VALUES("<a><b></b></a>");
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES("<to>JOHN</to><from></from>");
|
||||
|
||||
INSERT INTO t1 VALUES('<note><to>JOHN</to><from></from></note>');
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <note><to>JOHN</to><from></from></note>');
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <?xml?> <note><to>JOHN</to><from></from></note>');
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES('<note><to>JOHN</to><from></from></note> <?xml version="1.0" ?> ');
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
INSERT INTO t1 VALUES('<?somePI pi content ?> <?xml version="1.0" ?> <note><from>Lisa</from></note>');
|
||||
INSERT INTO t1 VALUES('<?somePI pi content ?> <note><from>Lisa</from></note>');
|
||||
INSERT INTO t1 VALUES('<?xml version="1.0" ?> <note><?somePI pi content ?><from>Lisa</from></note>');
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo # End of 11.8 tests
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define MYSQL_SERVER
|
||||
#include "mariadb.h"
|
||||
#include "my_xml.h"
|
||||
#include "sql_class.h"
|
||||
#include "sql_lex.h"
|
||||
#include "sql_type_xmltype.h"
|
||||
@@ -186,6 +187,36 @@ int Field_xmltype::report_wrong_value(const ErrConv &val)
|
||||
}
|
||||
|
||||
|
||||
static int check_parse_xml(const char *xml, size_t length, CHARSET_INFO *cs)
|
||||
{
|
||||
MY_XML_PARSER p;
|
||||
|
||||
/* Prepare XML parser */
|
||||
my_xml_parser_create(&p);
|
||||
p.flags= MY_XML_FLAG_RELATIVE_NAMES |
|
||||
MY_XML_FLAG_SKIP_TEXT_NORMALIZATION |
|
||||
MY_XML_FLAG_ASSERT_WELL_FORMED;
|
||||
|
||||
return my_xml_parse(&p, xml, length);
|
||||
}
|
||||
|
||||
|
||||
int Field_xmltype::store(const char *from, size_t length, CHARSET_INFO *cs)
|
||||
{
|
||||
if (length < 4 ||
|
||||
check_parse_xml(from, length, cs) != MY_XML_OK)
|
||||
goto err;
|
||||
|
||||
|
||||
return Field_blob::store(from, length, cs);
|
||||
|
||||
err:
|
||||
get_thd()->push_warning_wrong_value(
|
||||
Sql_condition::WARN_LEVEL_WARN, "XML", from);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
class Item_xmltype_typecast_func_handler: public Item_handled_func::Handler_str
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -117,6 +117,8 @@ public:
|
||||
|
||||
void sql_type(String &str) const override;
|
||||
uint size_of() const override { return sizeof(*this); }
|
||||
int store(const char *to, size_t length, CHARSET_INFO *charset) override;
|
||||
using Field_str::store;
|
||||
};
|
||||
|
||||
|
||||
|
||||
210
strings/xml.c
210
strings/xml.c
@@ -30,9 +30,9 @@
|
||||
#define MY_XML_SLASH '/'
|
||||
#define MY_XML_COMMENT 'C'
|
||||
#define MY_XML_TEXT 'T'
|
||||
#define MY_XML_QUESTION '?'
|
||||
#define MY_XML_EXCLAM '!'
|
||||
#define MY_XML_CDATA 'D'
|
||||
#define MY_XML_PROCESSING_INSTRUCTION '?'
|
||||
#define MY_XML_CDATA 'A'
|
||||
#define MY_XML_DTD 'D'
|
||||
|
||||
typedef struct xml_attr_st
|
||||
{
|
||||
@@ -95,8 +95,8 @@ static const char *lex2str(int lex)
|
||||
case MY_XML_SLASH: return "'/'";
|
||||
case MY_XML_COMMENT: return "COMMENT";
|
||||
case MY_XML_TEXT: return "TEXT";
|
||||
case MY_XML_QUESTION: return "'?'";
|
||||
case MY_XML_EXCLAM: return "'!'";
|
||||
case MY_XML_PROCESSING_INSTRUCTION: return "'?'";
|
||||
case MY_XML_DTD: return "DTD";
|
||||
}
|
||||
return "unknown token";
|
||||
}
|
||||
@@ -145,6 +145,43 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a)
|
||||
a->end=p->cur;
|
||||
lex=MY_XML_COMMENT;
|
||||
}
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<?")))
|
||||
{
|
||||
lex= MY_XML_UNKNOWN;
|
||||
p->cur+= 2;
|
||||
|
||||
a->beg= p->cur;
|
||||
if (my_xml_is_id0(p->cur[0]))
|
||||
{
|
||||
int termination_expected= FALSE;
|
||||
|
||||
p->cur++;
|
||||
while (p->cur < p->end && my_xml_is_id1(p->cur[0]))
|
||||
p->cur++;
|
||||
|
||||
a->end=p->cur;
|
||||
/*
|
||||
After the target name the syntax requires the
|
||||
terminating '?>' or some spaces then an
|
||||
arbitrary string to the '>?'.
|
||||
*/
|
||||
if (p->cur < p->end && !my_xml_is_space(p->cur[0]))
|
||||
termination_expected= TRUE;
|
||||
|
||||
while (p->cur < p->end)
|
||||
{
|
||||
if (my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("?>")) == 0)
|
||||
{
|
||||
lex= MY_XML_PROCESSING_INSTRUCTION;
|
||||
p->cur+= 2;
|
||||
break;
|
||||
}
|
||||
else if (termination_expected)
|
||||
break;
|
||||
p->cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<![CDATA[")))
|
||||
{
|
||||
p->cur+= 9;
|
||||
@@ -159,7 +196,56 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a)
|
||||
}
|
||||
lex= MY_XML_CDATA;
|
||||
}
|
||||
else if (strchr("?=/<>!",p->cur[0]))
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<!DOCTYPE")))
|
||||
{
|
||||
/* skip <!DOCTYPE part. TODO: add parser for the DTD */
|
||||
int in_quote= 0;
|
||||
int level= 1;
|
||||
|
||||
p->cur+= 9;
|
||||
lex= MY_XML_UNKNOWN;
|
||||
for (; p->cur < p->end; p->cur++)
|
||||
{
|
||||
if (p->cur[0] == '"' || p->cur[0] == '\'')
|
||||
{
|
||||
if (!in_quote)
|
||||
in_quote= p->cur[0];
|
||||
else
|
||||
{
|
||||
if (p->cur[0] == in_quote)
|
||||
in_quote= 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_quote)
|
||||
continue;
|
||||
|
||||
switch (p->cur[0])
|
||||
{
|
||||
case MY_XML_LT:
|
||||
{
|
||||
level++;
|
||||
break;
|
||||
}
|
||||
case MY_XML_GT:
|
||||
{
|
||||
level--;
|
||||
if (level == 0)
|
||||
{
|
||||
lex= MY_XML_DTD;
|
||||
p->cur++;
|
||||
goto dtd_end;
|
||||
}
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
dtd_end:
|
||||
a->end= p->cur;
|
||||
}
|
||||
|
||||
else if (strchr("=/<>",p->cur[0]))
|
||||
{
|
||||
p->cur++;
|
||||
a->end=p->cur;
|
||||
@@ -205,6 +291,20 @@ ret:
|
||||
|
||||
static int my_xml_value(MY_XML_PARSER *st, const char *str, size_t len)
|
||||
{
|
||||
if ((st->flags & MY_XML_FLAG_ASSERT_WELL_FORMED) &&
|
||||
st->attr.end == st->attr.start)
|
||||
{
|
||||
/*
|
||||
Values are not allowed on the root level of XML.
|
||||
Though spaces are ok.
|
||||
*/
|
||||
while (len > 0)
|
||||
{
|
||||
if (!my_xml_is_space(str[--len]))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
return MY_XML_OK;
|
||||
}
|
||||
return (st->value) ? (st->value)(st,str,len) : MY_XML_OK;
|
||||
}
|
||||
|
||||
@@ -266,6 +366,14 @@ static int my_xml_enter(MY_XML_PARSER *st, const char *str, size_t len)
|
||||
st->attr.end[0]= '/';
|
||||
st->attr.end++;
|
||||
}
|
||||
else if ((st->flags & MY_XML_FLAG_ASSERT_WELL_FORMED) &&
|
||||
st->current_node_type == MY_XML_NODE_TAG)
|
||||
{
|
||||
/* level 0 nesting of the XML document .*/
|
||||
if (st->root_node_counter++)
|
||||
return MY_XML_ERROR; /* no multiple root nodes allowed. */
|
||||
st->item_counter++;
|
||||
}
|
||||
memcpy(st->attr.end, str, len);
|
||||
st->attr.end+= len;
|
||||
st->attr.end[0]= '\0';
|
||||
@@ -340,19 +448,46 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
if (p->cur[0] == '<')
|
||||
{
|
||||
int lex;
|
||||
int question=0;
|
||||
int exclam=0;
|
||||
|
||||
lex=my_xml_scan(p,&a);
|
||||
|
||||
if (MY_XML_COMMENT == lex)
|
||||
if (MY_XML_COMMENT == lex ||
|
||||
MY_XML_DTD == lex)
|
||||
{
|
||||
p->item_counter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MY_XML_PROCESSING_INSTRUCTION == lex)
|
||||
{
|
||||
size_t tag_len= (size_t) (a.end - a.beg);
|
||||
if ((p->flags & MY_XML_FLAG_ASSERT_WELL_FORMED) &&
|
||||
tag_len == 3 && memcmp(a.beg, "xml", 3) == 0)
|
||||
{
|
||||
/*
|
||||
The <?xml ..?> processing instruction has special meaning.
|
||||
If appears it must be first line of the XML document.
|
||||
*/
|
||||
if (p->item_counter)
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
|
||||
p->item_counter++;
|
||||
|
||||
if (p->processing_instruction &&
|
||||
MY_XML_OK != p->processing_instruction(p,
|
||||
a.beg, (size_t) (a.end-a.beg),
|
||||
a.end, (size_t) (p->cur - a.end - 2)))
|
||||
return MY_XML_ERROR;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lex == MY_XML_CDATA)
|
||||
{
|
||||
a.beg+= 9;
|
||||
a.end-= 3;
|
||||
my_xml_value(p, a.beg, (size_t) (a.end-a.beg));
|
||||
if (MY_XML_OK != my_xml_value(p, a.beg, (size_t) (a.end-a.beg)))
|
||||
return MY_XML_ERROR;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -371,16 +506,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
goto gt;
|
||||
}
|
||||
|
||||
if (MY_XML_EXCLAM == lex)
|
||||
{
|
||||
lex=my_xml_scan(p,&a);
|
||||
exclam=1;
|
||||
}
|
||||
else if (MY_XML_QUESTION == lex)
|
||||
{
|
||||
lex=my_xml_scan(p,&a);
|
||||
question=1;
|
||||
}
|
||||
|
||||
if (MY_XML_IDENT == lex)
|
||||
{
|
||||
@@ -395,8 +520,7 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
|
||||
while ((MY_XML_IDENT == (lex=my_xml_scan(p,&a))) ||
|
||||
((MY_XML_STRING == lex && exclam)))
|
||||
while (MY_XML_IDENT == (lex=my_xml_scan(p,&a)))
|
||||
{
|
||||
MY_XML_ATTR b;
|
||||
if (MY_XML_EQ == (lex=my_xml_scan(p,&b)))
|
||||
@@ -424,15 +548,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
(MY_XML_OK != my_xml_leave(p,a.beg,(size_t) (a.end-a.beg))))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
else if ((MY_XML_STRING == lex) && exclam)
|
||||
{
|
||||
/*
|
||||
We are in <!DOCTYPE>, e.g.
|
||||
<!DOCTYPE name SYSTEM "SystemLiteral">
|
||||
<!DOCTYPE name PUBLIC "PublicLiteral" "SystemLiteral">
|
||||
Just skip "SystemLiteral" and "PublicidLiteral"
|
||||
*/
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -445,24 +560,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
}
|
||||
|
||||
gt:
|
||||
if (question)
|
||||
{
|
||||
if (lex != MY_XML_QUESTION)
|
||||
{
|
||||
snprintf(p->errstr,sizeof(p->errstr),"%s unexpected ('?' wanted)",lex2str(lex));
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
if (MY_XML_OK != my_xml_leave(p,NULL,0))
|
||||
return MY_XML_ERROR;
|
||||
lex=my_xml_scan(p,&a);
|
||||
}
|
||||
|
||||
if (exclam)
|
||||
{
|
||||
if (MY_XML_OK != my_xml_leave(p,NULL,0))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
|
||||
if (lex != MY_XML_GT)
|
||||
{
|
||||
snprintf(p->errstr,sizeof(p->errstr),"%s unexpected ('>' wanted)",lex2str(lex));
|
||||
@@ -479,12 +576,15 @@ gt:
|
||||
my_xml_norm_text(&a);
|
||||
if (a.beg != a.end)
|
||||
{
|
||||
my_xml_value(p,a.beg,(size_t) (a.end-a.beg));
|
||||
if (MY_XML_OK != my_xml_value(p, a.beg, (size_t) (a.end-a.beg)))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p->attr.start[0])
|
||||
if (p->attr.start[0] ||
|
||||
((p->flags & MY_XML_FLAG_ASSERT_WELL_FORMED) &&
|
||||
p->root_node_counter == 0))
|
||||
{
|
||||
snprintf(p->errstr,sizeof(p->errstr),"unexpected END-OF-INPUT");
|
||||
return MY_XML_ERROR;
|
||||
@@ -537,6 +637,14 @@ void my_xml_set_leave_handler(MY_XML_PARSER *p,
|
||||
}
|
||||
|
||||
|
||||
void my_xml_set_processing_instruction_handler(MY_XML_PARSER *p,
|
||||
int (*p_i)(MY_XML_PARSER *, const char *, size_t,
|
||||
const char *, size_t))
|
||||
{
|
||||
p->processing_instruction= p_i;
|
||||
}
|
||||
|
||||
|
||||
void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data)
|
||||
{
|
||||
p->user_data=user_data;
|
||||
|
||||
Reference in New Issue
Block a user