use core::ffi::c_void;
use core::ptr;
use std::os::raw::{c_char, c_int, c_uint};
use crate::abi::allocator;
use crate::abi::constants::*;
use crate::abi::structs::*;
use crate::abi::types::xmlAttributeType::XML_ATTRIBUTE_CDATA;
use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
use crate::abi::types::xmlDocProperties::XML_DOC_WELLFORMED;
use crate::abi::types::xmlElementType::*;
use crate::abi::types::*;
use crate::xml::globals;
unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
if str.is_null() {
return ptr::null_mut();
}
let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
if len == 0 {
let buf = unsafe { allocator::xmlMalloc(1) as *mut xmlChar };
if !buf.is_null() {
unsafe { *buf = 0 };
}
return buf;
}
let buf = unsafe { allocator::xmlMalloc(len + 1) as *mut xmlChar };
if !buf.is_null() {
unsafe {
ptr::copy_nonoverlapping(str, buf, len + 1);
}
}
buf
}
unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
if src.is_null() || dest.is_null() || max_len == 0 {
return false;
}
let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
if len >= max_len {
return false;
}
unsafe {
ptr::copy_nonoverlapping(src, dest, len);
*dest.add(len) = 0;
}
true
}
pub unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
if str.is_null() {
return 0;
}
let mut len: c_int = 0;
while unsafe { *str.add(len as usize) != 0 } {
len += 1;
}
len
}
pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
if doc.is_null() {
return ptr::null_mut();
}
unsafe {
(*doc).type_ = XML_DOCUMENT_NODE as c_int;
(*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_WELLFORMED as c_int;
(*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
let ver = if version.is_null() {
XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
} else {
version
};
(*doc).version = dup_xml_str(ver);
}
doc
}
pub unsafe fn free_doc(doc: *mut _xmlDoc) {
if doc.is_null() {
return;
}
let d = unsafe { &mut *doc };
if !d.intSubset.is_null() {
free_dtd(d.intSubset);
}
if !d.extSubset.is_null() {
free_dtd(d.extSubset);
}
if !d.children.is_null() {
free_node_list(d.children);
}
if !d.oldNs.is_null() {
free_ns_list(d.oldNs);
}
if !d.version.is_null() {
allocator::xmlFree(d.version as *mut c_void);
}
if !d.encoding.is_null() {
allocator::xmlFree(d.encoding as *mut c_void);
}
if !d.URL.is_null() {
allocator::xmlFree(d.URL as *mut c_void);
}
allocator::xmlFree(doc as *mut c_void);
}
pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
if doc.is_null() {
return ptr::null_mut();
}
let d = unsafe { &*doc };
let new_doc = new_doc(d.version);
if new_doc.is_null() {
return ptr::null_mut();
}
unsafe {
(*new_doc).type_ = d.type_;
(*new_doc).standalone = d.standalone;
(*new_doc).encoding = dup_xml_str(d.encoding);
(*new_doc).URL = dup_xml_str(d.URL);
(*new_doc).charset = d.charset;
(*new_doc).properties = d.properties;
if recursive != 0 && !d.children.is_null() {
(*new_doc).children = copy_node_list(d.children, recursive);
if !(*new_doc).children.is_null() {
(*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
propagate_doc((*new_doc).children, new_doc);
}
}
}
new_doc
}
pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
if doc.is_null() {
return ptr::null_mut();
}
let d = unsafe { &mut *doc };
let old_root = doc_get_root_element(doc);
if !root.is_null() {
unsafe {
(*root).parent = ptr::null_mut();
(*root).doc = doc;
}
d.children = root;
d.last = root;
unsafe {
(*root).prev = ptr::null_mut();
(*root).next = ptr::null_mut();
}
} else {
d.children = ptr::null_mut();
d.last = ptr::null_mut();
}
old_root
}
pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
if doc.is_null() {
return ptr::null_mut();
}
let d = unsafe { &*doc };
let mut cur = d.children;
while !cur.is_null() {
let node = unsafe { &*cur };
if node.type_ == XML_ELEMENT_NODE as c_int {
return cur;
}
cur = node.next;
}
ptr::null_mut()
}
pub fn get_line_no(node: *const _xmlNode) -> c_int {
if node.is_null() {
return 0;
}
let n = unsafe { &*node };
n.line as c_int
}
pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
unsafe {
(*node).type_ = XML_ELEMENT_NODE as c_int;
(*node).name = dup_xml_str(name);
(*node).ns = ns;
(*node).line = 0;
(*node).extra = 0;
if !ns.is_null() {
(*ns).context = node as *mut _xmlDoc;
}
}
node
}
pub unsafe fn free_node(node: *mut _xmlNode) {
if node.is_null() {
return;
}
let n = unsafe { &mut *node };
if !n.properties.is_null() {
free_prop_list(n.properties);
}
if !n.nsDef.is_null() {
free_ns_list(n.nsDef);
}
if !n.name.is_null() {
allocator::xmlFree(n.name as *mut c_void);
}
if !n.content.is_null() {
let node_type = n.type_;
if node_type == XML_TEXT_NODE as c_int
|| node_type == XML_CDATA_SECTION_NODE as c_int
|| node_type == XML_COMMENT_NODE as c_int
|| node_type == XML_PI_NODE as c_int
{
allocator::xmlFree(n.content as *mut c_void);
}
}
allocator::xmlFree(node as *mut c_void);
}
pub unsafe fn free_node_list(node: *mut _xmlNode) {
let mut cur = node;
while !cur.is_null() {
let next = unsafe { (*cur).next };
if !unsafe { (*cur).children }.is_null() {
free_node_list(unsafe { (*cur).children });
}
free_node(cur);
cur = next;
}
}
unsafe fn free_prop_list(prop: *mut _xmlAttr) {
let mut cur = prop;
while !cur.is_null() {
let next = unsafe { (*cur).next };
if !unsafe { (*cur).children }.is_null() {
free_node_list(unsafe { (*cur).children });
}
if !unsafe { (*cur).name }.is_null() {
allocator::xmlFree(unsafe { (*cur).name } as *mut c_void);
}
allocator::xmlFree(cur as *mut c_void);
cur = next;
}
}
unsafe fn free_ns_list(ns: *mut _xmlNs) {
let mut cur = ns;
while !cur.is_null() {
let next = unsafe { (*cur).next };
if !unsafe { (*cur).href }.is_null() {
allocator::xmlFree(unsafe { (*cur).href } as *mut c_void);
}
if !unsafe { (*cur).prefix }.is_null() {
allocator::xmlFree(unsafe { (*cur).prefix } as *mut c_void);
}
allocator::xmlFree(cur as *mut c_void);
cur = next;
}
}
pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let n = unsafe { &*node };
let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if new_node.is_null() {
return ptr::null_mut();
}
unsafe {
(*new_node).type_ = n.type_;
(*new_node).name = dup_xml_str(n.name);
(*new_node).line = n.line;
(*new_node).extra = n.extra;
(*new_node).psvi = n.psvi;
(*new_node)._private = n._private;
(*new_node).ns = n.ns;
if !n.nsDef.is_null() {
(*new_node).nsDef = copy_ns_list(n.nsDef);
}
let node_type = n.type_;
if (node_type == XML_TEXT_NODE as c_int
|| node_type == XML_CDATA_SECTION_NODE as c_int
|| node_type == XML_COMMENT_NODE as c_int
|| node_type == XML_PI_NODE as c_int)
&& !n.content.is_null()
{
(*new_node).content = dup_xml_str(n.content);
}
if !n.properties.is_null() {
(*new_node).properties = copy_prop_list(n.properties);
let mut prop = (*new_node).properties;
while !prop.is_null() {
(*prop).parent = new_node;
if !(*prop).children.is_null() {
propagate_doc((*prop).children, (*new_node).doc);
}
prop = (*prop).next;
}
}
if recursive != 0 && !n.children.is_null() {
(*new_node).children = copy_node_list(n.children, recursive);
if !(*new_node).children.is_null() {
(*(*new_node).children).parent = new_node;
(*(*new_node).children).doc = (*new_node).doc;
propagate_doc((*new_node).children, (*new_node).doc);
}
}
}
new_node
}
unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let n = unsafe { &*node };
let new_node = copy_node(node, recursive);
if new_node.is_null() {
return ptr::null_mut();
}
let mut prev = new_node;
let mut cur = n.next;
while !cur.is_null() {
let new_cur = copy_node(cur, recursive);
if new_cur.is_null() {
break;
}
unsafe {
(*prev).next = new_cur;
(*new_cur).prev = prev;
}
prev = new_cur;
cur = unsafe { (*cur).next };
}
new_node
}
unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
if ns.is_null() {
return ptr::null_mut();
}
let n = unsafe { &*ns };
let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
if new_ns.is_null() {
return ptr::null_mut();
}
unsafe {
(*new_ns).type_ = n.type_;
(*new_ns).href = dup_xml_str(n.href);
(*new_ns).prefix = dup_xml_str(n.prefix);
(*new_ns)._private = n._private;
}
let mut prev = new_ns;
let mut cur = n.next;
while !cur.is_null() {
let c = unsafe { &*cur };
let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
if new_cur.is_null() {
break;
}
unsafe {
(*new_cur).type_ = c.type_;
(*new_cur).href = dup_xml_str(c.href);
(*new_cur).prefix = dup_xml_str(c.prefix);
(*new_cur)._private = c._private;
(*prev).next = new_cur;
}
prev = new_cur;
cur = c.next;
}
new_ns
}
unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
if prop.is_null() {
return ptr::null_mut();
}
let p = unsafe { &*prop };
let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
if new_prop.is_null() {
return ptr::null_mut();
}
unsafe {
(*new_prop).type_ = p.type_;
(*new_prop).name = dup_xml_str(p.name);
(*new_prop).ns = p.ns;
(*new_prop).atype = p.atype;
if !p.children.is_null() {
(*new_prop).children = copy_node_list(p.children, 1);
if !(*new_prop).children.is_null() {
(*(*new_prop).children).parent = new_prop as *mut _xmlNode;
}
}
}
let mut prev = new_prop;
let mut cur = p.next;
while !cur.is_null() {
let c = unsafe { &*cur };
let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
if new_cur.is_null() {
break;
}
unsafe {
(*new_cur).type_ = c.type_;
(*new_cur).name = dup_xml_str(c.name);
(*new_cur).ns = c.ns;
(*new_cur).atype = c.atype;
if !c.children.is_null() {
(*new_cur).children = copy_node_list(c.children, 1);
if !(*new_cur).children.is_null() {
(*(*new_cur).children).parent = new_cur as *mut _xmlNode;
}
}
(*prev).next = new_cur;
}
prev = new_cur;
cur = c.next;
}
new_prop
}
unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
let mut cur = node;
while !cur.is_null() {
unsafe {
(*cur).doc = doc;
let mut prop = (*cur).properties;
while !prop.is_null() {
(*prop).doc = doc;
if !(*prop).children.is_null() {
propagate_doc((*prop).children, doc);
}
prop = (*prop).next;
}
if !(*cur).children.is_null() {
propagate_doc((*cur).children, doc);
}
}
cur = unsafe { (*cur).next };
}
}
pub unsafe fn unlink_node(node: *mut _xmlNode) {
if node.is_null() {
return;
}
let n = unsafe { &mut *node };
let prev = n.prev;
let next = n.next;
if !prev.is_null() {
unsafe { (*prev).next = next };
}
if !next.is_null() {
unsafe { (*next).prev = prev };
}
let parent = n.parent;
if !parent.is_null() {
if unsafe { (*parent).children } == node {
unsafe { (*parent).children = next };
}
if unsafe { (*parent).last } == node {
unsafe { (*parent).last = prev };
}
}
let doc = n.doc;
if !doc.is_null() && !parent.is_null() {
}
if !doc.is_null() && parent.is_null() {
if unsafe { (*doc).children } == node {
unsafe { (*doc).children = next };
}
if unsafe { (*doc).last } == node {
unsafe { (*doc).last = prev };
}
}
n.parent = ptr::null_mut();
n.prev = ptr::null_mut();
n.next = ptr::null_mut();
}
pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
if parent.is_null() || cur.is_null() {
return ptr::null_mut();
}
let p = unsafe { &mut *parent };
let c = unsafe { &mut *cur };
if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
unlink_node(cur);
}
c.parent = parent;
if p.children.is_null() {
p.children = cur;
p.last = cur;
c.prev = ptr::null_mut();
c.next = ptr::null_mut();
} else {
c.prev = p.last;
c.next = ptr::null_mut();
if !p.last.is_null() {
unsafe { (*p.last).next = cur };
}
p.last = cur;
}
let doc = if !p.doc.is_null() {
p.doc
} else {
ptr::null_mut()
};
if !doc.is_null() && c.doc != doc {
propagate_doc(cur, doc);
}
cur
}
pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
if cur.is_null() || elem.is_null() {
return ptr::null_mut();
}
let c = unsafe { &mut *cur };
let e = unsafe { &mut *elem };
if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
unlink_node(elem);
}
e.parent = c.parent;
e.prev = cur;
e.next = c.next;
if !c.next.is_null() {
unsafe { (*c.next).prev = elem };
}
c.next = elem;
let parent = c.parent;
if !parent.is_null() && unsafe { (*parent).last } == cur {
unsafe { (*parent).last = elem };
}
if !c.doc.is_null() && e.doc != c.doc {
propagate_doc(elem, c.doc);
}
elem
}
pub unsafe fn new_child(
parent: *mut _xmlNode,
ns: *mut _xmlNs,
name: *const xmlChar,
) -> *mut _xmlNode {
let node = new_node(ns, name);
if node.is_null() {
return ptr::null_mut();
}
if !parent.is_null() {
add_child(parent, node);
}
node
}
pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
unsafe {
(*node).type_ = XML_TEXT_NODE as c_int;
(*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
(*node).content = if content.is_null() {
let empty = allocator::xmlMalloc(1) as *mut xmlChar;
if !empty.is_null() {
*empty = 0;
}
empty
} else {
dup_xml_str(content)
};
(*node).line = 0;
}
node
}
pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
unsafe {
(*node).type_ = XML_COMMENT_NODE as c_int;
(*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
(*node).content = dup_xml_str(content);
(*node).line = 0;
}
node
}
pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
unsafe {
(*node).type_ = XML_PI_NODE as c_int;
(*node).name = dup_xml_str(name);
(*node).content = dup_xml_str(content);
(*node).line = 0;
}
node
}
pub unsafe fn new_cdata_block(
doc: *mut _xmlDoc,
content: *const xmlChar,
len: c_int,
) -> *mut _xmlNode {
let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
unsafe {
(*node).type_ = XML_CDATA_SECTION_NODE as c_int;
(*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
(*node).doc = doc;
if !content.is_null() && len > 0 {
(*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
if !(*node).content.is_null() {
ptr::copy_nonoverlapping(content, (*node).content, len as usize);
*((*node).content.add(len as usize)) = 0;
}
} else {
let empty = allocator::xmlMalloc(1) as *mut xmlChar;
if !empty.is_null() {
*empty = 0;
}
(*node).content = empty;
}
(*node).line = 0;
}
node
}
pub unsafe fn new_ns(
node: *mut _xmlNode,
href: *const xmlChar,
prefix: *const xmlChar,
) -> *mut _xmlNs {
let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
if ns.is_null() {
return ptr::null_mut();
}
unsafe {
(*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
(*ns).href = dup_xml_str(href);
(*ns).prefix = dup_xml_str(prefix);
(*ns).context = node as *mut _xmlDoc;
if !node.is_null() {
let n = &mut *node;
if n.nsDef.is_null() {
n.nsDef = ns;
} else {
let mut last = n.nsDef;
while !(*last).next.is_null() {
last = (*last).next;
}
(*last).next = ns;
}
}
}
ns
}
pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
if node.is_null() {
return;
}
unsafe {
(*node).ns = ns;
}
}
pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
if node.is_null() {
return ptr::null_mut();
}
let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
let mut cur = node;
while !cur.is_null() {
let n = unsafe { &*cur };
let mut ns_def = n.nsDef;
while !ns_def.is_null() {
let ns = unsafe { &*ns_def };
let mut found = false;
for &existing in &ns_ptrs {
if existing == ns_def {
found = true;
break;
}
let e = unsafe { &*existing };
if !ns.href.is_null() && !e.href.is_null() {
let href_match =
unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
if href_match {
if ns.prefix.is_null() && e.prefix.is_null() {
found = true;
break;
}
if !ns.prefix.is_null() && !e.prefix.is_null() {
let prefix_match = unsafe {
crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
};
if prefix_match {
found = true;
break;
}
}
}
}
}
if !found {
ns_ptrs.push(ns_def);
}
ns_def = unsafe { (*ns_def).next };
}
cur = n.parent;
}
if ns_ptrs.is_empty() {
return ptr::null_mut();
}
let arr =
allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
if arr.is_null() {
return ptr::null_mut();
}
for (i, ns) in ns_ptrs.iter().enumerate() {
unsafe { *arr.add(i) = *ns };
}
unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
arr
}
pub unsafe fn search_ns(
doc: *mut _xmlDoc,
node: *mut _xmlNode,
name_space: *const xmlChar,
) -> *mut _xmlNs {
if node.is_null() {
return ptr::null_mut();
}
let mut cur = node;
while !cur.is_null() {
let n = unsafe { &*cur };
let mut ns_def = n.nsDef;
while !ns_def.is_null() {
let ns = unsafe { &*ns_def };
let match_prefix = if name_space.is_null() {
ns.prefix.is_null()
} else {
!ns.prefix.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
};
if match_prefix {
return ns_def;
}
ns_def = unsafe { (*ns_def).next };
}
cur = n.parent;
}
ptr::null_mut()
}
pub unsafe fn search_ns_by_href(
doc: *mut _xmlDoc,
node: *mut _xmlNode,
href: *const xmlChar,
) -> *mut _xmlNs {
if node.is_null() || href.is_null() {
return ptr::null_mut();
}
let mut cur = node;
while !cur.is_null() {
let n = unsafe { &*cur };
let mut ns_def = n.nsDef;
while !ns_def.is_null() {
let ns = unsafe { &*ns_def };
if !ns.href.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
{
return ns_def;
}
ns_def = unsafe { (*ns_def).next };
}
cur = n.parent;
}
ptr::null_mut()
}
pub unsafe fn set_prop(
node: *mut _xmlNode,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if node.is_null() || name.is_null() {
return ptr::null_mut();
}
let n = unsafe { &mut *node };
let mut existing = n.properties;
while !existing.is_null() {
let attr = unsafe { &*existing };
if !attr.name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
{
if !attr.children.is_null() {
free_node_list(attr.children);
let attr_mut = existing as *mut _xmlAttr;
unsafe { (*attr_mut).children = ptr::null_mut() };
unsafe { (*attr_mut).last = ptr::null_mut() };
}
if !value.is_null() {
let text = new_text(value);
if !text.is_null() {
let attr_mut = existing as *mut _xmlAttr;
unsafe {
(*attr_mut).children = text;
(*attr_mut).last = text;
(*text).parent = existing as *mut _xmlNode;
(*text).doc = n.doc;
}
}
}
return existing;
}
existing = unsafe { (*existing).next };
}
let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
if attr.is_null() {
return ptr::null_mut();
}
unsafe {
(*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
(*attr).name = dup_xml_str(name);
(*attr).parent = node;
(*attr).doc = n.doc;
(*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
if !value.is_null() {
let text = new_text(value);
if !text.is_null() {
(*attr).children = text;
(*attr).last = text;
(*text).parent = attr as *mut _xmlNode;
(*text).doc = n.doc;
}
}
if n.properties.is_null() {
n.properties = attr;
} else {
let mut last = n.properties;
while !(*last).next.is_null() {
last = (*last).next;
}
(*last).next = attr;
(*attr).prev = last;
}
}
attr
}
pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
if node.is_null() || name.is_null() {
return ptr::null_mut();
}
let n = unsafe { &*node };
let mut cur = n.properties;
while !cur.is_null() {
let attr = unsafe { &*cur };
if !attr.name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
{
if !attr.children.is_null() {
let text = unsafe { &*attr.children };
if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
return dup_xml_str(text.content);
}
}
return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
}
cur = unsafe { (*cur).next };
}
ptr::null_mut()
}
pub unsafe fn get_ns_prop(
node: *mut _xmlNode,
name: *const xmlChar,
_name_space: *const xmlChar,
) -> *mut xmlChar {
get_prop(node, name)
}
pub unsafe fn set_ns_prop(
node: *mut _xmlNode,
_ns: *mut _xmlNs,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
set_prop(node, name, value)
}
pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
if attr.is_null() {
return -1;
}
let a = unsafe { &mut *attr };
let parent = a.parent;
if !parent.is_null() {
let p = unsafe { &mut *parent };
if p.properties == attr {
p.properties = a.next;
}
}
if !a.prev.is_null() {
unsafe { (*a.prev).next = a.next };
}
if !a.next.is_null() {
unsafe { (*a.next).prev = a.prev };
}
if !a.children.is_null() {
free_node_list(a.children);
}
if !a.name.is_null() {
allocator::xmlFree(a.name as *mut c_void);
}
allocator::xmlFree(attr as *mut c_void);
0
}
pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
if doc.is_null() {
return ptr::null_mut();
}
let d = unsafe { &*doc };
d.intSubset
}
pub unsafe fn new_dtd(
doc: *mut _xmlDoc,
name: *const xmlChar,
ExternalID: *const xmlChar,
SystemID: *const xmlChar,
) -> *mut _xmlDtd {
let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
if dtd.is_null() {
return ptr::null_mut();
}
unsafe {
(*dtd).type_ = XML_DTD_NODE as c_int;
(*dtd).name = dup_xml_str(name);
(*dtd).ExternalID = dup_xml_str(ExternalID);
(*dtd).SystemID = dup_xml_str(SystemID);
(*dtd).parent = doc;
(*dtd).doc = doc;
if !doc.is_null() {
if (*doc).intSubset.is_null() {
(*doc).intSubset = dtd;
}
}
}
dtd
}
unsafe fn free_dtd(dtd: *mut _xmlDtd) {
if dtd.is_null() {
return;
}
let d = unsafe { &mut *dtd };
if !d.name.is_null() {
allocator::xmlFree(d.name as *mut c_void);
}
if !d.ExternalID.is_null() {
allocator::xmlFree(d.ExternalID as *mut c_void);
}
if !d.SystemID.is_null() {
allocator::xmlFree(d.SystemID as *mut c_void);
}
if !d.children.is_null() {
free_node_list(d.children);
}
allocator::xmlFree(dtd as *mut c_void);
}
pub unsafe fn new_entity(
_doc: *mut _xmlDoc,
name: *const xmlChar,
etype: c_int,
ExternalID: *const xmlChar,
SystemID: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlEntity {
let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
if entity.is_null() {
return ptr::null_mut();
}
unsafe {
(*entity).type_ = XML_ENTITY_DECL as c_int;
(*entity).name = dup_xml_str(name);
(*entity).etype = etype;
(*entity).ExternalID = dup_xml_str(ExternalID);
(*entity).SystemID = dup_xml_str(SystemID);
(*entity).content = dup_xml_str(content);
(*entity).length = if content.is_null() {
0
} else {
crate::abi::exports_xml2::xmlStrlen(content)
};
(*entity).flags = 0;
(*entity).expandedSize = 0;
}
entity
}
pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
let _ = doc;
let _ = name;
ptr::null_mut()
}
pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
let _ = doc;
let _ = name;
ptr::null_mut()
}
#[cfg(test)]
mod tests {
use super::*;
use core::ffi::c_void;
fn c_str(s: &str) -> *const xmlChar {
let bytes = s.as_bytes();
let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
if !buf.is_null() {
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
*buf.add(bytes.len()) = 0;
}
}
buf as *const xmlChar
}
#[test]
fn test_new_free_doc() {
unsafe {
let doc = new_doc(ptr::null());
assert!(!doc.is_null());
assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
assert_eq!((*doc).standalone, -1);
assert_eq!((*doc).doc, doc);
assert!(!(*doc).version.is_null());
free_doc(doc);
}
}
#[test]
fn test_new_doc_with_version() {
unsafe {
let ver = c_str("2.0");
let doc = new_doc(ver);
assert!(!doc.is_null());
let doc_ver = (*doc).version;
assert!(!doc_ver.is_null());
assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
allocator::xmlFree(ver as *mut c_void);
free_doc(doc);
}
}
#[test]
fn test_new_node() {
unsafe {
let doc = new_doc(ptr::null());
let node = new_node(ptr::null_mut(), c_str("root"));
assert!(!node.is_null());
assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
assert!(!(*node).name.is_null());
free_node(node);
free_doc(doc);
}
}
#[test]
fn test_doc_set_root_element() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
let old = doc_set_root_element(doc, root);
assert!(old.is_null());
assert_eq!(doc_get_root_element(doc), root);
assert_eq!((*doc).children, root as *mut _xmlNode);
free_doc(doc);
}
}
#[test]
fn test_add_child_and_sibling() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
assert!(!child1.is_null());
assert_eq!((*child1).parent, root);
assert_eq!((*root).children, child1);
assert_eq!((*root).last, child1);
let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
assert!(!child2.is_null());
assert_eq!((*child2).parent, root);
assert_eq!((*child1).next, child2);
assert_eq!((*child2).prev, child1);
assert_eq!((*root).last, child2);
let sibling = new_node(ptr::null_mut(), c_str("sibling"));
add_sibling(child2, sibling);
assert_eq!((*child2).next, sibling);
assert_eq!((*sibling).prev, child2);
assert_eq!((*root).last, sibling);
free_doc(doc);
}
}
#[test]
fn test_unlink_node() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
unlink_node(child1);
assert!((*child1).parent.is_null());
assert!((*child1).prev.is_null());
assert!((*child1).next.is_null());
assert_eq!((*root).children, child2);
assert_eq!((*root).last, child2);
free_node(child1);
free_doc(doc);
}
}
#[test]
fn test_text_and_comment_nodes() {
unsafe {
let text = new_text(c_str("hello world"));
assert!(!text.is_null());
assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
assert!(!(*text).content.is_null());
free_node(text);
let comment = new_comment(c_str("my comment"));
assert!(!comment.is_null());
assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
free_node(comment);
let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
assert!(!pi.is_null());
assert_eq!((*pi).type_, XML_PI_NODE as c_int);
free_node(pi);
}
}
#[test]
fn test_set_and_get_prop() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let attr = set_prop(root, c_str("id"), c_str("42"));
assert!(!attr.is_null());
assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
let value = get_prop(root, c_str("id"));
assert!(!value.is_null());
assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
allocator::xmlFree(value as *mut c_void);
free_doc(doc);
}
}
#[test]
fn test_remove_prop() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
set_prop(root, c_str("a"), c_str("1"));
set_prop(root, c_str("b"), c_str("2"));
let value = get_prop(root, c_str("a"));
assert!(!value.is_null());
allocator::xmlFree(value as *mut c_void);
let attr = (*root).properties;
assert!(!attr.is_null());
let result = remove_prop(attr);
assert_eq!(result, 0);
let value2 = get_prop(root, c_str("a"));
assert!(value2.is_null());
free_doc(doc);
}
}
#[test]
fn test_namespace_operations() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
assert!(!ns.is_null());
assert!(!(*root).nsDef.is_null());
set_ns(root, ns);
assert_eq!((*root).ns, ns);
let found = search_ns(doc, root, c_str("ex"));
assert_eq!(found, ns);
let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
assert_eq!(found_href, ns);
free_doc(doc);
}
}
#[test]
fn test_new_dtd() {
unsafe {
let doc = new_doc(ptr::null());
let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
assert!(!dtd.is_null());
assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
assert_eq!(get_int_subset(doc), dtd);
free_doc(doc);
}
}
#[test]
fn test_copy_node_deep() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let child = new_child(root, ptr::null_mut(), c_str("child"));
let copy = copy_node(root, 1);
assert!(!copy.is_null());
assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
assert!(!(*copy).children.is_null());
assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
free_node(copy);
free_doc(doc);
}
}
#[test]
fn test_new_cdata_block() {
unsafe {
let doc = new_doc(ptr::null());
let content = c_str("some <cdata> content");
let cdata = new_cdata_block(doc, content, 20);
assert!(!cdata.is_null());
assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
free_node(cdata);
free_doc(doc);
}
}
#[test]
fn test_null_handling() {
unsafe {
assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
assert!(new_node(ptr::null_mut(), ptr::null()).is_null() == false); free_node(ptr::null_mut()); free_doc(ptr::null_mut()); assert!(unlink_node(ptr::null_mut()) == ()); assert!(add_child(ptr::null_mut(), ptr::null_mut()).is_null());
assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
free_doc(doc);
}
}
}