use core::ffi::c_void;
use core::ptr;
use std::os::raw::{c_char, c_int, c_long, c_ulong};
use crate::abi::allocator;
use crate::abi::constants::*;
use crate::abi::structs::*;
use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
use crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT;
use crate::abi::types::xmlElementType::*;
use crate::abi::types::*;
use crate::xml::io;
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::xmlMallocImpl(1) as *mut xmlChar };
if !buf.is_null() {
unsafe { *buf = 0 };
}
return buf;
}
let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
if !buf.is_null() {
unsafe {
ptr::copy_nonoverlapping(str, buf, len + 1);
}
}
buf
}
#[allow(dead_code)]
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 const 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_USERBUILT as c_int;
(*doc).compression = -1; (*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);
}
crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
doc
}
pub unsafe fn free_doc(doc: *mut _xmlDoc) {
if doc.is_null() {
return;
}
crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
let d = unsafe { &mut *doc };
let dict = d.dict;
let mut ext_subset = d.extSubset;
let int_subset = d.intSubset;
if !ext_subset.is_null() && ext_subset == int_subset {
ext_subset = ptr::null_mut();
}
if !ext_subset.is_null() {
unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
d.extSubset = ptr::null_mut();
free_dtd(ext_subset);
}
if !int_subset.is_null() {
unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
d.intSubset = ptr::null_mut();
free_dtd(int_subset);
}
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::xmlFreeImpl(d.version as *mut c_void);
}
if !d.encoding.is_null() {
allocator::xmlFreeImpl(d.encoding as *mut c_void);
}
if !d.URL.is_null() {
allocator::xmlFreeImpl(d.URL as *mut c_void);
}
allocator::xmlFreeImpl(doc as *mut c_void);
if !dict.is_null() {
crate::abi::exports_xml2::xmlDictFree(dict);
}
}
unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
if node.is_null() {
return;
}
let parent = (*node).parent;
if parent.is_null() {
return;
}
if (*node).prev.is_null() {
(*parent).children = (*node).next;
} else {
(*(*node).prev).next = (*node).next;
}
if (*node).next.is_null() {
(*parent).last = (*node).prev;
} else {
(*(*node).next).prev = (*node).prev;
}
(*node).next = ptr::null_mut();
(*node).prev = ptr::null_mut();
(*node).parent = ptr::null_mut();
}
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 !d.intSubset.is_null() {
let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
if !dtd_copy.is_null() {
(*new_doc).intSubset = dtd_copy;
}
}
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_long {
unsafe { get_line_no_internal(node, 0) }
}
unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
if depth >= 5 {
return -1;
}
if node.is_null() {
return -1;
}
let n = unsafe { &*node };
if n.type_ == XML_ELEMENT_NODE as c_int
|| n.type_ == XML_TEXT_NODE as c_int
|| n.type_ == XML_COMMENT_NODE as c_int
|| n.type_ == XML_PI_NODE as c_int
{
if n.line == 65535 {
if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
let r = unsafe { get_line_no_internal(n.children, depth + 1) };
if r != -1 {
return r;
}
}
if !n.next.is_null() {
let r = unsafe { get_line_no_internal(n.next, depth + 1) };
if r != -1 {
return r;
}
}
if !n.prev.is_null() {
let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
if r != -1 {
return r;
}
}
}
n.line as c_long
} else if !n.prev.is_null()
&& (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
|| unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
|| unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
|| unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
{
unsafe { get_line_no_internal(n.prev, depth + 1) }
} else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
unsafe { get_line_no_internal(n.parent, depth + 1) }
} else {
-1
}
}
pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
if node.is_null() {
return ptr::null_mut();
}
let typ = (*node).type_;
let mut result: Vec<u8> = Vec::new();
match typ {
t if t == XML_TEXT_NODE as c_int
|| t == XML_CDATA_SECTION_NODE as c_int
|| t == XML_COMMENT_NODE as c_int
|| t == XML_PI_NODE as c_int =>
{
if !(*node).content.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
result
.extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
} else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
let mut child = (*node).children;
while !child.is_null() {
if !(*child).content.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
result.extend_from_slice(core::slice::from_raw_parts(
(*child).content,
len as usize,
));
}
child = (*child).next;
}
}
}
t if t == XML_ATTRIBUTE_NODE as c_int => {
if !(*node).children.is_null() {
let child = (*node).children;
if !(*child).content.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
result.extend_from_slice(core::slice::from_raw_parts(
(*child).content,
len as usize,
));
}
}
}
t if t == XML_ENTITY_REF_NODE as c_int => {
let name = (*node).name;
if !name.is_null() && !(*node).doc.is_null() {
let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
if !ent.is_null() && !(*ent).content.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
result.extend_from_slice(core::slice::from_raw_parts(
(*ent).content,
len as usize,
));
}
}
}
t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
let root = doc_get_root_element(node as *mut _xmlDoc);
if !root.is_null() {
let sub = node_get_content(root);
if !sub.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen(sub);
result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
allocator::xmlFreeImpl(sub as *mut c_void);
}
}
}
_ => {
let mut child = (*node).children;
while !child.is_null() {
let ctype = (*child).type_;
if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
if !(*child).content.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
result.extend_from_slice(core::slice::from_raw_parts(
(*child).content,
len as usize,
));
}
} else if ctype == XML_ENTITY_REF_NODE as c_int
|| ctype == XML_ELEMENT_NODE as c_int
{
let sub = node_get_content(child);
if !sub.is_null() {
let len = crate::abi::exports_xml2::xmlStrlen(sub);
result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
allocator::xmlFreeImpl(sub as *mut c_void);
}
}
child = (*child).next;
}
}
}
let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
if buf.is_null() {
return ptr::null_mut();
}
if !result.is_empty() {
ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
}
*buf.add(result.len()) = 0;
buf
}
pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
if name.is_null() {
return ptr::null_mut();
}
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;
}
}
crate::abi::data_globals::register_node_hook(node);
node
}
pub unsafe fn free_node(node: *mut _xmlNode) {
if node.is_null() {
return;
}
let n = unsafe { &mut *node };
if n.type_ == XML_DTD_NODE as c_int {
free_dtd(node as *mut _xmlDtd);
return;
} else if n.type_ == XML_NAMESPACE_DECL as c_int {
free_ns(node as *mut _xmlNs);
return;
} else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
free_prop(node as *mut _xmlAttr);
return;
} else if n.type_ == XML_ELEMENT_DECL as c_int {
crate::xml::dtd::free_element(node as *mut _xmlElement);
return;
} else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
return;
} else if n.type_ == XML_ENTITY_DECL as c_int {
crate::xml::entities::free_entity(node as *mut _xmlEntity);
return;
}
crate::abi::data_globals::deregister_node_hook(node);
let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
if is_element && !n.properties.is_null() {
free_prop_list(n.properties);
}
if is_element && !n.nsDef.is_null() {
free_ns_list(n.nsDef);
}
if !n.name.is_null() {
allocator::xmlFreeImpl(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
{
let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
if n.content as *const c_void != inline_addr {
allocator::xmlFreeImpl(n.content as *mut c_void);
}
}
}
allocator::xmlFreeImpl(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 };
let t = unsafe { (*cur).type_ };
if t == XML_DTD_NODE as c_int {
unsafe {
(*cur).prev = ptr::null_mut();
(*cur).next = ptr::null_mut();
}
cur = next;
continue;
}
if t != XML_ENTITY_REF_NODE as c_int && !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 };
free_prop(cur);
cur = next;
}
}
unsafe fn free_prop(prop: *mut _xmlAttr) {
if prop.is_null() {
return;
}
if !unsafe { (*prop).children }.is_null() {
free_node_list(unsafe { (*prop).children });
}
if !unsafe { (*prop).name }.is_null() {
allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
}
allocator::xmlFreeImpl(prop as *mut c_void);
}
unsafe fn free_ns_list(ns: *mut _xmlNs) {
let mut cur = ns;
while !cur.is_null() {
let next = unsafe { (*cur).next };
free_ns(cur);
cur = next;
}
}
unsafe fn free_ns(ns: *mut _xmlNs) {
if ns.is_null() {
return;
}
if !unsafe { (*ns).href }.is_null() {
allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
}
if !unsafe { (*ns).prefix }.is_null() {
allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
}
allocator::xmlFreeImpl(ns as *mut c_void);
}
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);
if n.type_ == XML_ELEMENT_NODE as c_int {
(*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;
let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
if is_element && !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 is_element && !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() {
let mut child = (*new_node).children;
let mut last_child = child;
while !child.is_null() {
(*child).parent = new_node;
(*child).doc = (*new_node).doc;
propagate_doc(child, (*new_node).doc);
if (*child).next.is_null() {
last_child = child;
}
child = (*child).next;
}
(*new_node).last = last_child;
}
}
}
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;
if (*cur).type_ == XML_ELEMENT_NODE as c_int {
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 add_sibling_before(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 = c.prev;
e.next = cur;
if !c.prev.is_null() {
unsafe { (*c.prev).next = elem };
}
c.prev = elem;
let parent = c.parent;
if !parent.is_null() && unsafe { (*parent).children } == cur {
unsafe { (*parent).children = elem };
}
let doc = c.doc;
if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
unsafe { (*doc).children = 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::xmlMallocImpl(1) as *mut xmlChar;
if !empty.is_null() {
*empty = 0;
}
empty
} else {
dup_xml_str(content)
};
(*node).line = 0;
}
crate::abi::data_globals::register_node_hook(node);
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;
}
crate::abi::data_globals::register_node_hook(node);
node
}
pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
if name.is_null() {
return ptr::null_mut();
}
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;
}
crate::abi::data_globals::register_node_hook(node);
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).doc = doc;
if !content.is_null() && len > 0 {
(*node).content = allocator::xmlMallocImpl((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::xmlMallocImpl(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::xmlMallocImpl((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;
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;
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;
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::xmlFreeImpl(a.name as *mut c_void);
}
allocator::xmlFreeImpl(attr as *mut c_void);
0
}
pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
if node.is_null() || name.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).properties };
while !cur.is_null() {
let attr = unsafe { &*cur };
if !attr.name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
&& attr.ns.is_null()
{
return cur;
}
cur = unsafe { (*cur).next };
}
ptr::null_mut()
}
pub unsafe fn has_ns_prop(
node: *mut _xmlNode,
name: *const xmlChar,
name_space: *const xmlChar,
) -> *mut _xmlAttr {
if node.is_null() || name.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).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 name_space.is_null() {
if attr.ns.is_null() {
return cur;
}
} else if !attr.ns.is_null()
&& !(*attr.ns).href.is_null()
&& unsafe {
crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
}
{
return cur;
}
}
cur = unsafe { (*cur).next };
}
ptr::null_mut()
}
pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
let attr = unsafe { has_prop(node, name) };
if attr.is_null() {
return -1;
}
unsafe { remove_prop(attr) }
}
pub unsafe fn unset_ns_prop(
node: *mut _xmlNode,
name: *const xmlChar,
name_space: *const xmlChar,
) -> c_int {
let attr = unsafe { has_ns_prop(node, name, name_space) };
if attr.is_null() {
return -1;
}
unsafe { remove_prop(attr) }
}
pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).children };
while !cur.is_null() {
if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
return cur;
}
cur = unsafe { (*cur).next };
}
ptr::null_mut()
}
pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).last };
while !cur.is_null() {
if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
return cur;
}
cur = unsafe { (*cur).prev };
}
ptr::null_mut()
}
pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).next };
while !cur.is_null() {
if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
return cur;
}
cur = unsafe { (*cur).next };
}
ptr::null_mut()
}
pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
if node.is_null() {
return ptr::null_mut();
}
let mut cur = unsafe { (*node).prev };
while !cur.is_null() {
if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
return cur;
}
cur = unsafe { (*cur).prev };
}
ptr::null_mut()
}
pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
if node.is_null() {
return 0;
}
let mut cur = unsafe { (*node).children };
let mut count: c_ulong = 0;
while !cur.is_null() {
if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
count += 1;
}
cur = unsafe { (*cur).next };
}
count
}
pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
if node.is_null() || str.is_null() || num <= 0 {
return -1;
}
let cur = unsafe { &mut *node };
if cur.content.is_null() {
let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
if p.is_null() {
return -1;
}
unsafe {
ptr::copy_nonoverlapping(str, p, num as usize);
*p.add(num as usize) = 0;
}
cur.content = p;
return 0;
}
let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
let p = unsafe {
allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
as *mut xmlChar
};
if p.is_null() {
return -1;
}
unsafe {
ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
*p.add(old_len + num as usize) = 0;
}
cur.content = p;
0
}
pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
if text.is_null() || ntext.is_null() {
return ptr::null_mut();
}
if unsafe { (*ntext).content.is_null() } {
unsafe { free_node(ntext) };
return text;
}
let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
return ptr::null_mut();
}
unsafe { free_node(ntext) };
text
}
pub const 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() && (*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 };
let d = &mut *dtd;
if !d.children.is_null() {
let mut c = d.children;
while !c.is_null() {
let next = (*c).next;
let t = (*c).type_;
if t != XML_ELEMENT_DECL as c_int
&& t != XML_ATTRIBUTE_DECL as c_int
&& t != XML_ENTITY_DECL as c_int
{
unlink_node_internal(c, ptr::null_mut());
free_node(c);
}
c = next;
}
}
if !d.name.is_null() {
allocator::xmlFreeImpl(d.name as *mut c_void);
}
if !d.ExternalID.is_null() {
allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
}
if !d.SystemID.is_null() {
allocator::xmlFreeImpl(d.SystemID as *mut c_void);
}
unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
}
unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
crate::xml::dtd::free_element(payload as *mut _xmlElement);
}
unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
}
unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
crate::xml::entities::free_entity(payload as *mut _xmlEntity);
}
if !d.notations.is_null() {
crate::xml::hash::hash_free(
d.notations as *mut crate::xml::hash::HashTable,
Some(free_notation_wrapper),
);
d.notations = ptr::null_mut();
}
if !d.elements.is_null() {
crate::xml::hash::hash_free(
d.elements as *mut crate::xml::hash::HashTable,
Some(free_element_wrapper),
);
d.elements = ptr::null_mut();
}
if !d.attributes.is_null() {
crate::xml::hash::hash_free(
d.attributes as *mut crate::xml::hash::HashTable,
Some(free_attribute_wrapper),
);
d.attributes = ptr::null_mut();
}
if !d.entities.is_null() {
crate::xml::hash::hash_free(
d.entities as *mut crate::xml::hash::HashTable,
Some(free_entity_wrapper),
);
d.entities = ptr::null_mut();
}
if !d.pentities.is_null() {
crate::xml::hash::hash_free(
d.pentities as *mut crate::xml::hash::HashTable,
Some(free_entity_wrapper),
);
d.pentities = ptr::null_mut();
}
allocator::xmlFreeImpl(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 {
crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
}
pub unsafe fn add_doc_entity(
doc: *mut _xmlDoc,
name: *const xmlChar,
etype: c_int,
ExternalID: *const xmlChar,
SystemID: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlEntity {
if doc.is_null() || name.is_null() {
return ptr::null_mut();
}
unsafe {
let mut dtd = (*doc).intSubset;
if dtd.is_null() {
dtd = new_dtd(
doc,
c"internal".as_ptr() as *const xmlChar,
ptr::null(),
ptr::null(),
);
if dtd.is_null() {
return ptr::null_mut();
}
}
crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
}
}
pub unsafe fn add_dtd_entity(
doc: *mut _xmlDoc,
name: *const xmlChar,
etype: c_int,
ExternalID: *const xmlChar,
SystemID: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlEntity {
if doc.is_null() || name.is_null() {
return ptr::null_mut();
}
unsafe {
let mut dtd = (*doc).extSubset;
if dtd.is_null() {
dtd = new_dtd(
doc,
c"internal".as_ptr() as *const xmlChar,
ptr::null(),
ptr::null(),
);
if dtd.is_null() {
return ptr::null_mut();
}
(*doc).extSubset = dtd;
}
crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
}
}
pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
if doc.is_null() || name.is_null() {
return ptr::null_mut();
}
unsafe {
if !(*doc).intSubset.is_null() {
let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
if !e.is_null() {
return e;
}
}
if !(*doc).extSubset.is_null() {
return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
}
ptr::null_mut()
}
}
pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
}
const ENTITY_LT: &[xmlChar] = b"<";
const ENTITY_GT: &[xmlChar] = b">";
const ENTITY_AMP: &[xmlChar] = b"&";
const ENTITY_QUOT: &[xmlChar] = b""";
#[allow(dead_code)]
const ENTITY_APOS: &[xmlChar] = b"'";
const INDENT: &[xmlChar] = b" ";
const MAX_INDENT: c_int = 60;
pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
if buf.is_null() || content.is_null() || len <= 0 {
return;
}
let mut i: c_int = 0;
while i < len {
let ch = unsafe { *content.add(i as usize) };
if ch == b']'
&& i + 2 < len
&& unsafe { *content.add(i as usize + 1) == b']' }
&& unsafe { *content.add(i as usize + 2) == b'>' }
{
io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
i += 3;
continue;
}
match ch {
b'<' => {
io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
}
b'&' => {
io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
}
b'>' => {
io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
}
b'\r' => {
io::buf_add(buf, b" " as *const u8, 5);
}
0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
let hex = format!("&#x{:X};", ch);
io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
}
_ => {
io::buf_add(buf, &ch as *const u8, 1);
}
}
i += 1;
}
}
pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
if buf.is_null() || value.is_null() {
return;
}
let len = xml_strlen(value);
let mut i: c_int = 0;
while i < len {
let ch = unsafe { *value.add(i as usize) };
match ch {
b'\n' => {
io::buf_add(buf, b" " as *const u8, 5);
}
b'\r' => {
io::buf_add(buf, b" " as *const u8, 5);
}
b'\t' => {
io::buf_add(buf, b"	" as *const u8, 4);
}
b'<' => {
io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
}
b'&' => {
io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
}
b'"' => {
io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
}
b'>' => {
io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
}
_ => {
io::buf_add(buf, &ch as *const u8, 1);
}
}
i += 1;
}
}
unsafe fn write_indent(
buf: *mut _xmlBuffer,
level: c_int,
indent: *const xmlChar,
indent_len: c_int,
) {
if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
return;
}
let indent_nr = MAX_INDENT / indent_len;
let mut lvl = level;
if lvl > indent_nr {
lvl = indent_nr;
}
for _ in 0..lvl {
io::buf_add(buf, indent, indent_len);
}
}
unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
if node.is_null() {
return false;
}
let n = unsafe { &*node };
if n.name.is_null() {
return false;
}
c_str_eq_bytes(n.name, b"textnoenc")
}
const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
let mut i = 0usize;
while i < b.len() {
if unsafe { *s.add(i) } != b[i] {
return false;
}
i += 1;
}
unsafe { *s.add(i) == 0 }
}
#[derive(Clone, Copy)]
struct DumpState {
format: c_int,
saved: c_int,
unformatted: *mut _xmlNode,
indent: *const xmlChar,
indent_len: c_int,
no_decl: c_int,
encoding: *const xmlChar,
}
impl DumpState {
const fn new(format: c_int) -> Self {
let f = if format != 0 { 1 } else { 0 };
DumpState {
format: f,
saved: f,
unformatted: ptr::null_mut(),
indent: INDENT.as_ptr(),
indent_len: INDENT.len() as c_int,
no_decl: 0,
encoding: ptr::null(),
}
}
const unsafe fn with_indent_enc(
format: c_int,
indent: *const xmlChar,
no_decl: c_int,
encoding: *const xmlChar,
) -> Self {
let f = if format != 0 { 1 } else { 0 };
let (ptr, len) = if indent.is_null() {
(INDENT.as_ptr(), INDENT.len() as c_int)
} else {
let mut n = 0i32;
while unsafe { *indent.add(n as usize) } != 0 {
n += 1;
}
(indent, n)
};
DumpState {
format: f,
saved: f,
unformatted: ptr::null_mut(),
indent: ptr,
indent_len: len,
no_decl,
encoding,
}
}
}
unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
let n = unsafe { &*node };
if !n.ns.is_null() {
let ns = unsafe { &*n.ns };
if !ns.prefix.is_null() {
io::buf_cat(buf, ns.prefix);
io::buf_ccat(buf, b':');
}
}
if !n.name.is_null() {
io::buf_cat(buf, n.name);
}
}
unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
if cur.is_null() || buf.is_null() {
return;
}
let ns = unsafe { &*cur };
if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
return;
}
io::buf_ccat(buf, b' ');
if !ns.prefix.is_null() {
io::buf_add(buf, b"xmlns:" as *const u8, 6);
io::buf_cat(buf, ns.prefix);
} else {
io::buf_add(buf, b"xmlns" as *const u8, 5);
}
io::buf_add(buf, b"=\"" as *const u8, 2);
serialize_attr_value(buf, ns.href);
io::buf_ccat(buf, b'"');
}
}
unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
if cur.is_null() || buf.is_null() {
return;
}
io::buf_ccat(buf, b' ');
let a = unsafe { &*cur };
if !a.ns.is_null() {
let ans = unsafe { &*a.ns };
if !ans.prefix.is_null() {
io::buf_cat(buf, ans.prefix);
io::buf_ccat(buf, b':');
}
}
if !a.name.is_null() {
io::buf_cat(buf, a.name);
}
io::buf_add(buf, b"=\"" as *const u8, 2);
let mut child = a.children;
while !child.is_null() {
let ct = unsafe { (*child).type_ };
if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
serialize_attr_value(buf, unsafe { (*child).content });
} else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
io::buf_ccat(buf, b'&');
io::buf_cat(buf, unsafe { (*child).name });
io::buf_ccat(buf, b';');
}
child = unsafe { (*child).next };
}
io::buf_ccat(buf, b'"');
}
unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
let n = unsafe { &*nota };
io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
if !n.name.is_null() {
io::buf_cat(buf, n.name);
}
if !n.PublicID.is_null() {
io::buf_add(buf, b" PUBLIC " as *const u8, 8);
write_quoted_string(buf, n.PublicID);
if !n.SystemID.is_null() {
io::buf_ccat(buf, b' ');
write_quoted_string(buf, n.SystemID);
}
} else {
io::buf_add(buf, b" SYSTEM " as *const u8, 8);
write_quoted_string(buf, n.SystemID);
}
io::buf_add(buf, b" >\n" as *const u8, 4);
}
unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
use crate::abi::types::xmlElementContentOccur::*;
if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
io::buf_ccat(buf, b'?');
} else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
io::buf_ccat(buf, b'*');
} else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
io::buf_ccat(buf, b'+');
}
}
unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
use crate::abi::types::xmlElementContentOccur::*;
use crate::abi::types::xmlElementContentType::*;
if content.is_null() {
return;
}
io::buf_ccat(buf, b'(');
let mut cur = content;
loop {
if cur.is_null() {
return;
}
let c = unsafe { &*cur };
match c.type_ {
t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
io::buf_add(buf, b"#PCDATA" as *const u8, 7);
}
t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
if !c.prefix.is_null() {
io::buf_cat(buf, c.prefix);
io::buf_ccat(buf, b':');
}
if !c.name.is_null() {
io::buf_cat(buf, c.name);
}
}
t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
if cur != content
&& !c.parent.is_null()
&& (c.type_ != unsafe { (*c.parent).type_ }
|| c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
{
io::buf_ccat(buf, b'(');
}
cur = c.c1;
continue;
}
_ => {}
}
while cur != content {
let ccur = unsafe { &*cur };
let parent = ccur.parent;
if parent.is_null() {
return;
}
let p = unsafe { &*parent };
if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
|| ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
&& (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
{
io::buf_ccat(buf, b')');
}
dump_element_occur(buf, ccur.ocur);
if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
io::buf_add(buf, b" , " as *const u8, 3);
} else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
io::buf_add(buf, b" | " as *const u8, 3);
}
if cur == p.c1 {
cur = p.c2;
break;
}
cur = parent;
}
if cur == content {
break;
}
}
io::buf_ccat(buf, b')');
let cc = unsafe { &*content };
dump_element_occur(buf, cc.ocur);
}
unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
use crate::abi::types::xmlElementTypeVal::*;
let e = unsafe { &*elem };
io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
if !e.prefix.is_null() {
io::buf_cat(buf, e.prefix);
io::buf_ccat(buf, b':');
}
if !e.name.is_null() {
io::buf_cat(buf, e.name);
}
io::buf_ccat(buf, b' ');
match e.etype {
t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
io::buf_add(buf, b"EMPTY" as *const u8, 5);
}
t if t == XML_ELEMENT_TYPE_ANY as c_int => {
io::buf_add(buf, b"ANY" as *const u8, 3);
}
t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
dump_element_content(buf, e.content);
}
_ => {}
}
io::buf_add(buf, b">\n" as *const u8, 2);
}
unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
let mut e = cur;
while !e.is_null() {
let en = unsafe { &*e };
if !en.name.is_null() {
io::buf_cat(buf, en.name);
}
if !en.next.is_null() {
io::buf_add(buf, b" | " as *const u8, 3);
}
e = en.next;
}
io::buf_ccat(buf, b')');
}
unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
use crate::abi::types::xmlAttributeDefault::*;
use crate::abi::types::xmlAttributeType::*;
let a = unsafe { &*attr };
io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
if !a.elem.is_null() {
io::buf_cat(buf, a.elem);
}
io::buf_ccat(buf, b' ');
if !a.prefix.is_null() {
io::buf_cat(buf, a.prefix);
io::buf_ccat(buf, b':');
}
if !a.name.is_null() {
io::buf_cat(buf, a.name);
}
match a.atype {
t if t == XML_ATTRIBUTE_CDATA as c_int => {
io::buf_add(buf, b" CDATA" as *const u8, 6);
}
t if t == XML_ATTRIBUTE_ID as c_int => {
io::buf_add(buf, b" ID" as *const u8, 3);
}
t if t == XML_ATTRIBUTE_IDREF as c_int => {
io::buf_add(buf, b" IDREF" as *const u8, 6);
}
t if t == XML_ATTRIBUTE_IDREFS as c_int => {
io::buf_add(buf, b" IDREFS" as *const u8, 7);
}
t if t == XML_ATTRIBUTE_ENTITY as c_int => {
io::buf_add(buf, b" ENTITY" as *const u8, 7);
}
t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
io::buf_add(buf, b" ENTITIES" as *const u8, 9);
}
t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
}
t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
}
t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
io::buf_add(buf, b" (" as *const u8, 2);
dump_enumeration(buf, a.tree);
}
t if t == XML_ATTRIBUTE_NOTATION as c_int => {
io::buf_add(buf, b" NOTATION (" as *const u8, 11);
dump_enumeration(buf, a.tree);
}
_ => {}
}
match a.def {
t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
}
t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
}
t if t == XML_ATTRIBUTE_FIXED as c_int => {
io::buf_add(buf, b" #FIXED" as *const u8, 7);
}
_ => {}
}
if !a.defaultValue.is_null() {
io::buf_add(buf, b" \"" as *const u8, 2);
serialize_attr_value(buf, a.defaultValue);
io::buf_ccat(buf, b'"');
}
io::buf_add(buf, b">\n" as *const u8, 2);
}
unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
if buf.is_null() {
return;
}
io::buf_ccat(buf, b'"');
if !str.is_null() {
let mut i = 0usize;
while unsafe { *str.add(i) != 0 } {
let ch = unsafe { *str.add(i) };
if ch == b'"' {
io::buf_add(buf, b""" as *const u8, 6);
} else {
io::buf_add(buf, &ch as *const u8, 1);
}
i += 1;
}
}
io::buf_ccat(buf, b'"');
}
unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
use crate::abi::types::xmlEntityType::*;
let e = unsafe { &*ent };
if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
|| e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
{
io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
} else {
io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
}
if !e.name.is_null() {
io::buf_cat(buf, e.name);
}
io::buf_ccat(buf, b' ');
if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
|| e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
|| e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
{
if !e.ExternalID.is_null() {
io::buf_add(buf, b"PUBLIC " as *const u8, 7);
write_quoted_string(buf, e.ExternalID);
io::buf_ccat(buf, b' ');
} else {
io::buf_add(buf, b"SYSTEM " as *const u8, 7);
}
write_quoted_string(buf, e.SystemID);
}
if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
io::buf_add(buf, b" NDATA " as *const u8, 7);
if !e.orig.is_null() {
io::buf_cat(buf, e.orig);
} else if !e.content.is_null() {
io::buf_cat(buf, e.content);
}
}
if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
|| e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
{
if !e.orig.is_null() {
write_quoted_string(buf, e.orig);
} else {
io::buf_ccat(buf, b'"');
if !e.content.is_null() {
let mut i = 0usize;
while unsafe { *e.content.add(i) != 0 } {
let ch = unsafe { *e.content.add(i) };
match ch {
b'"' => io::buf_add(buf, b""" as *const u8, 6),
b'%' => io::buf_add(buf, b"%" as *const u8, 6),
_ => io::buf_add(buf, &ch as *const u8, 1),
};
i += 1;
}
}
io::buf_ccat(buf, b'"');
}
}
io::buf_add(buf, b">\n" as *const u8, 2);
}
unsafe fn dtd_dump_output(
buf: *mut _xmlBuffer,
cur: *mut _xmlNode,
state: &mut DumpState,
level: &mut c_int,
) {
let dtd = cur as *mut _xmlDtd;
let d = unsafe { &*dtd };
io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
if !d.name.is_null() {
io::buf_cat(buf, d.name);
}
if !d.ExternalID.is_null() {
io::buf_add(buf, b" PUBLIC " as *const u8, 8);
write_quoted_string(buf, d.ExternalID);
io::buf_ccat(buf, b' ');
write_quoted_string(buf, d.SystemID);
} else if !d.SystemID.is_null() {
io::buf_add(buf, b" SYSTEM " as *const u8, 8);
write_quoted_string(buf, d.SystemID);
}
if d.entities.is_null()
&& d.elements.is_null()
&& d.attributes.is_null()
&& d.notations.is_null()
&& d.pentities.is_null()
{
io::buf_ccat(buf, b'>');
return;
}
io::buf_add(buf, b" [\n" as *const u8, 3);
let format = state.format;
let lvl = *level;
state.format = 0;
*level = -1;
if !d.notations.is_null() {
crate::xml::hash::hash_scan(
d.notations as *mut crate::xml::hash::HashTable,
Some(dump_notation_decl_cb),
buf as *mut c_void,
);
}
if !d.elements.is_null() {
crate::xml::hash::hash_scan(
d.elements as *mut crate::xml::hash::HashTable,
Some(dump_element_decl_cb),
buf as *mut c_void,
);
}
if !d.attributes.is_null() {
crate::xml::hash::hash_scan(
d.attributes as *mut crate::xml::hash::HashTable,
Some(dump_attribute_decl_cb),
buf as *mut c_void,
);
}
if !d.entities.is_null() {
crate::xml::hash::hash_scan(
d.entities as *mut crate::xml::hash::HashTable,
Some(dump_entity_decl_cb),
buf as *mut c_void,
);
}
if !d.pentities.is_null() {
crate::xml::hash::hash_scan(
d.pentities as *mut crate::xml::hash::HashTable,
Some(dump_entity_decl_cb),
buf as *mut c_void,
);
}
state.format = format;
*level = lvl;
io::buf_add(buf, b"]>" as *const u8, 2);
}
unsafe extern "C" fn dump_notation_decl_cb(
payload: *mut c_void,
data: *mut c_void,
_name: *const crate::abi::types::xmlChar,
) {
if !payload.is_null() && !data.is_null() {
dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
}
}
unsafe extern "C" fn dump_element_decl_cb(
payload: *mut c_void,
data: *mut c_void,
_name: *const crate::abi::types::xmlChar,
) {
if !payload.is_null() && !data.is_null() {
dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
}
}
unsafe extern "C" fn dump_attribute_decl_cb(
payload: *mut c_void,
data: *mut c_void,
_name: *const crate::abi::types::xmlChar,
) {
if !payload.is_null() && !data.is_null() {
dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
}
}
unsafe extern "C" fn dump_entity_decl_cb(
payload: *mut c_void,
data: *mut c_void,
_name: *const crate::abi::types::xmlChar,
) {
if !payload.is_null() && !data.is_null() {
dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
}
}
unsafe fn doc_content_dump_output(
buf: *mut _xmlBuffer,
cur: *mut _xmlNode,
state: &mut DumpState,
level: &mut c_int,
) {
let doc = cur as *mut _xmlDoc;
let d = unsafe { &*doc };
if state.no_decl == 0 {
io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
if !d.version.is_null() {
io::buf_cat(buf, d.version);
} else {
io::buf_add(buf, b"1.0" as *const u8, 3);
}
io::buf_ccat(buf, b'"');
let enc = if state.encoding.is_null() {
d.encoding
} else {
state.encoding
};
if !enc.is_null() {
io::buf_add(buf, b" encoding=\"" as *const u8, 11);
io::buf_cat(buf, enc);
io::buf_ccat(buf, b'"');
}
match d.standalone {
0 => {
io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
}
1 => {
io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
}
_ => {}
}
io::buf_add(buf, b"?>\n" as *const u8, 3);
}
if !d.intSubset.is_null() {
let mut in_chain = false;
let mut c = d.children;
while !c.is_null() {
if c as *mut c_void == d.intSubset as *mut c_void {
in_chain = true;
break;
}
c = unsafe { (*c).next };
}
if !in_chain {
let mut lvl = 0;
dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
io::buf_ccat(buf, b'\n');
}
}
if !d.children.is_null() {
let mut child = d.children;
while !child.is_null() {
*level = 0;
node_dump_internal(buf, child, child, cur, state, level);
let ct = unsafe { (*child).type_ };
if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
io::buf_ccat(buf, b'\n');
}
child = unsafe { (*child).next };
}
}
}
unsafe fn node_dump_internal(
buf: *mut _xmlBuffer,
cur: *mut _xmlNode,
root: *mut _xmlNode,
parent: *mut _xmlNode,
state: &mut DumpState,
level: &mut c_int,
) {
if cur.is_null() || buf.is_null() {
return;
}
let n = unsafe { &*cur };
match n.type_ {
t if t == XML_ELEMENT_NODE as c_int => {
if cur != root && state.format == 1 {
write_indent(buf, *level, state.indent, state.indent_len);
}
if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
let mut sub = DumpState::new(state.format);
let mut sub_level = *level;
node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
return;
}
io::buf_ccat(buf, b'<');
write_qname(buf, cur);
let mut nsdef = n.nsDef;
while !nsdef.is_null() {
ns_dump_output(buf, nsdef);
nsdef = unsafe { (*nsdef).next };
}
let mut attr = n.properties;
while !attr.is_null() {
attr_dump_output(buf, attr);
attr = unsafe { (*attr).next };
}
if n.children.is_null() {
io::buf_add(buf, b"/>" as *const u8, 2);
} else {
if state.format == 1 {
let mut tmp = n.children;
while !tmp.is_null() {
let tt = unsafe { (*tmp).type_ };
if tt == XML_TEXT_NODE as c_int
|| tt == XML_CDATA_SECTION_NODE as c_int
|| tt == XML_ENTITY_REF_NODE as c_int
{
state.format = 0;
state.unformatted = cur;
break;
}
tmp = unsafe { (*tmp).next };
}
}
io::buf_ccat(buf, b'>');
if state.format == 1 {
io::buf_ccat(buf, b'\n');
}
if *level >= 0 {
*level += 1;
}
let mut child = n.children;
while !child.is_null() {
node_dump_internal(buf, child, root, cur, state, level);
if state.format == 1 {
let ct = unsafe { (*child).type_ };
if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
io::buf_ccat(buf, b'\n');
}
}
child = unsafe { (*child).next };
}
if *level > 0 {
*level -= 1;
}
if state.format == 1 {
write_indent(buf, *level, state.indent, state.indent_len);
}
io::buf_add(buf, b"</" as *const u8, 2);
write_qname(buf, cur);
io::buf_ccat(buf, b'>');
if cur == state.unformatted {
state.format = state.saved;
state.unformatted = ptr::null_mut();
}
}
}
t if t == XML_TEXT_NODE as c_int => {
if !n.content.is_null() {
if is_noenc_text(cur) {
io::buf_cat(buf, n.content);
} else {
serialize_text(buf, n.content, xml_strlen(n.content));
}
} else if !n.children.is_null() {
let c = node_get_content(cur);
if !c.is_null() {
if is_noenc_text(cur) {
io::buf_cat(buf, c);
} else {
serialize_text(buf, c, xml_strlen(c));
}
allocator::xmlFreeImpl(c as *mut c_void);
}
}
}
t if t == XML_CDATA_SECTION_NODE as c_int => {
if n.content.is_null() || unsafe { *n.content == 0 } {
io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
} else {
let len = xml_strlen(n.content) as usize;
let bytes = core::slice::from_raw_parts(n.content, len);
let mut i = 0usize;
let mut seg_start = 0usize;
while i < len {
if bytes[i] == b']'
&& i + 2 < len
&& bytes[i + 1] == b']'
&& bytes[i + 2] == b'>'
{
io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
io::buf_add(buf, b"]]>" as *const u8, 3);
seg_start = i + 2;
i += 3;
continue;
}
i += 1;
}
if seg_start < len {
io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
io::buf_add(buf, b"]]>" as *const u8, 3);
}
}
}
t if t == XML_COMMENT_NODE as c_int => {
if cur != root && state.format == 1 {
write_indent(buf, *level, state.indent, state.indent_len);
}
if !n.content.is_null() {
io::buf_add(buf, b"<!--" as *const u8, 4);
io::buf_cat(buf, n.content);
io::buf_add(buf, b"-->" as *const u8, 3);
}
}
t if t == XML_PI_NODE as c_int => {
if cur != root && state.format == 1 {
write_indent(buf, *level, state.indent, state.indent_len);
}
io::buf_add(buf, b"<?" as *const u8, 2);
if !n.name.is_null() {
io::buf_cat(buf, n.name);
}
if !n.content.is_null() && unsafe { *n.content != 0 } {
io::buf_ccat(buf, b' ');
io::buf_cat(buf, n.content);
}
io::buf_add(buf, b"?>" as *const u8, 2);
}
t if t == XML_ENTITY_REF_NODE as c_int => {
io::buf_ccat(buf, b'&');
if !n.name.is_null() {
io::buf_cat(buf, n.name);
}
io::buf_ccat(buf, b';');
}
t if t == XML_DOCUMENT_NODE as c_int => {
doc_content_dump_output(buf, cur, state, level);
}
t if t == XML_HTML_DOCUMENT_NODE as c_int => {
crate::xml::html::serialize_node(cur, buf, state.format, *level);
}
t if t == XML_DTD_NODE as c_int => {
dtd_dump_output(buf, cur, state, level);
}
t if t == XML_ATTRIBUTE_NODE as c_int => {
attr_dump_output(buf, cur as *mut _xmlAttr);
}
t if t == XML_NAMESPACE_DECL as c_int => {
ns_dump_output(buf, cur as *mut _xmlNs);
}
t if t == XML_ELEMENT_DECL as c_int => {
dump_element_decl(buf, cur as *mut _xmlElement);
}
t if t == XML_ATTRIBUTE_DECL as c_int => {
dump_attribute_decl(buf, cur as *mut _xmlAttribute);
}
t if t == XML_ENTITY_DECL as c_int => {
dump_entity_decl(buf, cur as *mut _xmlEntity);
}
_ => {}
}
}
pub(crate) unsafe fn serialize_node(
node: *mut _xmlNode,
buf: *mut _xmlBuffer,
format: c_int,
level: c_int,
) {
unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
}
pub(crate) unsafe fn serialize_node_opt(
node: *mut _xmlNode,
buf: *mut _xmlBuffer,
format: c_int,
level: c_int,
indent: *const xmlChar,
) {
unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
}
pub(crate) unsafe fn serialize_node_opts(
node: *mut _xmlNode,
buf: *mut _xmlBuffer,
format: c_int,
level: c_int,
indent: *const xmlChar,
no_decl: c_int,
) {
unsafe { serialize_node_opts_enc(node, buf, format, level, indent, no_decl, ptr::null()) };
}
pub(crate) unsafe fn serialize_node_opts_enc(
node: *mut _xmlNode,
buf: *mut _xmlBuffer,
format: c_int,
level: c_int,
indent: *const xmlChar,
no_decl: c_int,
encoding: *const xmlChar,
) {
if node.is_null() || buf.is_null() {
return;
}
let parent = unsafe { (*node).parent };
let mut state = DumpState::with_indent_enc(format, indent, no_decl, encoding);
let mut lvl = level;
node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
}
pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
if buf.is_null() || doc.is_null() {
return -1;
}
let before = io::buf_length(buf);
serialize_node(doc as *mut _xmlNode, buf, 0, 0);
let after = io::buf_length(buf);
if after < 0 || before < 0 {
return -1;
}
after - before
}
pub(crate) unsafe fn node_dump(
buf: *mut _xmlBuffer,
doc: *mut _xmlDoc,
node: *mut _xmlNode,
level: c_int,
format: c_int,
) -> c_int {
let _ = doc; if buf.is_null() || node.is_null() {
return -1;
}
let before = io::buf_length(buf);
serialize_node(node, buf, format, level);
let after = io::buf_length(buf);
if after < 0 || before < 0 {
return -1;
}
after - before
}
#[allow(dead_code)]
pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
if doc.is_null() || fd < 0 {
return -1;
}
let out = io::output_buffer_create_fd(fd, ptr::null_mut());
if out.is_null() {
return -1;
}
let buf = io::buf_create(-1);
if buf.is_null() {
io::output_buffer_close(out);
return -1;
}
let ret = doc_dump(buf, doc);
if ret >= 0 {
io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
io::output_buffer_flush(out);
}
io::buf_free(buf);
io::output_buffer_close(out);
ret
}
#[allow(dead_code)]
pub(crate) unsafe fn save_doc_to_buf(
doc: *mut _xmlDoc,
buf: *mut _xmlBuffer,
compression: c_int,
) -> c_int {
let _ = compression;
if doc.is_null() || buf.is_null() {
return -1;
}
doc_dump(buf, doc)
}
#[allow(dead_code)]
pub(crate) unsafe fn save_format_doc_to_buf(
doc: *mut _xmlDoc,
buf: *mut _xmlBuffer,
compression: c_int,
) -> c_int {
let _ = compression;
if doc.is_null() || buf.is_null() {
return -1;
}
let before = io::buf_length(buf);
serialize_node(doc as *mut _xmlNode, buf, 1, 0);
let after = io::buf_length(buf);
if after < 0 || before < 0 {
return -1;
}
after - before
}
#[allow(dead_code)]
pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
if node.is_null() {
return ptr::null_mut();
}
let buf = io::buf_create(-1);
if buf.is_null() {
return ptr::null_mut();
}
serialize_node(node, buf, 0, 0);
let content = io::buf_content(buf);
if content.is_null() {
io::buf_free(buf);
return ptr::null_mut();
}
let result = dup_xml_str(content);
io::buf_free(buf);
result
}
pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
if doc.is_null() {
return ptr::null_mut();
}
let buf = io::buf_create(-1);
if buf.is_null() {
return ptr::null_mut();
}
serialize_node(doc as *mut _xmlNode, buf, 0, 0);
let content = io::buf_content(buf);
if content.is_null() {
io::buf_free(buf);
return ptr::null_mut();
}
let result = dup_xml_str(content);
io::buf_free(buf);
result
}
pub(crate) unsafe fn xmlNodeDump(
buf: *mut _xmlBuffer,
doc: *mut _xmlDoc,
node: *mut _xmlNode,
level: c_int,
format: c_int,
) -> c_int {
node_dump(buf, doc, node, level, format)
}
pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
if fp.is_null() || doc.is_null() {
return -1;
}
let buf = io::buf_create(-1);
if buf.is_null() {
return -1;
}
let ret = doc_dump(buf, doc);
if ret < 0 {
io::buf_free(buf);
return -1;
}
let content = io::buf_content(buf);
let len = io::buf_length(buf);
if !content.is_null() && len > 0 {
let written = libc::fwrite(
content as *const c_void,
1,
len as usize,
fp as *mut libc::FILE,
);
io::buf_free(buf);
written as c_int
} else {
io::buf_free(buf);
0
}
}
pub(crate) unsafe fn xmlDocDumpFormatMemory(
doc: *mut _xmlDoc,
mem: *mut *mut xmlChar,
size: *mut c_int,
format: c_int,
) {
if doc.is_null() || mem.is_null() || size.is_null() {
return;
}
let buf = io::buf_create(-1);
if buf.is_null() {
unsafe {
*mem = ptr::null_mut();
*size = 0;
}
return;
}
serialize_node(doc as *mut _xmlNode, buf, format, 0);
let content = io::buf_content(buf);
let len = io::buf_length(buf);
if !content.is_null() && len > 0 {
let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
if !result.is_null() {
ptr::copy_nonoverlapping(content, result, len as usize);
*result.add(len as usize) = 0;
unsafe {
*mem = result;
*size = len;
}
} else {
unsafe {
*mem = ptr::null_mut();
*size = 0;
}
}
} else {
unsafe {
*mem = ptr::null_mut();
*size = 0;
}
}
io::buf_free(buf);
}
pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
xmlDocDumpFormatMemory(doc, mem, size, 0)
}
pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), 0) }
}
pub(crate) unsafe fn xmlSaveFileEnc(
filename: *const c_char,
cur: *mut _xmlDoc,
encoding: *const c_char,
) -> c_int {
unsafe { xmlSaveFormatFileEnc(filename, cur, encoding, 0) }
}
pub(crate) unsafe fn xmlSaveFormatFile(
filename: *const c_char,
cur: *mut _xmlDoc,
format: c_int,
) -> c_int {
unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), format) }
}
pub(crate) unsafe fn xmlSaveFormatFileEnc(
filename: *const c_char,
cur: *mut _xmlDoc,
encoding: *const c_char,
format: c_int,
) -> c_int {
if cur.is_null() {
return -1;
}
let options = if format != 0 {
crate::xml::save::XML_SAVE_FORMAT
} else {
0
};
let ctxt = crate::xml::save::xmlSaveToFilename(filename, encoding, options);
if ctxt.is_null() {
return -1;
}
crate::xml::save::xmlSaveDoc(ctxt, cur);
crate::xml::save::xmlSaveClose(ctxt)
}
pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
if doc.is_null() {
return -1;
}
unsafe { (*doc).compression }
}
pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
if doc.is_null() {
return;
}
unsafe {
(*doc).compression = mode;
}
}
#[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::xmlMallocImpl(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::xmlFreeImpl(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_node_get_content_recurses_descendants() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("library"));
doc_set_root_element(doc, root);
let book = new_child(root, ptr::null_mut(), c_str("book"));
let title = new_child(book, ptr::null_mut(), c_str("title"));
let text = new_text(c_str("Rust"));
add_child(title, text);
let content = node_get_content(book);
assert!(!content.is_null());
let s = core::slice::from_raw_parts(
content,
libc::strlen(content as *const libc::c_char) as usize,
);
assert_eq!(s, b"Rust", "descendant text not concatenated");
allocator::xmlFreeImpl(content as *mut c_void);
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);
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::xmlFreeImpl(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::xmlFreeImpl(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()); let doc = new_doc(ptr::null());
assert!(new_node(ptr::null_mut(), ptr::null()).is_null());
free_node(ptr::null_mut()); free_doc(ptr::null_mut()); 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);
}
}
unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
let content = io::buf_content(buf);
if content.is_null() {
return expected.is_empty();
}
let len = io::buf_length(buf) as usize;
if len != expected.len() {
return false;
}
let slice = unsafe { core::slice::from_raw_parts(content, len) };
slice == expected.as_bytes()
}
#[test]
fn test_serialize_empty_document() {
unsafe {
let doc = new_doc(ptr::null());
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_element_with_text() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let text = new_text(c_str("hello world"));
add_child(root, text);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_element_with_attributes() {
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("id"), c_str("42"));
set_prop(root, c_str("name"), c_str("test"));
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_nested_elements() {
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 grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
let text = new_text(c_str("text"));
add_child(grandchild, text);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_with_formatting() {
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 text = new_text(c_str("text"));
add_child(child, text);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
serialize_node(doc as *mut _xmlNode, buf, 1, 0);
let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_escape_ampersand() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let text = new_text(c_str("a & b"));
add_child(root, text);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_escape_angle_brackets() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let text = new_text(c_str("x < y > z"));
add_child(root, text);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_comment() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let comment = new_comment(c_str("my comment"));
add_child(root, comment);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_pi() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let pi = new_pi(
c_str("xml-stylesheet"),
c_str("href=\"style.xsl\" type=\"text/xsl\""),
);
add_child(root, pi);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_serialize_self_closing() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("empty"));
doc_set_root_element(doc, root);
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
#[test]
fn test_dump_node_to_string() {
unsafe {
let node = new_node(ptr::null_mut(), c_str("foo"));
let text = new_text(c_str("bar"));
add_child(node, text);
let result = dump_node(node);
assert!(!result.is_null());
let len = xml_strlen(result);
let slice = { core::slice::from_raw_parts(result, len as usize) };
assert_eq!(slice, b"<foo>bar</foo>");
allocator::xmlFreeImpl(result as *mut c_void);
free_node(node);
}
}
#[test]
fn test_dump_doc_to_string() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let result = dump_doc(doc);
assert!(!result.is_null());
let len = xml_strlen(result);
let slice = { core::slice::from_raw_parts(result, len as usize) };
let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
assert_eq!(slice, expected.as_bytes());
allocator::xmlFreeImpl(result as *mut c_void);
free_doc(doc);
}
}
#[test]
fn test_xmlDocDumpFormatMemory() {
unsafe {
let doc = new_doc(ptr::null());
let root = new_node(ptr::null_mut(), c_str("root"));
doc_set_root_element(doc, root);
let mut mem: *mut xmlChar = ptr::null_mut();
let mut size: c_int = 0;
xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
assert!(!mem.is_null());
assert!(size > 0);
let slice = { core::slice::from_raw_parts(mem, size as usize) };
let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
assert_eq!(slice, expected.as_bytes());
allocator::xmlFreeImpl(mem as *mut c_void);
free_doc(doc);
}
}
#[test]
fn test_serialize_escape_attribute() {
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("desc"), c_str("a < b & c \"quoted\""));
let buf = io::buf_create(-1);
assert!(!buf.is_null());
let ret = doc_dump(buf, doc);
assert!(ret >= 0);
let expected =
"<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
assert!(buf_eq_str(buf, expected));
io::buf_free(buf);
free_doc(doc);
}
}
}