Added proper parse errors with description, parsed offsets and stuff
git-svn-id: http://pugixml.googlecode.com/svn/trunk@111 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
0949bd80b6
commit
600c3814e9
199
src/pugixml.cpp
199
src/pugixml.cpp
@ -834,6 +834,14 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline xml_parse_result make_parse_result(xml_parse_status status, unsigned int offset, unsigned int line)
|
||||||
|
{
|
||||||
|
xml_parse_result result = {status, offset, line};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAKE_PARSE_RESULT(status) make_parse_result(status, 0, __LINE__)
|
||||||
|
|
||||||
struct xml_parser
|
struct xml_parser
|
||||||
{
|
{
|
||||||
xml_allocator& alloc;
|
xml_allocator& alloc;
|
||||||
@ -846,15 +854,18 @@ namespace
|
|||||||
#define SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
|
#define SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
|
||||||
#define SCANWHILE(X) { while ((X)) ++s; }
|
#define SCANWHILE(X) { while ((X)) ++s; }
|
||||||
#define ENDSEG() { ch = *s; *s = 0; ++s; }
|
#define ENDSEG() { ch = *s; *s = 0; ++s; }
|
||||||
#define CHECK_ERROR() { if (*s == 0) return false; }
|
#define ERROR(err, m) make_parse_result(err, static_cast<unsigned int>(m - buffer_start), __LINE__)
|
||||||
|
#define CHECK_ERROR(err, m) { if (*s == 0) return ERROR(err, m); }
|
||||||
|
|
||||||
xml_parser(xml_allocator& alloc): alloc(alloc)
|
xml_parser(xml_allocator& alloc): alloc(alloc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(char* s, xml_node_struct* xmldoc, unsigned int optmsk = parse_default)
|
xml_parse_result parse(char* s, xml_node_struct* xmldoc, unsigned int optmsk = parse_default)
|
||||||
{
|
{
|
||||||
if (!s || !xmldoc) return false;
|
if (!s || !xmldoc) return MAKE_PARSE_RESULT(status_internal_error);
|
||||||
|
|
||||||
|
char* buffer_start = s;
|
||||||
|
|
||||||
// UTF-8 BOM
|
// UTF-8 BOM
|
||||||
if ((unsigned char)*s == 0xEF && (unsigned char)*(s+1) == 0xBB && (unsigned char)*(s+2) == 0xBF)
|
if ((unsigned char)*s == 0xEF && (unsigned char)*(s+1) == 0xBB && (unsigned char)*(s+2) == 0xBF)
|
||||||
@ -876,22 +887,22 @@ namespace
|
|||||||
++s;
|
++s;
|
||||||
|
|
||||||
if (!is_chartype(*s, ct_start_symbol)) // bad PI
|
if (!is_chartype(*s, ct_start_symbol)) // bad PI
|
||||||
return false;
|
return ERROR(status_bad_pi, s);
|
||||||
else if (OPTSET(parse_pi) || OPTSET(parse_declaration))
|
else if (OPTSET(parse_pi) || OPTSET(parse_declaration))
|
||||||
{
|
{
|
||||||
mark = s;
|
mark = s;
|
||||||
SCANWHILE(is_chartype(*s, ct_symbol)); // Read PI target
|
SCANWHILE(is_chartype(*s, ct_symbol)); // Read PI target
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
if (!is_chartype(*s, ct_space) && *s != '?') // Target has to end with space or ?
|
if (!is_chartype(*s, ct_space) && *s != '?') // Target has to end with space or ?
|
||||||
return false;
|
return ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
ENDSEG();
|
ENDSEG();
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
if (ch == '?') // nothing except target present
|
if (ch == '?') // nothing except target present
|
||||||
{
|
{
|
||||||
if (*s != '>') return false;
|
if (*s != '>') return ERROR(status_bad_pi, s);
|
||||||
++s;
|
++s;
|
||||||
|
|
||||||
// stricmp / strcasecmp is not portable
|
// stricmp / strcasecmp is not portable
|
||||||
@ -930,7 +941,7 @@ namespace
|
|||||||
mark = s;
|
mark = s;
|
||||||
|
|
||||||
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
// replace ending ? with / to terminate properly
|
// replace ending ? with / to terminate properly
|
||||||
*s = '/';
|
*s = '/';
|
||||||
@ -953,17 +964,17 @@ namespace
|
|||||||
if (is_chartype(ch, ct_space))
|
if (is_chartype(ch, ct_space))
|
||||||
{
|
{
|
||||||
SKIPWS();
|
SKIPWS();
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
mark = s;
|
mark = s;
|
||||||
}
|
}
|
||||||
else mark = 0;
|
else mark = 0;
|
||||||
|
|
||||||
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
ENDSEG();
|
ENDSEG();
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
++s; // Step over >
|
++s; // Step over >
|
||||||
|
|
||||||
@ -978,7 +989,7 @@ namespace
|
|||||||
else // not parsing PI
|
else // not parsing PI
|
||||||
{
|
{
|
||||||
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
SCANFOR(*s == '?' && *(s+1) == '>'); // Look for '?>'.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_pi, s);
|
||||||
|
|
||||||
s += 2;
|
s += 2;
|
||||||
}
|
}
|
||||||
@ -1005,13 +1016,13 @@ namespace
|
|||||||
{
|
{
|
||||||
s = strconv_comment(s);
|
s = strconv_comment(s);
|
||||||
|
|
||||||
if (!s) return false;
|
if (!s) return ERROR(status_bad_comment, cursor->value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Scan for terminating '-->'.
|
// Scan for terminating '-->'.
|
||||||
SCANFOR(*s == '-' && *(s+1) == '-' && *(s+2) == '>');
|
SCANFOR(*s == '-' && *(s+1) == '-' && *(s+2) == '>');
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_comment, s);
|
||||||
|
|
||||||
if (OPTSET(parse_comments))
|
if (OPTSET(parse_comments))
|
||||||
*s = 0; // Zero-terminate this segment at the first terminating '-'.
|
*s = 0; // Zero-terminate this segment at the first terminating '-'.
|
||||||
@ -1024,12 +1035,12 @@ namespace
|
|||||||
POPNODE(); // Pop since this is a standalone.
|
POPNODE(); // Pop since this is a standalone.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_comment, s);
|
||||||
}
|
}
|
||||||
else if(*s == '[')
|
else if (*s == '[')
|
||||||
{
|
{
|
||||||
// '<![CDATA[...'
|
// '<![CDATA[...'
|
||||||
if(*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
|
if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
|
|
||||||
@ -1042,16 +1053,16 @@ namespace
|
|||||||
{
|
{
|
||||||
s = strconv_cdata(s);
|
s = strconv_cdata(s);
|
||||||
|
|
||||||
if (!s) return false;
|
if (!s) return ERROR(status_bad_cdata, cursor->value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Scan for terminating ']]>'.
|
// Scan for terminating ']]>'.
|
||||||
SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
|
SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_cdata, s);
|
||||||
|
|
||||||
ENDSEG(); // Zero-terminate this segment.
|
ENDSEG(); // Zero-terminate this segment.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_cdata, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
POPNODE(); // Pop since this is a standalone.
|
POPNODE(); // Pop since this is a standalone.
|
||||||
@ -1060,31 +1071,31 @@ namespace
|
|||||||
{
|
{
|
||||||
// Scan for terminating ']]>'.
|
// Scan for terminating ']]>'.
|
||||||
SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
|
SCANFOR(*s == ']' && *(s+1) == ']' && *(s+2) == '>');
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_cdata, s);
|
||||||
|
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
|
|
||||||
s += 2; // Step over the last ']>'.
|
s += 2; // Step over the last ']>'.
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_cdata, s);
|
||||||
}
|
}
|
||||||
else if (*s=='D' && *++s=='O' && *++s=='C' && *++s=='T' && *++s=='Y' && *++s=='P' && *++s=='E')
|
else if (*s=='D' && *++s=='O' && *++s=='C' && *++s=='T' && *++s=='Y' && *++s=='P' && *++s=='E')
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
|
|
||||||
SKIPWS(); // Eat any whitespace.
|
SKIPWS(); // Eat any whitespace.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_doctype, s);
|
||||||
|
|
||||||
LOC_DOCTYPE:
|
LOC_DOCTYPE:
|
||||||
SCANFOR(*s == '\'' || *s == '"' || *s == '[' || *s == '>');
|
SCANFOR(*s == '\'' || *s == '"' || *s == '[' || *s == '>');
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_doctype, s);
|
||||||
|
|
||||||
if (*s == '\'' || *s == '"') // '...SYSTEM "..."
|
if (*s == '\'' || *s == '"') // '...SYSTEM "..."
|
||||||
{
|
{
|
||||||
ch = *s++;
|
ch = *s++;
|
||||||
SCANFOR(*s == ch);
|
SCANFOR(*s == ch);
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_doctype, s);
|
||||||
|
|
||||||
++s;
|
++s;
|
||||||
goto LOC_DOCTYPE;
|
goto LOC_DOCTYPE;
|
||||||
@ -1104,11 +1115,11 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
SCANFOR(*s == '>');
|
SCANFOR(*s == '>');
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_doctype, s);
|
||||||
|
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_unrecognized_tag, s);
|
||||||
}
|
}
|
||||||
else if (is_chartype(*s, ct_start_symbol)) // '<#...'
|
else if (is_chartype(*s, ct_start_symbol)) // '<#...'
|
||||||
{
|
{
|
||||||
@ -1117,14 +1128,14 @@ namespace
|
|||||||
cursor->name = s;
|
cursor->name = s;
|
||||||
|
|
||||||
SCANWHILE(is_chartype(*s, ct_symbol)); // Scan for a terminator.
|
SCANWHILE(is_chartype(*s, ct_symbol)); // Scan for a terminator.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_start_element, s);
|
||||||
|
|
||||||
ENDSEG(); // Save char in 'ch', terminate & step over.
|
ENDSEG(); // Save char in 'ch', terminate & step over.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_start_element, s);
|
||||||
|
|
||||||
if (ch == '/') // '<#.../'
|
if (ch == '/') // '<#.../'
|
||||||
{
|
{
|
||||||
if (*s != '>') return false;
|
if (*s != '>') return ERROR(status_bad_start_element, s);
|
||||||
|
|
||||||
POPNODE(); // Pop.
|
POPNODE(); // Pop.
|
||||||
|
|
||||||
@ -1137,10 +1148,10 @@ namespace
|
|||||||
else if (is_chartype(ch, ct_space))
|
else if (is_chartype(ch, ct_space))
|
||||||
{
|
{
|
||||||
LOC_ATTRIBUTES:
|
LOC_ATTRIBUTES:
|
||||||
while (*s)
|
while (true)
|
||||||
{
|
{
|
||||||
SKIPWS(); // Eat any whitespace.
|
SKIPWS(); // Eat any whitespace.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_start_element, s);
|
||||||
|
|
||||||
if (is_chartype(*s, ct_start_symbol)) // <... #...
|
if (is_chartype(*s, ct_start_symbol)) // <... #...
|
||||||
{
|
{
|
||||||
@ -1148,15 +1159,15 @@ namespace
|
|||||||
a->name = s; // Save the offset.
|
a->name = s; // Save the offset.
|
||||||
|
|
||||||
SCANWHILE(is_chartype(*s, ct_symbol)); // Scan for a terminator.
|
SCANWHILE(is_chartype(*s, ct_symbol)); // Scan for a terminator.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_attribute, s);
|
||||||
|
|
||||||
ENDSEG(); // Save char in 'ch', terminate & step over.
|
ENDSEG(); // Save char in 'ch', terminate & step over.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_attribute, s);
|
||||||
|
|
||||||
if (is_chartype(ch, ct_space))
|
if (is_chartype(ch, ct_space))
|
||||||
{
|
{
|
||||||
SKIPWS(); // Eat any whitespace.
|
SKIPWS(); // Eat any whitespace.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_attribute, s);
|
||||||
|
|
||||||
ch = *s;
|
ch = *s;
|
||||||
++s;
|
++s;
|
||||||
@ -1165,7 +1176,7 @@ namespace
|
|||||||
if (ch == '=') // '<... #=...'
|
if (ch == '=') // '<... #=...'
|
||||||
{
|
{
|
||||||
SKIPWS(); // Eat any whitespace.
|
SKIPWS(); // Eat any whitespace.
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_attribute, s);
|
||||||
|
|
||||||
if (*s == '\'' || *s == '"') // '<... #="...'
|
if (*s == '\'' || *s == '"') // '<... #="...'
|
||||||
{
|
{
|
||||||
@ -1175,22 +1186,24 @@ namespace
|
|||||||
|
|
||||||
s = strconv_attribute(s, ch, optmsk);
|
s = strconv_attribute(s, ch, optmsk);
|
||||||
|
|
||||||
if (!s) return false;
|
if (!s) return ERROR(status_bad_attribute, a->value);
|
||||||
|
|
||||||
// After this line the loop continues from the start;
|
// After this line the loop continues from the start;
|
||||||
// Whitespaces, / and > are ok, symbols are wrong,
|
// Whitespaces, / and > are ok, symbols and EOF are wrong,
|
||||||
// everything else will be detected
|
// everything else will be detected
|
||||||
if (is_chartype(*s, ct_start_symbol)) return false;
|
if (is_chartype(*s, ct_start_symbol)) return ERROR(status_bad_attribute, s);
|
||||||
|
|
||||||
|
CHECK_ERROR(status_bad_start_element, s);
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_attribute, s);
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_attribute, s);
|
||||||
}
|
}
|
||||||
else if (*s == '/')
|
else if (*s == '/')
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
|
|
||||||
if (*s != '>') return false;
|
if (*s != '>') return ERROR(status_bad_start_element, s);
|
||||||
|
|
||||||
POPNODE(); // Pop.
|
POPNODE(); // Pop.
|
||||||
|
|
||||||
@ -1204,36 +1217,38 @@ namespace
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_start_element, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !!!
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_bad_start_element, s);
|
||||||
}
|
}
|
||||||
else if (*s == '/')
|
else if (*s == '/')
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
|
|
||||||
if (!cursor) return false;
|
if (!cursor) return ERROR(status_bad_end_element, s);
|
||||||
|
|
||||||
char* name = cursor->name;
|
char* name = cursor->name;
|
||||||
if (!name) return false;
|
if (!name) return ERROR(status_end_element_mismatch, s);
|
||||||
|
|
||||||
while (*s && is_chartype(*s, ct_symbol))
|
while (*s && is_chartype(*s, ct_symbol))
|
||||||
{
|
{
|
||||||
if (*s++ != *name++) return false;
|
if (*s++ != *name++) return ERROR(status_end_element_mismatch, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*name) return false;
|
if (*name) return ERROR(status_end_element_mismatch, s);
|
||||||
|
|
||||||
POPNODE(); // Pop.
|
POPNODE(); // Pop.
|
||||||
|
|
||||||
SKIPWS();
|
SKIPWS();
|
||||||
CHECK_ERROR();
|
CHECK_ERROR(status_bad_end_element, s);
|
||||||
|
|
||||||
if (*s != '>') return false;
|
if (*s != '>') return ERROR(status_bad_end_element, s);
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
else return false;
|
else return ERROR(status_unrecognized_tag, s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1255,7 +1270,7 @@ namespace
|
|||||||
|
|
||||||
s = strconv_pcdata(s, optmsk);
|
s = strconv_pcdata(s, optmsk);
|
||||||
|
|
||||||
if (!s) return false;
|
if (!s) return ERROR(status_bad_pcdata, cursor->value);
|
||||||
|
|
||||||
POPNODE(); // Pop since this is a standalone.
|
POPNODE(); // Pop since this is a standalone.
|
||||||
|
|
||||||
@ -1274,9 +1289,9 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor != xmldoc) return false;
|
if (cursor != xmldoc) return ERROR(status_end_element_mismatch, s);
|
||||||
|
|
||||||
return true;
|
return ERROR(status_ok, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -2595,7 +2610,7 @@ namespace pugi
|
|||||||
return empty() ? 0 : _root->document_order;
|
return empty() ? 0 : _root->document_order;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xml_node::precompute_document_order_impl(unsigned int mask)
|
void xml_node::precompute_document_order_impl()
|
||||||
{
|
{
|
||||||
if (type() != node_document) return;
|
if (type() != node_document) return;
|
||||||
|
|
||||||
@ -2604,10 +2619,10 @@ namespace pugi
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
cur._root->document_order = mask & current++;
|
cur._root->document_order = current++;
|
||||||
|
|
||||||
for (xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
|
for (xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
|
||||||
a._attr->document_order = mask & current++;
|
a._attr->document_order = current++;
|
||||||
|
|
||||||
if (cur.first_child())
|
if (cur.first_child())
|
||||||
cur = cur.first_child();
|
cur = cur.first_child();
|
||||||
@ -2649,13 +2664,13 @@ namespace pugi
|
|||||||
|
|
||||||
case node_element:
|
case node_element:
|
||||||
case node_declaration:
|
case node_declaration:
|
||||||
return _root->name_insitu ? _root->name - buffer : -1;
|
return _root->name_insitu ? static_cast<int>(_root->name - buffer) : -1;
|
||||||
|
|
||||||
case node_pcdata:
|
case node_pcdata:
|
||||||
case node_cdata:
|
case node_cdata:
|
||||||
case node_comment:
|
case node_comment:
|
||||||
case node_pi:
|
case node_pi:
|
||||||
return _root->value_insitu ? _root->value - buffer : -1;
|
return _root->value_insitu ? static_cast<int>(_root->value - buffer) : -1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@ -2806,6 +2821,33 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* xml_parse_result::description() const
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case status_ok: return "No error";
|
||||||
|
|
||||||
|
case status_file_not_found: return "File was not found";
|
||||||
|
case status_io_error: return "Error reading from file/stream";
|
||||||
|
case status_out_of_memory: return "Could not allocate memory";
|
||||||
|
case status_internal_error: return "Internal error occured";
|
||||||
|
|
||||||
|
case status_unrecognized_tag: return "Could not determine tag type";
|
||||||
|
|
||||||
|
case status_bad_pi: return "Error parsing document declaration/processing instruction";
|
||||||
|
case status_bad_comment: return "Error parsing comment";
|
||||||
|
case status_bad_cdata: return "Error parsing CDATA section";
|
||||||
|
case status_bad_doctype: return "Error parsing document type declaration";
|
||||||
|
case status_bad_pcdata: return "Error parsing PCDATA section";
|
||||||
|
case status_bad_start_element: return "Error parsing start element tag";
|
||||||
|
case status_bad_attribute: return "Error parsing element attribute";
|
||||||
|
case status_bad_end_element: return "Error parsing end element tag";
|
||||||
|
case status_end_element_mismatch: return "Start-end tags mismatch";
|
||||||
|
|
||||||
|
default: return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
xml_document::xml_document(): _buffer(0)
|
xml_document::xml_document(): _buffer(0)
|
||||||
{
|
{
|
||||||
create();
|
create();
|
||||||
@ -2848,28 +2890,28 @@ namespace pugi
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PUGIXML_NO_STL
|
#ifndef PUGIXML_NO_STL
|
||||||
bool xml_document::load(std::istream& stream, unsigned int options)
|
xml_parse_result xml_document::load(std::istream& stream, unsigned int options)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
if (!stream.good()) return false;
|
if (!stream.good()) return MAKE_PARSE_RESULT(status_io_error);
|
||||||
|
|
||||||
std::streamoff length, pos = stream.tellg();
|
std::streamoff length, pos = stream.tellg();
|
||||||
stream.seekg(0, std::ios::end);
|
stream.seekg(0, std::ios::end);
|
||||||
length = stream.tellg();
|
length = stream.tellg();
|
||||||
stream.seekg(pos, std::ios::beg);
|
stream.seekg(pos, std::ios::beg);
|
||||||
|
|
||||||
if (!stream.good()) return false;
|
if (!stream.good()) return MAKE_PARSE_RESULT(status_io_error);
|
||||||
|
|
||||||
char* s = static_cast<char*>(global_allocate(length + 1));
|
char* s = static_cast<char*>(global_allocate(length + 1));
|
||||||
if (!s) return false;
|
if (!s) return MAKE_PARSE_RESULT(status_out_of_memory);
|
||||||
|
|
||||||
stream.read(s, length);
|
stream.read(s, length);
|
||||||
|
|
||||||
if (stream.gcount() > length || stream.gcount() == 0)
|
if (stream.gcount() > length || stream.gcount() == 0)
|
||||||
{
|
{
|
||||||
global_deallocate(s);
|
global_deallocate(s);
|
||||||
return false;
|
return MAKE_PARSE_RESULT(status_io_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
s[stream.gcount()] = 0;
|
s[stream.gcount()] = 0;
|
||||||
@ -2878,24 +2920,24 @@ namespace pugi
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool xml_document::load(const char* contents, unsigned int options)
|
xml_parse_result xml_document::load(const char* contents, unsigned int options)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
char* s = static_cast<char*>(global_allocate(strlen(contents) + 1));
|
char* s = static_cast<char*>(global_allocate(strlen(contents) + 1));
|
||||||
if (!s) return false;
|
if (!s) return MAKE_PARSE_RESULT(status_out_of_memory);
|
||||||
|
|
||||||
strcpy(s, contents);
|
strcpy(s, contents);
|
||||||
|
|
||||||
return parse(transfer_ownership_tag(), s, options); // Parse the input string.
|
return parse(transfer_ownership_tag(), s, options); // Parse the input string.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xml_document::load_file(const char* name, unsigned int options)
|
xml_parse_result xml_document::load_file(const char* name, unsigned int options)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
FILE* file = fopen(name, "rb");
|
FILE* file = fopen(name, "rb");
|
||||||
if (!file) return false;
|
if (!file) return MAKE_PARSE_RESULT(status_file_not_found);
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
long length = ftell(file);
|
long length = ftell(file);
|
||||||
@ -2904,7 +2946,7 @@ namespace pugi
|
|||||||
if (length < 0)
|
if (length < 0)
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return false;
|
return MAKE_PARSE_RESULT(status_io_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* s = static_cast<char*>(global_allocate(length + 1));
|
char* s = static_cast<char*>(global_allocate(length + 1));
|
||||||
@ -2912,7 +2954,7 @@ namespace pugi
|
|||||||
if (!s)
|
if (!s)
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return false;
|
return MAKE_PARSE_RESULT(status_out_of_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t read = fread(s, (size_t)length, 1, file);
|
size_t read = fread(s, (size_t)length, 1, file);
|
||||||
@ -2921,7 +2963,7 @@ namespace pugi
|
|||||||
if (read != 1)
|
if (read != 1)
|
||||||
{
|
{
|
||||||
global_deallocate(s);
|
global_deallocate(s);
|
||||||
return false;
|
return MAKE_PARSE_RESULT(status_io_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
s[length] = 0;
|
s[length] = 0;
|
||||||
@ -2929,7 +2971,7 @@ namespace pugi
|
|||||||
return parse(transfer_ownership_tag(), s, options); // Parse the input string.
|
return parse(transfer_ownership_tag(), s, options); // Parse the input string.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xml_document::parse(char* xmlstr, unsigned int options)
|
xml_parse_result xml_document::parse(char* xmlstr, unsigned int options)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
@ -2943,9 +2985,9 @@ namespace pugi
|
|||||||
return parser.parse(xmlstr, _root, options); // Parse the input string.
|
return parser.parse(xmlstr, _root, options); // Parse the input string.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xml_document::parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options)
|
xml_parse_result xml_document::parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options)
|
||||||
{
|
{
|
||||||
bool res = parse(xmlstr, options);
|
xml_parse_result res = parse(xmlstr, options);
|
||||||
|
|
||||||
if (res) _buffer = xmlstr;
|
if (res) _buffer = xmlstr;
|
||||||
else global_deallocate(xmlstr);
|
else global_deallocate(xmlstr);
|
||||||
@ -2987,14 +3029,9 @@ namespace pugi
|
|||||||
|
|
||||||
void xml_document::precompute_document_order()
|
void xml_document::precompute_document_order()
|
||||||
{
|
{
|
||||||
precompute_document_order_impl(~0u);
|
precompute_document_order_impl();
|
||||||
}
|
}
|
||||||
|
|
||||||
void xml_document::invalidate_document_order()
|
|
||||||
{
|
|
||||||
precompute_document_order_impl(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PUGIXML_NO_STL
|
#ifndef PUGIXML_NO_STL
|
||||||
std::string as_utf8(const wchar_t* str)
|
std::string as_utf8(const wchar_t* str)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -621,7 +621,7 @@ namespace pugi
|
|||||||
explicit xml_node(xml_node_struct* p);
|
explicit xml_node(xml_node_struct* p);
|
||||||
|
|
||||||
/// \internal Precompute document order (valid only for document node)
|
/// \internal Precompute document order (valid only for document node)
|
||||||
void precompute_document_order_impl(unsigned int mask);
|
void precompute_document_order_impl();
|
||||||
|
|
||||||
/// \internal Get allocator
|
/// \internal Get allocator
|
||||||
xml_allocator& get_allocator() const;
|
xml_allocator& get_allocator() const;
|
||||||
@ -1494,6 +1494,55 @@ namespace pugi
|
|||||||
*/
|
*/
|
||||||
struct transfer_ownership_tag {};
|
struct transfer_ownership_tag {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsing status enumeration, returned as part of xml_parse_result struct
|
||||||
|
*/
|
||||||
|
enum xml_parse_status
|
||||||
|
{
|
||||||
|
status_ok = 0, ///< No error
|
||||||
|
|
||||||
|
status_file_not_found, ///< File was not found during load_file()
|
||||||
|
status_io_error, ///< Error reading from file/stream
|
||||||
|
status_out_of_memory, ///< Could not allocate memory
|
||||||
|
status_internal_error, ///< Internal error occured
|
||||||
|
|
||||||
|
status_unrecognized_tag, ///< Parser could not determine tag type
|
||||||
|
|
||||||
|
status_bad_pi, ///< Parsing error occured while parsing document declaration/processing instruction (<?...?>)
|
||||||
|
status_bad_comment, ///< Parsing error occured while parsing comment (<!--...-->)
|
||||||
|
status_bad_cdata, ///< Parsing error occured while parsing CDATA section (<![CDATA[...]]>)
|
||||||
|
status_bad_doctype, ///< Parsing error occured while parsing document type declaration
|
||||||
|
status_bad_pcdata, ///< Parsing error occured while parsing PCDATA section (>...<)
|
||||||
|
status_bad_start_element, ///< Parsing error occured while parsing start element tag (<name ...>)
|
||||||
|
status_bad_attribute, ///< Parsing error occured while parsing element attribute
|
||||||
|
status_bad_end_element, ///< Parsing error occured while parsing end element tag (</name>)
|
||||||
|
status_end_element_mismatch ///< There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser result
|
||||||
|
*/
|
||||||
|
struct xml_parse_result
|
||||||
|
{
|
||||||
|
/// Parsing status (\see xml_parse_status)
|
||||||
|
xml_parse_status status;
|
||||||
|
|
||||||
|
/// Last parsed offset (in bytes from file/string start)
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
/// Line in parser source which reported this
|
||||||
|
unsigned int line;
|
||||||
|
|
||||||
|
/// Cast to bool operator
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return status == status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get error description
|
||||||
|
const char* description() const;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document class (DOM tree root).
|
* Document class (DOM tree root).
|
||||||
* This class has noncopyable semantics (private copy ctor/assignment operator).
|
* This class has noncopyable semantics (private copy ctor/assignment operator).
|
||||||
@ -1529,9 +1578,9 @@ namespace pugi
|
|||||||
*
|
*
|
||||||
* \param stream - stream with xml data
|
* \param stream - stream with xml data
|
||||||
* \param options - parsing options
|
* \param options - parsing options
|
||||||
* \return success flag
|
* \return parsing result
|
||||||
*/
|
*/
|
||||||
bool load(std::istream& stream, unsigned int options = parse_default);
|
xml_parse_result load(std::istream& stream, unsigned int options = parse_default);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1539,18 +1588,18 @@ namespace pugi
|
|||||||
*
|
*
|
||||||
* \param contents - input string
|
* \param contents - input string
|
||||||
* \param options - parsing options
|
* \param options - parsing options
|
||||||
* \return success flag
|
* \return parsing result
|
||||||
*/
|
*/
|
||||||
bool load(const char* contents, unsigned int options = parse_default);
|
xml_parse_result load(const char* contents, unsigned int options = parse_default);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load document from file
|
* Load document from file
|
||||||
*
|
*
|
||||||
* \param name - file name
|
* \param name - file name
|
||||||
* \param options - parsing options
|
* \param options - parsing options
|
||||||
* \return success flag
|
* \return parsing result
|
||||||
*/
|
*/
|
||||||
bool load_file(const char* name, unsigned int options = parse_default);
|
xml_parse_result load_file(const char* name, unsigned int options = parse_default);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given XML string in-situ.
|
* Parse the given XML string in-situ.
|
||||||
@ -1560,9 +1609,9 @@ namespace pugi
|
|||||||
*
|
*
|
||||||
* \param xmlstr - readwrite string with xml data
|
* \param xmlstr - readwrite string with xml data
|
||||||
* \param options - parsing options
|
* \param options - parsing options
|
||||||
* \return success flag
|
* \return parsing result
|
||||||
*/
|
*/
|
||||||
bool parse(char* xmlstr, unsigned int options = parse_default);
|
xml_parse_result parse(char* xmlstr, unsigned int options = parse_default);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given XML string in-situ (gains ownership).
|
* Parse the given XML string in-situ (gains ownership).
|
||||||
@ -1572,9 +1621,9 @@ namespace pugi
|
|||||||
*
|
*
|
||||||
* \param xmlstr - readwrite string with xml data
|
* \param xmlstr - readwrite string with xml data
|
||||||
* \param options - parsing options
|
* \param options - parsing options
|
||||||
* \return success flag
|
* \return parsing result
|
||||||
*/
|
*/
|
||||||
bool parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options = parse_default);
|
xml_parse_result parse(const transfer_ownership_tag&, char* xmlstr, unsigned int options = parse_default);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save XML to writer
|
* Save XML to writer
|
||||||
@ -1600,13 +1649,6 @@ namespace pugi
|
|||||||
* Sometimes this makes evaluation of XPath queries faster.
|
* Sometimes this makes evaluation of XPath queries faster.
|
||||||
*/
|
*/
|
||||||
void precompute_document_order();
|
void precompute_document_order();
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidate document order for the whole tree
|
|
||||||
* If you precomputed document order for the tree and inserted new nodes/attributes after that,
|
|
||||||
* XPath queries will sometimes give incorrect results.
|
|
||||||
*/
|
|
||||||
void invalidate_document_order();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef PUGIXML_NO_XPATH
|
#ifndef PUGIXML_NO_XPATH
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user