Skip to content

Commit

Permalink
Add overloads with size_t type argument
Browse files Browse the repository at this point in the history
* bool xml_attribute::set_name(const char_t* rhs, size_t sz)

* xml_attribute xml_node::append_attribute(const char_t* name_, size_t sz)
*      xml_node xml_node::append_child(const char_t* name_, size_t sz)
* xml_attribute xml_node::attribute(const char_t* name_, size_t sz) const
*      xml_node xml_node::child(const char_t* name_, size_t sz) const
*          bool xml_node::set_name(const char_t* rhs, size_t sz)
  • Loading branch information
stefanroellin committed Dec 3, 2022
1 parent 9568394 commit 11d5044
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
81 changes: 81 additions & 0 deletions src/pugixml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ PUGI__NS_BEGIN
#endif
}

// Compare lhs (0 terminated) with [rhs_begin, rhs_end)
PUGI__FN bool strequal(const char_t* lhs, const char_t* rhs, size_t count)
{
for (size_t i = 0; i < count; ++i)
if (lhs[i] == 0 || lhs[i] != rhs[i])
return false;

return lhs[count] == 0;
}

// Compare lhs with [rhs_begin, rhs_end)
PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
{
Expand Down Expand Up @@ -5374,6 +5384,13 @@ namespace pugi
return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
}

PUGI__FN bool xml_attribute::set_name(const char_t* rhs, size_t sz)
{
if (!_attr) return false;

return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, sz);
}

PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz)
{
if (!_attr) return false;
Expand Down Expand Up @@ -5604,6 +5621,20 @@ namespace pugi
return xml_node();
}

PUGI__FN xml_node xml_node::child(const char_t* name_, size_t sz) const
{
if (!_root) return xml_node();

for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
{
const char_t* iname = i->name;
if (iname && impl::strequal(iname, name_, sz))
return xml_node(i);
}

return xml_node();
}

PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
{
if (!_root) return xml_attribute();
Expand All @@ -5618,6 +5649,20 @@ namespace pugi
return xml_attribute();
}

PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, size_t sz) const
{
if (!_root) return xml_attribute();

for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
{
const char_t* iname = i->name;
if (iname && impl::strequal(iname, name_, sz))
return xml_attribute(i);
}

return xml_attribute();
}

PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
{
if (!_root) return xml_node();
Expand Down Expand Up @@ -5771,6 +5816,16 @@ namespace pugi
return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
}

PUGI__FN bool xml_node::set_name(const char_t* rhs, size_t sz)
{
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;

if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
return false;

return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, sz);
}

PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz)
{
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
Expand Down Expand Up @@ -5808,6 +5863,23 @@ namespace pugi
return a;
}

PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_, size_t sz)
{
if (!impl::allow_insert_attribute(type())) return xml_attribute();

impl::xml_allocator& alloc = impl::get_allocator(_root);
if (!alloc.reserve()) return xml_attribute();

xml_attribute a(impl::allocate_attribute(alloc));
if (!a) return xml_attribute();

impl::append_attribute(a._attr, _root);

a.set_name(name_, sz);

return a;
}

PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
{
if (!impl::allow_insert_attribute(type())) return xml_attribute();
Expand Down Expand Up @@ -6010,6 +6082,15 @@ namespace pugi
return result;
}

PUGI__FN xml_node xml_node::append_child(const char_t* name_, size_t sz)
{
xml_node result = append_child(node_element);

result.set_name(name_, sz);

return result;
}

PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
{
xml_node result = prepend_child(node_element);
Expand Down
6 changes: 6 additions & 0 deletions src/pugixml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ namespace pugi

// Set attribute name/value (returns false if attribute is empty or there is not enough memory)
bool set_name(const char_t* rhs);
bool set_name(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs);

Expand Down Expand Up @@ -538,7 +539,9 @@ namespace pugi

// Get child, attribute or next/previous sibling with the specified name
xml_node child(const char_t* name) const;
xml_node child(const char_t* name, size_t sz) const;
xml_attribute attribute(const char_t* name) const;
xml_attribute attribute(const char_t* name, size_t) const;
xml_node next_sibling(const char_t* name) const;
xml_node previous_sibling(const char_t* name) const;

Expand All @@ -553,11 +556,13 @@ namespace pugi

// Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
bool set_name(const char_t* rhs);
bool set_name(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs);

// Add attribute with specified name. Returns added attribute, or empty attribute on errors.
xml_attribute append_attribute(const char_t* name);
xml_attribute append_attribute(const char_t* name, size_t sz);
xml_attribute prepend_attribute(const char_t* name);
xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
Expand All @@ -576,6 +581,7 @@ namespace pugi

// Add child element with specified name. Returns added node, or empty node on errors.
xml_node append_child(const char_t* name);
xml_node append_child(const char_t* name, size_t sz);
xml_node prepend_child(const char_t* name);
xml_node insert_child_after(const char_t* name, const xml_node& node);
xml_node insert_child_before(const char_t* name, const xml_node& node);
Expand Down
60 changes: 60 additions & 0 deletions tests/test_dom_modify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,33 @@ TEST_XML(dom_attr_assign, "<node/>")
CHECK_NODE(node, STR("<node attr1=\"v1\" attr2=\"-2147483647\" attr3=\"-2147483648\" attr4=\"4294967295\" attr5=\"4294967294\" attr6=\"0.5\" attr7=\"0.25\" attr8=\"true\"/>"));
}

