From 7f6b062e9f51c98e56713b1869c01573d7fe855f Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 15 Jan 2014 04:28:10 +0000 Subject: Implement automatic hexadecimal decoding for xml_attribute::as_int and xml_text::as_int. This is effectively a form of strtol with base 0, but without octal support. git-svn-id: http://pugixml.googlecode.com/svn/trunk@958 99668b35-9821-0410-8761-19e4c4f06640 --- docs/manual.qbk | 2 +- src/pugixml.cpp | 27 ++++++++++++++++++++++----- tests/test_dom_text.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- tests/test_dom_traverse.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/docs/manual.qbk b/docs/manual.qbk index 587c2b4..820b9e7 100644 --- a/docs/manual.qbk +++ b/docs/manual.qbk @@ -882,7 +882,7 @@ In many cases attribute values have types that are not strings - i.e. an attribu float xml_attribute::as_float(float def = 0) const; bool xml_attribute::as_bool(bool def = false) const; -`as_int`, `as_uint`, `as_double` and `as_float` convert attribute values to numbers. If attribute handle is null or attribute value is empty, `def` argument is returned (which is 0 by default). Otherwise, all leading whitespace characters are truncated, and the remaining string is parsed as a decimal number (`as_int` or `as_uint`) or as a floating point number in either decimal or scientific form (`as_double` or `as_float`). Any extra characters are silently discarded, i.e. `as_int` will return `1` for string `"1abc"`. +`as_int`, `as_uint`, `as_double` and `as_float` convert attribute values to numbers. If attribute handle is null or attribute value is empty, `def` argument is returned (which is 0 by default). Otherwise, all leading whitespace characters are truncated, and the remaining string is parsed as an integer number in either decimal or hexadecimal form (`as_int` or `as_uint`; hexadecimal format is used if the number has `0x` or `0X` prefix) or as a floating point number in either decimal or scientific form (`as_double` or `as_float`). Any extra characters are silently discarded, i.e. `as_int` will return `1` for string `"1abc"`. In case the input string contains a number that is out of the target numeric range, the result is undefined. diff --git a/src/pugixml.cpp b/src/pugixml.cpp index be8bcea..b637f27 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3314,14 +3314,29 @@ PUGI__NS_BEGIN } // get value with conversion functions + PUGI__FN int get_integer_base(const char_t* value) + { + const char_t* s = value; + + while (PUGI__IS_CHARTYPE(*s, ct_space)) + s++; + + if (*s == '-') + s++; + + return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; + } + PUGI__FN int get_value_int(const char_t* value, int def) { if (!value) return def; + int base = get_integer_base(value); + #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstol(value, 0, 10)); + return static_cast(wcstol(value, 0, base)); #else - return static_cast(strtol(value, 0, 10)); + return static_cast(strtol(value, 0, base)); #endif } @@ -3329,10 +3344,12 @@ PUGI__NS_BEGIN { if (!value) return def; + int base = get_integer_base(value); + #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstoul(value, 0, 10)); + return static_cast(wcstoul(value, 0, base)); #else - return static_cast(strtoul(value, 0, 10)); + return static_cast(strtoul(value, 0, base)); #endif } @@ -9876,7 +9893,7 @@ namespace pugi return error ? error : "No error"; } - PUGI__FN xpath_variable::xpath_variable() + PUGI__FN xpath_variable::xpath_variable(): _type(xpath_type_none), _next(0) { } diff --git a/tests/test_dom_text.cpp b/tests/test_dom_text.cpp index 153c372..2e38f29 100644 --- a/tests/test_dom_text.cpp +++ b/tests/test_dom_text.cpp @@ -57,7 +57,7 @@ TEST_XML_FLAGS(dom_text_as_string, "foo1-1-21474836482147483647") +TEST_XML(dom_text_as_int, "1-1-214748364821474836470") { xml_node node = doc.child(STR("node")); @@ -66,9 +66,22 @@ TEST_XML(dom_text_as_int, "1-1-214748 CHECK(node.child(STR("text2")).text().as_int() == -1); CHECK(node.child(STR("text3")).text().as_int() == -2147483647 - 1); CHECK(node.child(STR("text4")).text().as_int() == 2147483647); + CHECK(node.child(STR("text5")).text().as_int() == 0); } -TEST_XML(dom_text_as_uint, "0121474836474294967295") +TEST_XML(dom_text_as_int_hex, "07770x5ab0XFf-0x20-0x800000000x") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.child(STR("text1")).text().as_int() == 777); // no octal support! intentional + CHECK(node.child(STR("text2")).text().as_int() == 1451); + CHECK(node.child(STR("text3")).text().as_int() == 255); + CHECK(node.child(STR("text4")).text().as_int() == -32); + CHECK(node.child(STR("text5")).text().as_int() == -2147483647 - 1); + CHECK(node.child(STR("text6")).text().as_int() == 0); +} + +TEST_XML(dom_text_as_uint, "01214748364742949672950") { xml_node node = doc.child(STR("node")); @@ -77,6 +90,29 @@ TEST_XML(dom_text_as_uint, "012147483 CHECK(node.child(STR("text2")).text().as_uint() == 1); CHECK(node.child(STR("text3")).text().as_uint() == 2147483647); CHECK(node.child(STR("text4")).text().as_uint() == 4294967295u); + CHECK(node.child(STR("text5")).text().as_uint() == 0); +} + +TEST_XML(dom_text_as_uint_hex, "07770x5ab0XFf0x200xFFFFFFFF0x") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.child(STR("text1")).text().as_uint() == 777); // no octal support! intentional + CHECK(node.child(STR("text2")).text().as_uint() == 1451); + CHECK(node.child(STR("text3")).text().as_uint() == 255); + CHECK(node.child(STR("text4")).text().as_uint() == 32); + CHECK(node.child(STR("text5")).text().as_uint() == 4294967295u); + CHECK(node.child(STR("text6")).text().as_uint() == 0); +} + +TEST_XML(dom_text_as_integer_space, " \t\n1234\n\t 0x123- 16- 0x10") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.child(STR("text1")).text().as_int() == 1234); + CHECK(node.child(STR("text2")).text().as_int() == 291); + CHECK(node.child(STR("text3")).text().as_int() == 0); + CHECK(node.child(STR("text4")).text().as_int() == 0); } TEST_XML(dom_text_as_float, "010.12-5.13e-43.14159265358979323846") diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp index d699c5e..1668174 100644 --- a/tests/test_dom_traverse.cpp +++ b/tests/test_dom_traverse.cpp @@ -87,7 +87,7 @@ TEST_XML(dom_attr_as_string, "") CHECK_STRING(xml_attribute().as_string(), STR("")); } -TEST_XML(dom_attr_as_int, "") +TEST_XML(dom_attr_as_int, "") { xml_node node = doc.child(STR("node")); @@ -96,9 +96,22 @@ TEST_XML(dom_attr_as_int, "") +TEST_XML(dom_attr_as_int_hex, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute(STR("attr1")).as_int() == 777); // no octal support! intentional + CHECK(node.attribute(STR("attr2")).as_int() == 1451); + CHECK(node.attribute(STR("attr3")).as_int() == 255); + CHECK(node.attribute(STR("attr4")).as_int() == -32); + CHECK(node.attribute(STR("attr5")).as_int() == -2147483647 - 1); + CHECK(node.attribute(STR("attr6")).as_int() == 0); +} + +TEST_XML(dom_attr_as_uint, "") { xml_node node = doc.child(STR("node")); @@ -107,6 +120,29 @@ TEST_XML(dom_attr_as_uint, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute(STR("attr1")).as_uint() == 777); // no octal support! intentional + CHECK(node.attribute(STR("attr2")).as_uint() == 1451); + CHECK(node.attribute(STR("attr3")).as_uint() == 255); + CHECK(node.attribute(STR("attr4")).as_uint() == 32); + CHECK(node.attribute(STR("attr5")).as_uint() == 4294967295u); + CHECK(node.attribute(STR("attr6")).as_uint() == 0); +} + +TEST_XML(dom_attr_as_integer_space, "") +{ + xml_node node = doc.child(STR("node")); + + CHECK(node.attribute(STR("attr1")).as_int() == 1234); + CHECK(node.attribute(STR("attr2")).as_int() == 291); + CHECK(node.attribute(STR("attr3")).as_int() == 0); + CHECK(node.attribute(STR("attr4")).as_int() == 0); } TEST_XML(dom_attr_as_float, "") -- cgit v1.2.3