TEST_XML(dom_attr_assign_with_size, "<node/>")
{
xml_node node = doc.child(STR("node"));

node.append_attribute(STR("attr12345"), 5) = STR("v1");
xml_attribute() = STR("v1");

node.append_attribute(STR("attr23456"), 5) = -2147483647;
node.append_attribute(STR("attr321"), 5) = -2147483647 - 1;
xml_attribute() = -2147483647 - 1;

node.append_attribute(STR("attr4unused"), 5) = 4294967295u;
node.append_attribute(STR("attr5unused"), 5) = 4294967294u;
xml_attribute() = 4294967295u;

node.append_attribute(STR("attr6"), 5) = 0.5;
xml_attribute() = 0.5;

node.append_attribute(STR("attr76543210"), 5) = 0.25f;
xml_attribute() = 0.25f;

node.append_attribute(STR("attr8888"), 5) = true;
xml_attribute() = true;

CHECK_NODE(node, STR("<node attr1=\"v1\" attr2=\"-2147483647\" attr3=\"-2147483648\" attr4=\"4294967295\" attr5=\"4294967294\" attr6=\"0.5\" attr7=\"0.25\" attr8=\"true\"/>"));
}

TEST_XML(dom_attr_set_name, "<node attr='value' />")
{
xml_attribute attr = doc.child(STR("node")).attribute(STR("attr"));
Expand All @@ -46,6 +73,16 @@ TEST_XML(dom_attr_set_name, "<node attr='value' />")
CHECK_NODE(doc, STR("<node n=\"value\"/>"));
}

TEST_XML(dom_attr_set_name_with_size, "<node attr='value' />")
{
xml_attribute attr = doc.child(STR("node")).attribute(STR("attr"));

CHECK(attr.set_name(STR("n1234"), 1));
CHECK(!xml_attribute().set_name(STR("nfail"), 1));

CHECK_NODE(doc, STR("<node n=\"value\"/>"));
}

TEST_XML(dom_attr_set_value, "<node/>")
{
xml_node node = doc.child(STR("node"));
Expand Down Expand Up @@ -206,6 +243,15 @@ TEST_XML(dom_node_set_name, "<node>text</node>")
CHECK_NODE(doc, STR("<n>text</n>"));
}

TEST_XML(dom_node_set_name_size, "<node>text</node>")
{
CHECK(doc.child(STR("node")).set_name(STR("nlongname"), 1));
CHECK(!doc.child(STR("node")).first_child().set_name(STR("n42"), 1));
CHECK(!xml_node().set_name(STR("nanothername"), 1));

CHECK_NODE(doc, STR("<n>text</n>"));
}

TEST_XML(dom_node_set_value, "<node>text</node>")
{
CHECK(doc.child(STR("node")).first_child().set_value(STR("no text")));
Expand Down Expand Up @@ -696,6 +742,20 @@ TEST_XML(dom_node_append_child_name, "<node>foo<child/></node>")
CHECK_NODE(doc, STR("<node>foo<child/><n1/><n2/></node>"));
}

TEST_XML(dom_node_append_child_name_size, "<node>foo<child/></node>")
{
CHECK(xml_node().append_child(STR("")) == xml_node());
CHECK(doc.child(STR("node")).first_child().append_child(STR(""), 0) == xml_node());

xml_node n1 = doc.child(STR("node")).append_child(STR("n1garbage"), 2);
CHECK(n1);

xml_node n2 = doc.child(STR("node")).append_child(STR("n2n1"), 2);
CHECK(n2 && n1 != n2);

CHECK_NODE(doc, STR("<node>foo<child/><n1/><n2/></node>"));
}

TEST_XML(dom_node_insert_child_after_name, "<node>foo<child/></node>")
{
CHECK(xml_node().insert_child_after(STR(""), xml_node()) == xml_node());
Expand Down
5 changes: 5 additions & 0 deletions tests/test_dom_traverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ TEST_XML(dom_attr_eq_ops, "<node attr1='1' attr2='2'/>")
generic_eq_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2")));
}

TEST_XML(dom_attr_eq_ops_with_size, "<node attr1='1' attr2='2'/>")
{
generic_eq_ops_test(doc.child(STR("nodeunused"), 4).attribute(STR("attr123456"), 5), doc.child(STR("nodenode"), 4).attribute(STR("attr2"), 5));
}

TEST_XML(dom_attr_rel_ops, "<node attr1='1' attr2='2'/>")
{
generic_rel_ops_test(doc.child(STR("node")).attribute(STR("attr1")), doc.child(STR("node")).attribute(STR("attr2")));
Expand Down

0 comments on commit 11d5044

Please sign in to comment.