#![allow(
missing_docs,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
#![allow(clippy::comparison_chain)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::manual_swap)]
#![allow(unused_assignments)]
#![allow(missing_debug_implementations)]
use core::ffi::c_void;
use core::ptr;
use std::os::raw::{c_char, c_int};
use std::sync::atomic::{AtomicI32, Ordering};
use crate::abi::allocator::{xmlFree, xmlMalloc, xmlMallocZero, xmlRealloc};
use crate::abi::constants::*;
use crate::abi::structs::*;
use crate::abi::types::xmlElementType::*;
use crate::abi::types::*;
use crate::xml::entities;
use crate::xml::hash;
use crate::xml::tree;
unsafe fn dup_str(s: *const xmlChar) -> *mut xmlChar {
unsafe { crate::abi::exports_xml2::xmlStrdup(s) }
}
unsafe fn str_len(s: *const xmlChar) -> c_int {
unsafe { crate::abi::exports_xml2::xmlStrlen(s) }
}
unsafe fn str_prefix(name: *const xmlChar, max: usize) -> Vec<u8> {
if name.is_null() {
return vec![0];
}
let mut v = Vec::new();
let mut i = 0usize;
while i < max {
let c = unsafe { *name.add(i) };
if c == 0 {
break;
}
v.push(c);
i += 1;
}
v.push(0);
v
}
unsafe fn str_eq_or_ptr(a: *const xmlChar, b: *const xmlChar) -> bool {
if a == b {
return true;
}
unsafe { crate::abi::exports_xml2::xmlStrEqual(a, b) != 0 }
}
unsafe fn strcasecmp_eq(a: *const xmlChar, lit: &[u8]) -> bool {
if a.is_null() {
return false;
}
let mut i = 0usize;
loop {
let ca = unsafe { *a.add(i) };
if i >= lit.len() {
return ca == 0;
}
let cb = lit[i];
if ca == 0 || ca.to_ascii_lowercase() != cb.to_ascii_lowercase() {
return false;
}
i += 1;
}
}
unsafe fn is_str_xml(s: *const xmlChar) -> bool {
unsafe { crate::abi::exports_xml2::xmlStrEqual(s, b"xml\0".as_ptr() as *const xmlChar) != 0 }
}
const TEXT_NAME: &[u8] = b"text\0";
unsafe fn copy_char_multibyte(mut out: *mut xmlChar, val: c_int) -> c_int {
if out.is_null() || val < 0 {
return 0;
}
if val >= 0x80 {
let saved = out;
let bits: c_int;
if val < 0x800 {
*out = ((val >> 6) | 0xC0) as u8;
out = out.add(1);
bits = 0;
} else if val < 0x10000 {
*out = ((val >> 12) | 0xE0) as u8;
out = out.add(1);
bits = 6;
} else if val < 0x110000 {
*out = ((val >> 18) | 0xF0) as u8;
out = out.add(1);
bits = 12;
} else {
return 0;
}
let mut b = bits;
loop {
*out = (((val >> b) & 0x3F) | 0x80) as u8;
out = out.add(1);
if b == 0 {
break;
}
b -= 6;
}
return unsafe { out.offset_from(saved) } as c_int;
}
*out = val as u8;
1
}
unsafe fn vec_to_c_string(v: &[u8]) -> *mut xmlChar {
let buf = unsafe { xmlMalloc(v.len() + 1) } as *mut xmlChar;
if buf.is_null() {
return ptr::null_mut();
}
unsafe {
ptr::copy_nonoverlapping(v.as_ptr(), buf, v.len());
*buf.add(v.len()) = 0;
}
buf
}
unsafe fn text_set_content(text: *mut _xmlNode, content: *mut xmlChar) {
if !(*text).content.is_null() {
let inline_addr = core::ptr::addr_of_mut!((*text).properties) as *const c_void;
if (*text).content as *const c_void != inline_addr {
unsafe { xmlFree((*text).content as *mut c_void) };
}
}
(*text).content = content;
(*text).properties = ptr::null_mut();
}
unsafe fn text_add_content(text: *mut _xmlNode, content: *const xmlChar, len: c_int) -> c_int {
if content.is_null() {
return 0;
}
let l = if len < 0 {
unsafe { str_len(content) }
} else {
len
};
let merged = unsafe { crate::abi::exports_xml2::xmlStrncatNew((*text).content, content, l) };
if merged.is_null() {
return -1;
}
unsafe { text_set_content(text, merged) };
0
}
unsafe fn new_doc_text(doc: *mut _xmlDoc, content: *const xmlChar) -> *mut _xmlNode {
let n = unsafe { tree::new_text(content) };
if !n.is_null() {
(*n).doc = doc;
}
n
}
unsafe fn new_doc_text_len(
doc: *mut _xmlDoc,
content: *const xmlChar,
len: c_int,
) -> *mut _xmlNode {
let node = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if node.is_null() {
return ptr::null_mut();
}
(*node).type_ = XML_TEXT_NODE as c_int;
(*node).name = unsafe { dup_str(TEXT_NAME.as_ptr() as *const xmlChar) };
(*node).doc = doc;
if !content.is_null() {
(*node).content = unsafe { crate::abi::exports_xml2::xmlStrndup(content, len) };
if (*node).content.is_null() {
unsafe { tree::free_node(node) };
return ptr::null_mut();
}
}
node
}
unsafe fn new_entity_ref(doc: *mut _xmlDoc, name: *mut xmlChar) -> *mut _xmlNode {
let cur = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if cur.is_null() {
unsafe { xmlFree(name as *mut c_void) };
return ptr::null_mut();
}
(*cur).type_ = XML_ENTITY_REF_NODE as c_int;
(*cur).doc = doc;
(*cur).name = name;
cur
}
unsafe fn predefined_entity_content(name: *const xmlChar) -> *const xmlChar {
if name.is_null() {
return ptr::null();
}
let c = unsafe { *name };
let n1 = unsafe { *name.add(1) };
let n2 = unsafe { *name.add(2) };
match c {
b'l' if n1 == b't' && n2 == 0 => b"<\0".as_ptr() as *const xmlChar,
b'g' if n1 == b't' && n2 == 0 => b">\0".as_ptr() as *const xmlChar,
b'a' if n1 == b'm' && n2 == b'p' && unsafe { *name.add(3) } == 0 => {
b"&\0".as_ptr() as *const xmlChar
}
b'q' if n1 == b'u'
&& n2 == b'o'
&& unsafe { *name.add(3) } == b't'
&& unsafe { *name.add(4) } == 0 =>
{
b"\"\0".as_ptr() as *const xmlChar
}
b'a' if n1 == b'p'
&& n2 == b'o'
&& unsafe { *name.add(3) } == b's'
&& unsafe { *name.add(4) } == 0 =>
{
b"'\0".as_ptr() as *const xmlChar
}
_ => ptr::null(),
}
}
unsafe fn list_append(head: *mut *mut _xmlNode, last: *mut *mut _xmlNode, node: *mut _xmlNode) {
if (*head).is_null() {
*head = node;
} else {
(**last).next = node;
(*node).prev = *last;
}
*last = node;
}
unsafe fn node_parse_att_value(
doc: *mut _xmlDoc,
attr: *mut _xmlNode,
value: *const xmlChar,
len: usize,
) -> c_int {
let mut head: *mut _xmlNode = ptr::null_mut();
let mut last: *mut _xmlNode = ptr::null_mut();
let mut remaining = len;
if !value.is_null() && *value != 0 {
let mut cur = value;
let mut q = cur;
let mut buf: Vec<u8> = Vec::new();
let mut failed = false;
while remaining > 0 && *cur != 0 {
if *cur == b'&' {
let mut charval: c_int = 0;
if cur != q {
buf.extend_from_slice(core::slice::from_raw_parts(
q,
cur.offset_from(q) as usize,
));
q = cur;
}
if remaining > 2 && *cur.add(1) == b'#' && *cur.add(2) == b'x' {
cur = cur.add(3);
remaining -= 3;
while remaining > 0 {
let tmp = *cur;
if tmp == b';' {
break;
}
charval = match tmp {
b'0'..=b'9' => charval * 16 + (tmp - b'0') as c_int,
b'a'..=b'f' => charval * 16 + (tmp - b'a') as c_int + 10,
b'A'..=b'F' => charval * 16 + (tmp - b'A') as c_int + 10,
_ => {
charval = 0;
break;
}
};
if charval > 0x110000 {
charval = 0x110000;
}
cur = cur.add(1);
remaining -= 1;
}
if *cur == b';' {
cur = cur.add(1);
remaining -= 1;
}
q = cur;
} else if remaining > 1 && *cur.add(1) == b'#' {
cur = cur.add(2);
remaining -= 2;
while remaining > 0 {
let tmp = *cur;
if tmp == b';' {
break;
}
charval = match tmp {
b'0'..=b'9' => charval * 10 + (tmp - b'0') as c_int,
_ => {
charval = 0;
break;
}
};
if charval > 0x110000 {
charval = 0x110000;
}
cur = cur.add(1);
remaining -= 1;
}
if *cur == b';' {
cur = cur.add(1);
remaining -= 1;
}
q = cur;
} else {
cur = cur.add(1);
remaining -= 1;
q = cur;
while remaining > 0 && *cur != 0 && *cur != b';' {
cur = cur.add(1);
remaining -= 1;
}
if remaining <= 0 || *cur == 0 {
failed = true;
break;
}
if cur != q {
let mut val = unsafe {
crate::abi::exports_xml2::xmlStrndup(q, (cur.offset_from(q)) as c_int)
};
if val.is_null() {
failed = true;
break;
}
let ent = unsafe { tree::get_doc_entity(doc, val) };
let is_predef = unsafe { predefined_entity_content(val) };
if !is_predef.is_null() {
let p = is_predef;
let mut i = 0usize;
while unsafe { *p.add(i) } != 0 {
buf.push(unsafe { *p.add(i) });
i += 1;
}
} else {
if !buf.is_empty() {
let node = unsafe { new_doc_text(doc, ptr::null()) };
if node.is_null() {
unsafe { xmlFree(val as *mut c_void) };
failed = true;
break;
}
(*node).content = unsafe { vec_to_c_string(&buf) };
if (*node).content.is_null() {
unsafe { tree::free_node(node) };
unsafe { xmlFree(val as *mut c_void) };
failed = true;
break;
}
buf.clear();
(*node).parent = attr;
unsafe { list_append(&mut head, &mut last, node) };
}
let node = unsafe { new_entity_ref(doc, val) };
val = ptr::null_mut();
if node.is_null() {
failed = true;
break;
}
(*node).parent = attr;
(*node).last = ent as *mut _xmlNode;
if !ent.is_null() {
(*node).children = ent as *mut _xmlNode;
(*node).content = (*ent).content;
}
unsafe { list_append(&mut head, &mut last, node) };
}
if !val.is_null() {
unsafe { xmlFree(val as *mut c_void) };
}
}
cur = cur.add(1);
remaining -= 1;
q = cur;
}
if charval != 0 && !failed {
if charval >= 0x110000 {
charval = 0xFFFD; }
let mut buffer = [0u8; 8];
let l = unsafe { copy_char_multibyte(buffer.as_mut_ptr(), charval) };
if l > 0 {
buf.extend_from_slice(&buffer[..l as usize]);
}
}
if failed {
break;
}
} else {
cur = cur.add(1);
remaining -= 1;
}
}
if !failed && cur != q {
buf.extend_from_slice(core::slice::from_raw_parts(q, cur.offset_from(q) as usize));
}
if !failed {
if !buf.is_empty() {
let node = unsafe { new_doc_text(doc, ptr::null()) };
if node.is_null() {
failed = true;
} else {
(*node).content = unsafe { vec_to_c_string(&buf) };
if (*node).content.is_null() {
unsafe { tree::free_node(node) };
failed = true;
} else {
(*node).parent = attr;
unsafe { list_append(&mut head, &mut last, node) };
}
}
} else if head.is_null() {
let node = unsafe { new_doc_text(doc, b"\0".as_ptr() as *const xmlChar) };
if node.is_null() {
failed = true;
} else {
(*node).parent = attr;
head = node;
last = node;
}
}
}
if failed {
if !head.is_null() {
unsafe { tree::free_node_list(head) };
}
return -1;
}
}
if !attr.is_null() {
if !(*attr).children.is_null() {
unsafe { tree::free_node_list((*attr).children) };
}
(*attr).children = head;
(*attr).last = last;
}
0
}
unsafe fn ensure_xml_decl(doc: *mut _xmlDoc) -> *mut _xmlNs {
if doc.is_null() {
return ptr::null_mut();
}
if !(*doc).oldNs.is_null() {
return (*doc).oldNs;
}
let ns = unsafe {
tree::new_ns(
ptr::null_mut(),
XML_XML_NAMESPACE.as_ptr() as *const xmlChar,
b"xml\0".as_ptr() as *const xmlChar,
)
};
if ns.is_null() {
return ptr::null_mut();
}
(*doc).oldNs = ns;
ns
}
unsafe fn ns_list_lookup_by_prefix(ns_list: *mut _xmlNs, prefix: *const xmlChar) -> *mut _xmlNs {
if ns_list.is_null() {
return ptr::null_mut();
}
let mut ns = ns_list;
loop {
if unsafe { str_eq_or_ptr(prefix, (*ns).prefix) } {
return ns;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
ptr::null_mut()
}
unsafe fn free_prop_impl(cur: *mut _xmlAttr) {
if cur.is_null() {
return;
}
if !(*cur).children.is_null() {
unsafe { tree::free_node_list((*cur).children) };
}
if !(*cur).name.is_null() {
unsafe { xmlFree((*cur).name as *mut c_void) };
}
unsafe { xmlFree(cur as *mut c_void) };
}
unsafe fn free_ns_impl(cur: *mut _xmlNs) {
if cur.is_null() {
return;
}
if !(*cur).href.is_null() {
unsafe { xmlFree((*cur).href as *mut c_void) };
}
if !(*cur).prefix.is_null() {
unsafe { xmlFree((*cur).prefix as *mut c_void) };
}
unsafe { xmlFree(cur as *mut c_void) };
}
unsafe fn find_prop_node_internal(
node: *mut _xmlNode,
name: *const xmlChar,
ns_href: *const xmlChar,
_use_dtd: c_int,
) -> *mut _xmlAttr {
if node.is_null() || (*node).type_ != XML_ELEMENT_NODE as c_int || name.is_null() {
return ptr::null_mut();
}
if !(*node).properties.is_null() {
let mut prop = (*node).properties;
if ns_href.is_null() {
loop {
if (*prop).ns.is_null()
&& !(*prop).name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual((*prop).name, name) != 0 }
{
return prop;
}
if (*prop).next.is_null() {
break;
}
prop = (*prop).next;
}
} else {
loop {
if !(*prop).ns.is_null()
&& !(*prop).name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual((*prop).name, name) != 0 }
&& !(*(*prop).ns).href.is_null()
&& unsafe {
crate::abi::exports_xml2::xmlStrEqual((*(*prop).ns).href, ns_href) != 0
}
{
return prop;
}
if (*prop).next.is_null() {
break;
}
prop = (*prop).next;
}
}
}
ptr::null_mut()
}
unsafe fn get_prop_node_value_internal(prop: *mut _xmlAttr) -> *mut xmlChar {
if (*prop).children.is_null() {
return unsafe { dup_str(b"\0".as_ptr() as *const xmlChar) };
}
let text = (*prop).children;
if (*text).type_ == XML_TEXT_NODE as c_int {
if (*text).content.is_null() {
return unsafe { dup_str(b"\0".as_ptr() as *const xmlChar) };
}
return unsafe { dup_str((*text).content) };
}
unsafe { tree::node_get_content(prop as *mut _xmlNode) }
}
unsafe fn get_attr_value(
node: *mut _xmlNode,
name: *const xmlChar,
ns_uri: *const xmlChar,
) -> *mut xmlChar {
let prop = unsafe { find_prop_node_internal(node, name, ns_uri, 0) };
if prop.is_null() {
return ptr::null_mut();
}
unsafe { get_prop_node_value_internal(prop) }
}
unsafe fn set_ns_prop_impl(
node: *mut _xmlNode,
ns: *mut _xmlNs,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if node.is_null() || name.is_null() {
return ptr::null_mut();
}
let ns_href = if ns.is_null() {
ptr::null()
} else {
(*ns).href
};
let existing = unsafe { find_prop_node_internal(node, name, ns_href, 0) };
if !existing.is_null() {
if !(*existing).children.is_null() {
unsafe { tree::free_node_list((*existing).children) };
(*existing).children = ptr::null_mut();
(*existing).last = ptr::null_mut();
}
if !value.is_null() {
let text = unsafe { new_doc_text((*node).doc, value) };
if !text.is_null() {
(*existing).children = text;
(*existing).last = text;
(*text).parent = existing as *mut _xmlNode;
(*text).doc = (*node).doc;
}
}
return existing;
}
unsafe { new_prop_internal(node, ns, name, value, 0) }
}
unsafe fn new_prop_internal(
node: *mut _xmlNode,
ns: *mut _xmlNs,
name: *const xmlChar,
value: *const xmlChar,
eatname: c_int,
) -> *mut _xmlAttr {
let doc: *mut _xmlDoc;
if !node.is_null() && (*node).type_ != XML_ELEMENT_NODE as c_int {
if eatname == 1 {
unsafe { xmlFree(name as *mut c_void) };
}
return ptr::null_mut();
}
let cur = unsafe { xmlMallocZero(size_of::<_xmlAttr>()) } as *mut _xmlAttr;
if cur.is_null() {
if eatname == 1 {
unsafe { xmlFree(name as *mut c_void) };
}
return ptr::null_mut();
}
(*cur).type_ = XML_ATTRIBUTE_NODE as c_int;
(*cur).parent = node;
if !node.is_null() {
doc = (*node).doc;
(*cur).doc = doc;
} else {
doc = ptr::null_mut();
}
(*cur).ns = ns;
if eatname == 0 {
(*cur).name = unsafe { dup_str(name) };
if (*cur).name.is_null() {
unsafe { free_prop_impl(cur) };
return ptr::null_mut();
}
} else {
(*cur).name = name;
}
if !value.is_null() {
let text = unsafe { new_doc_text(doc, value) };
if text.is_null() {
unsafe { free_prop_impl(cur) };
return ptr::null_mut();
}
(*cur).children = text;
(*cur).last = ptr::null_mut();
let mut tmp = text;
while !tmp.is_null() {
(*tmp).parent = cur as *mut _xmlNode;
if (*tmp).next.is_null() {
(*cur).last = tmp;
}
tmp = (*tmp).next;
}
}
if !node.is_null() {
if (*node).properties.is_null() {
(*node).properties = cur;
} else {
let mut prev = (*node).properties;
while !(*prev).next.is_null() {
prev = (*prev).next;
}
(*prev).next = cur;
(*cur).prev = prev;
}
}
cur
}
unsafe fn remove_prop_impl(cur: *mut _xmlAttr) -> c_int {
if cur.is_null() {
return -1;
}
if (*cur).parent.is_null() {
return -1;
}
let mut tmp = (*(*cur).parent).properties;
if tmp == cur {
(*(*cur).parent).properties = (*cur).next;
if !(*cur).next.is_null() {
(*(*cur).next).prev = ptr::null_mut();
}
unsafe { free_prop_impl(cur) };
return 0;
}
while !tmp.is_null() {
if (*tmp).next == cur {
(*tmp).next = (*cur).next;
if !(*tmp).next.is_null() {
(*(*tmp).next).prev = tmp;
}
unsafe { free_prop_impl(cur) };
return 0;
}
tmp = (*tmp).next;
}
-1
}
unsafe fn node_set_doc_impl(node: *mut _xmlNode, doc: *mut _xmlDoc) -> c_int {
let ret = 0;
match (*node).type_ as u32 {
t if t == XML_ENTITY_REF_NODE as u32 => {
(*node).children = ptr::null_mut();
(*node).last = ptr::null_mut();
(*node).content = ptr::null_mut();
if !doc.is_null() && (!(*doc).intSubset.is_null() || !(*doc).extSubset.is_null()) {
let ent = unsafe { tree::get_doc_entity(doc, (*node).name) };
if !ent.is_null() {
(*node).children = ent as *mut _xmlNode;
(*node).last = ent as *mut _xmlNode;
(*node).content = (*ent).content;
}
}
}
t if t == XML_DTD_NODE as u32 => {
if !(*node).doc.is_null() {
if (*(*node).doc).intSubset == node as *mut _xmlDtd {
(*(*node).doc).intSubset = ptr::null_mut();
}
if (*(*node).doc).extSubset == node as *mut _xmlDtd {
(*(*node).doc).extSubset = ptr::null_mut();
}
}
}
_ => {}
}
(*node).doc = doc;
ret
}
unsafe fn set_list_doc_impl(list: *mut _xmlNode, doc: *mut _xmlDoc) -> c_int {
let mut ret = 0;
if list.is_null() || (*list).type_ == XML_NAMESPACE_DECL as c_int {
return 0;
}
let mut cur = list;
while !cur.is_null() {
if (*cur).doc != doc {
if unsafe { set_tree_doc_impl(cur, doc) } < 0 {
ret = -1;
}
}
cur = (*cur).next;
}
ret
}
unsafe fn set_tree_doc_impl(tree: *mut _xmlNode, doc: *mut _xmlDoc) -> c_int {
let mut ret = 0;
if tree.is_null() || (*tree).type_ == XML_NAMESPACE_DECL as c_int {
return 0;
}
if (*tree).doc == doc {
return 0;
}
if (*tree).type_ == XML_ELEMENT_NODE as c_int {
let mut prop = (*tree).properties;
while !prop.is_null() {
if !(*prop).children.is_null() {
if unsafe { set_list_doc_impl((*prop).children, doc) } < 0 {
ret = -1;
}
}
if unsafe { node_set_doc_impl(prop as *mut _xmlNode, doc) } < 0 {
ret = -1;
}
prop = (*prop).next;
}
}
if !(*tree).children.is_null() && (*tree).type_ != XML_ENTITY_REF_NODE as c_int {
if unsafe { set_list_doc_impl((*tree).children, doc) } < 0 {
ret = -1;
}
}
if unsafe { node_set_doc_impl(tree, doc) } < 0 {
ret = -1;
}
ret
}
unsafe fn insert_prop(
doc: *mut _xmlDoc,
cur: *mut _xmlNode,
parent: *mut _xmlNode,
prev: *mut _xmlNode,
next: *mut _xmlNode,
) -> *mut _xmlNode {
if (!prev.is_null() && (*prev).type_ != XML_ATTRIBUTE_NODE as c_int)
|| (!next.is_null() && (*next).type_ != XML_ATTRIBUTE_NODE as c_int)
{
return ptr::null_mut();
}
let ns_href = if (*cur).ns.is_null() {
ptr::null()
} else {
(*(*cur).ns).href
};
let attr = unsafe { find_prop_node_internal(parent, (*cur).name, ns_href, 0) };
unsafe { tree::unlink_node(cur) };
if (*cur).doc != doc {
if unsafe { set_tree_doc_impl(cur, doc) } < 0 {
return ptr::null_mut();
}
}
(*cur).parent = parent;
(*cur).prev = prev;
(*cur).next = next;
if prev.is_null() {
if !parent.is_null() {
(*parent).properties = cur as *mut _xmlAttr;
}
} else {
(*prev).next = cur;
}
if !next.is_null() {
(*next).prev = cur;
}
if !attr.is_null() && attr != cur as *mut _xmlAttr {
unsafe { remove_prop_impl(attr) };
}
cur
}
unsafe fn insert_node(
doc: *mut _xmlDoc,
cur: *mut _xmlNode,
parent: *mut _xmlNode,
prev: *mut _xmlNode,
next: *mut _xmlNode,
coalesce: c_int,
) -> *mut _xmlNode {
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
return unsafe { insert_prop(doc, cur, parent, prev, next) };
}
if coalesce != 0 && (*cur).type_ == XML_TEXT_NODE as c_int {
if !prev.is_null()
&& (*prev).type_ == XML_TEXT_NODE as c_int
&& unsafe { str_eq_or_ptr((*prev).name, (*cur).name) }
{
if unsafe { text_add_content(prev, (*cur).content, -1) } < 0 {
return ptr::null_mut();
}
unsafe { tree::unlink_node(cur) };
unsafe { tree::free_node(cur) };
return prev;
}
if !next.is_null()
&& (*next).type_ == XML_TEXT_NODE as c_int
&& unsafe { str_eq_or_ptr((*next).name, (*cur).name) }
{
if !(*cur).content.is_null() {
let l = unsafe { str_len((*next).content) };
let merged = unsafe {
crate::abi::exports_xml2::xmlStrncatNew((*cur).content, (*next).content, l)
};
if merged.is_null() {
return ptr::null_mut();
}
unsafe { text_set_content(next, merged) };
}
unsafe { tree::unlink_node(cur) };
unsafe { tree::free_node(cur) };
return next;
}
}
let old_parent = (*cur).parent;
if !old_parent.is_null() {
if (*old_parent).children == cur {
(*old_parent).children = (*cur).next;
}
if (*old_parent).last == cur {
(*old_parent).last = (*cur).prev;
}
}
if !(*cur).next.is_null() {
(*(*cur).next).prev = (*cur).prev;
}
if !(*cur).prev.is_null() {
(*(*cur).prev).next = (*cur).next;
}
if (*cur).doc != doc {
if unsafe { set_tree_doc_impl(cur, doc) } < 0 {
(*cur).parent = ptr::null_mut();
(*cur).prev = ptr::null_mut();
(*cur).next = ptr::null_mut();
return ptr::null_mut();
}
}
(*cur).parent = parent;
(*cur).prev = prev;
(*cur).next = next;
if prev.is_null() {
if !parent.is_null() {
(*parent).children = cur;
}
} else {
(*prev).next = cur;
}
if next.is_null() {
if !parent.is_null() {
(*parent).last = cur;
}
} else {
(*next).prev = cur;
}
cur
}
unsafe fn add_child_coalesce(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
if parent.is_null()
|| (*parent).type_ == XML_NAMESPACE_DECL as c_int
|| cur.is_null()
|| (*cur).type_ == XML_NAMESPACE_DECL as c_int
|| parent == cur
{
return ptr::null_mut();
}
if (*parent).type_ == XML_TEXT_NODE as c_int {
if unsafe { text_add_content(parent, (*cur).content, -1) } < 0 {
return ptr::null_mut();
}
unsafe { tree::unlink_node(cur) };
unsafe { tree::free_node(cur) };
return parent;
}
let prev: *mut _xmlNode = if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
let mut p = (*parent).properties;
if !p.is_null() {
while !(*p).next.is_null() {
p = (*p).next;
}
}
p as *mut _xmlNode
} else {
(*parent).last
};
if cur == prev {
return cur;
}
unsafe { insert_node((*parent).doc, cur, parent, prev, ptr::null_mut(), 1) }
}
unsafe fn new_elem(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
let cur = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if cur.is_null() {
return ptr::null_mut();
}
(*cur).type_ = XML_ELEMENT_NODE as c_int;
(*cur).doc = doc;
(*cur).name = name;
(*cur).ns = ns;
if !content.is_null() {
if unsafe { node_parse_att_value(doc, cur, content, usize::MAX) } < 0 {
unsafe { xmlFree(cur as *mut c_void) };
return ptr::null_mut();
}
}
cur
}
unsafe fn new_doc_node(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
if name.is_null() {
return ptr::null_mut();
}
let copy = unsafe { dup_str(name) };
if copy.is_null() {
return ptr::null_mut();
}
let cur = unsafe { new_elem(doc, ns, copy, content) };
if cur.is_null() {
unsafe { xmlFree(copy as *mut c_void) };
return ptr::null_mut();
}
cur
}
unsafe fn new_doc_node_eat_name(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *mut xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
if name.is_null() {
return ptr::null_mut();
}
let cur = unsafe { new_elem(doc, ns, name, content) };
if cur.is_null() {
unsafe { xmlFree(name as *mut c_void) };
return ptr::null_mut();
}
cur
}
unsafe fn new_doc_raw_node(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
let cur = unsafe { new_doc_node(doc, ns, name, ptr::null()) };
if cur.is_null() {
return ptr::null_mut();
}
(*cur).doc = doc;
if !content.is_null() {
let text = unsafe { new_doc_text(doc, content) };
if text.is_null() {
unsafe { tree::free_node(cur) };
return ptr::null_mut();
}
(*cur).children = text;
(*cur).last = text;
(*text).parent = cur;
}
cur
}
pub type xmlDOMWrapAcquireNsFunction = unsafe extern "C" fn(
ctxt: *mut _xmlDOMWrapCtxt,
node: *mut _xmlNode,
nsName: *const xmlChar,
nsPrefix: *const xmlChar,
) -> *mut _xmlNs;
#[repr(C)]
pub struct _xmlDOMWrapCtxt {
pub _private: *mut c_void,
pub type_: c_int,
pub namespaceMap: *mut c_void,
pub getNsForNodeFunc: Option<xmlDOMWrapAcquireNsFunction>,
}
const XML_TREE_NSMAP_PARENT: c_int = -1;
const XML_TREE_NSMAP_DOC: c_int = -3;
const XML_TREE_NSMAP_CUSTOM: c_int = -4;
const XML_DOM_RECONNS_REMOVEREDUND: c_int = 1 << 0;
#[repr(C)]
struct NsMapItem {
next: *mut NsMapItem,
prev: *mut NsMapItem,
oldNs: *mut _xmlNs,
newNs: *mut _xmlNs,
shadowDepth: c_int,
depth: c_int,
}
#[repr(C)]
struct NsMap {
first: *mut NsMapItem,
last: *mut NsMapItem,
pool: *mut NsMapItem,
}
unsafe fn ns_map_not_empty(m: *mut NsMap) -> bool {
!m.is_null() && !(*m).first.is_null()
}
unsafe fn ns_map_free(nsmap: *mut NsMap) {
if nsmap.is_null() {
return;
}
let mut cur = (*nsmap).pool;
while !cur.is_null() {
let next = (*cur).next;
unsafe { xmlFree(cur as *mut c_void) };
cur = next;
}
cur = (*nsmap).first;
while !cur.is_null() {
let next = (*cur).next;
unsafe { xmlFree(cur as *mut c_void) };
cur = next;
}
unsafe { xmlFree(nsmap as *mut c_void) };
}
unsafe fn ns_map_add_item(
nsmap: *mut *mut NsMap,
position: c_int,
oldNs: *mut _xmlNs,
newNs: *mut _xmlNs,
depth: c_int,
) -> *mut NsMapItem {
if nsmap.is_null() {
return ptr::null_mut();
}
if position != -1 && position != 0 {
return ptr::null_mut();
}
let mut map = *nsmap;
if map.is_null() {
map = unsafe { xmlMallocZero(size_of::<NsMap>()) } as *mut NsMap;
if map.is_null() {
return ptr::null_mut();
}
*nsmap = map;
}
let ret = unsafe { xmlMallocZero(size_of::<NsMapItem>()) } as *mut NsMapItem;
if ret.is_null() {
return ptr::null_mut();
}
if (*map).first.is_null() {
(*map).first = ret;
(*map).last = ret;
} else if position == -1 {
(*ret).prev = (*map).last;
(*(*map).last).next = ret;
(*map).last = ret;
} else {
(*(*map).first).prev = ret;
(*ret).next = (*map).first;
(*map).first = ret;
}
(*ret).oldNs = oldNs;
(*ret).newNs = newNs;
(*ret).shadowDepth = -1;
(*ret).depth = depth;
ret
}
unsafe fn ns_map_pop(map: *mut NsMap) -> *mut NsMapItem {
let i = (*map).last;
(*map).last = (*i).prev;
if (*map).last.is_null() {
(*map).first = ptr::null_mut();
} else {
(*(*map).last).next = ptr::null_mut();
}
(*i).prev = ptr::null_mut();
(*i).next = (*map).pool;
(*map).pool = i;
i
}
unsafe fn store_ns(
doc: *mut _xmlDoc,
ns_name: *const xmlChar,
prefix: *const xmlChar,
) -> *mut _xmlNs {
if doc.is_null() {
return ptr::null_mut();
}
let mut ns = unsafe { ensure_xml_decl(doc) };
if ns.is_null() {
return ptr::null_mut();
}
if !(*ns).next.is_null() {
ns = (*ns).next;
loop {
if unsafe { str_eq_or_ptr((*ns).prefix, prefix) }
&& !(*ns).href.is_null()
&& !ns_name.is_null()
&& unsafe { crate::abi::exports_xml2::xmlStrEqual((*ns).href, ns_name) != 0 }
{
return ns;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
}
if !ns.is_null() {
let n = unsafe { tree::new_ns(ptr::null_mut(), ns_name, prefix) };
if n.is_null() {
return ptr::null_mut();
}
(*ns).next = n;
return n;
}
ptr::null_mut()
}
unsafe fn gather_in_scope_ns(map: *mut *mut NsMap, node: *mut _xmlNode) -> c_int {
if map.is_null() || !(*map).is_null() {
return -1;
}
if node.is_null() || (*node).type_ == XML_NAMESPACE_DECL as c_int {
return -1;
}
let mut cur = node;
while !cur.is_null() && cur != (*cur).doc as *mut _xmlNode {
if (*cur).type_ == XML_ELEMENT_NODE as c_int && !(*cur).nsDef.is_null() {
let mut ns = (*cur).nsDef;
loop {
let mut shadowed = 0;
if unsafe { ns_map_not_empty(*map) } {
let mut mi = (*(*map)).first;
while !mi.is_null() {
if !(*mi).newNs.is_null()
&& unsafe { str_eq_or_ptr((*ns).prefix, (*(*mi).newNs).prefix) }
{
shadowed = 1;
break;
}
mi = (*mi).next;
}
}
let mi =
unsafe { ns_map_add_item(map, 0, ptr::null_mut(), ns, XML_TREE_NSMAP_PARENT) };
if mi.is_null() {
return -1;
}
if shadowed != 0 {
(*mi).shadowDepth = 0;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
}
cur = (*cur).parent;
}
0
}
unsafe fn ns_norm_add_ns_map_item2(
list: *mut *mut *mut _xmlNs,
size: *mut c_int,
number: *mut c_int,
old_ns: *mut _xmlNs,
new_ns: *mut _xmlNs,
) -> c_int {
if *number >= *size {
let new_size = if *size <= 0 { 6 } else { (*size) * 2 };
let tmp = unsafe {
xmlRealloc(
*list as *mut c_void,
(new_size as usize) * 2 * size_of::<*mut _xmlNs>(),
)
} as *mut *mut _xmlNs;
if tmp.is_null() {
return -1;
}
*list = tmp;
*size = new_size;
}
let arr = *list;
unsafe {
arr.add((2 * *number) as usize).write(old_ns);
arr.add((2 * *number + 1) as usize).write(new_ns);
}
*number += 1;
0
}
unsafe fn search_ns_by_prefix_strict(
doc: *mut _xmlDoc,
node: *mut _xmlNode,
prefix: *const xmlChar,
ret_ns: *mut *mut _xmlNs,
) -> c_int {
if doc.is_null() || node.is_null() || (*node).type_ == XML_NAMESPACE_DECL as c_int {
return -1;
}
if !ret_ns.is_null() {
*ret_ns = ptr::null_mut();
}
if unsafe { is_str_xml(prefix) } {
if !ret_ns.is_null() {
let ns = unsafe { ensure_xml_decl(doc) };
if ns.is_null() {
return -1;
}
*ret_ns = ns;
}
return 1;
}
let mut cur = node;
loop {
if (*cur).type_ == XML_ELEMENT_NODE as c_int {
if !(*cur).nsDef.is_null() {
let mut ns = (*cur).nsDef;
loop {
if unsafe { str_eq_or_ptr(prefix, (*ns).prefix) } {
if (*ns).href.is_null() {
return 0;
}
if !ret_ns.is_null() {
*ret_ns = ns;
}
return 1;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
}
} else if (*cur).type_ == XML_ENTITY_DECL as c_int {
return 0;
}
cur = (*cur).parent;
if cur.is_null() || (*cur).doc == cur as *mut _xmlDoc {
break;
}
}
0
}
unsafe fn search_ns_by_namespace_strict(
doc: *mut _xmlDoc,
node: *mut _xmlNode,
ns_name: *const xmlChar,
ret_ns: *mut *mut _xmlNs,
prefixed: c_int,
) -> c_int {
if doc.is_null() || ns_name.is_null() || ret_ns.is_null() {
return -1;
}
if node.is_null() || (*node).type_ == XML_NAMESPACE_DECL as c_int {
return -1;
}
*ret_ns = ptr::null_mut();
if unsafe {
crate::abi::exports_xml2::xmlStrEqual(ns_name, XML_XML_NAMESPACE.as_ptr() as *const xmlChar)
!= 0
} {
let ns = unsafe { ensure_xml_decl(doc) };
if ns.is_null() {
return -1;
}
*ret_ns = ns;
return 1;
}
let mut cur = node;
let mut prev: *mut _xmlNode = ptr::null_mut();
let mut out: *mut _xmlNode = ptr::null_mut();
loop {
if (*cur).type_ == XML_ELEMENT_NODE as c_int {
if !(*cur).nsDef.is_null() {
let mut ns = (*cur).nsDef;
loop {
if prefixed != 0 && (*ns).prefix.is_null() {
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
continue;
}
if !prev.is_null() {
let mut prevns = (*prev).nsDef;
let mut shadowed: *mut _xmlNs = ptr::null_mut();
while !prevns.is_null() {
if unsafe { str_eq_or_ptr((*prevns).prefix, (*ns).prefix) } {
shadowed = prevns;
break;
}
prevns = (*prevns).next;
}
if !shadowed.is_null() {
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
continue;
}
}
if unsafe { crate::abi::exports_xml2::xmlStrEqual(ns_name, (*ns).href) != 0 } {
if !out.is_null() {
if unsafe {
search_ns_by_prefix_strict(doc, node, (*ns).prefix, ptr::null_mut())
} == 0
{
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
continue;
}
}
*ret_ns = ns;
return 1;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
out = prev;
prev = cur;
}
} else if (*cur).type_ == XML_ENTITY_DECL as c_int {
return 0;
}
cur = (*cur).parent;
if cur.is_null() || (*cur).doc == cur as *mut _xmlDoc {
break;
}
}
0
}
unsafe fn declare_ns_forced(
doc: *mut _xmlDoc,
elem: *mut _xmlNode,
ns_name: *const xmlChar,
prefix: *const xmlChar,
check_shadow: c_int,
) -> *mut _xmlNs {
if doc.is_null() || elem.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
return ptr::null_mut();
}
let mut counter: c_int = 0;
let mut buf: Vec<u8> = Vec::new();
let mut cur_prefix: *const xmlChar = prefix;
loop {
let mut used = false;
if !(*elem).nsDef.is_null()
&& !unsafe { ns_list_lookup_by_prefix((*elem).nsDef, cur_prefix) }.is_null()
{
used = true;
}
if !used && check_shadow != 0 && !(*elem).parent.is_null() {
if unsafe {
search_ns_by_prefix_strict(doc, (*elem).parent, cur_prefix, ptr::null_mut())
} == 1
{
used = true;
}
}
if !used {
let ret = unsafe { tree::new_ns(ptr::null_mut(), ns_name, cur_prefix) };
if ret.is_null() {
return ptr::null_mut();
}
if (*elem).nsDef.is_null() {
(*elem).nsDef = ret;
} else {
let mut ns2 = (*elem).nsDef;
while !(*ns2).next.is_null() {
ns2 = (*ns2).next;
}
(*ns2).next = ret;
}
return ret;
}
counter += 1;
if counter > 1000 {
return ptr::null_mut();
}
if prefix.is_null() {
let s = format!("ns_{}", counter);
buf = s.into_bytes();
buf.push(0);
} else {
let p = unsafe { str_prefix(prefix, 30) };
let p_str = String::from_utf8_lossy(&p[..p.len().saturating_sub(1)]);
let s = format!("{}_{}", p_str, counter);
buf = s.into_bytes();
buf.push(0);
}
cur_prefix = buf.as_ptr() as *const xmlChar;
}
}
unsafe fn acquire_normalized_ns(
doc: *mut _xmlDoc,
elem: *mut _xmlNode,
ns: *mut _xmlNs,
ret_ns: *mut *mut _xmlNs,
ns_map: *mut *mut NsMap,
depth: c_int,
ancestors_only: c_int,
prefixed: c_int,
) -> c_int {
if doc.is_null() || ns.is_null() || ret_ns.is_null() || ns_map.is_null() {
return -1;
}
*ret_ns = ptr::null_mut();
if unsafe { is_str_xml((*ns).prefix) } {
let xml_ns = unsafe { ensure_xml_decl(doc) };
if xml_ns.is_null() {
return -1;
}
*ret_ns = xml_ns;
return 0;
}
if unsafe { ns_map_not_empty(*ns_map) } && !(ancestors_only != 0 && elem.is_null()) {
let mut mi = (*(*ns_map)).first;
while !mi.is_null() {
if (*mi).depth >= XML_TREE_NSMAP_PARENT
&& ((ancestors_only == 0) || (*mi).depth == XML_TREE_NSMAP_PARENT)
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& !(*(*mi).newNs).href.is_null()
&& *(*(*mi).newNs).href != 0
&& ((prefixed == 0) || !(*(*mi).newNs).prefix.is_null())
&& ((*ns).href == (*(*mi).newNs).href
|| unsafe {
crate::abi::exports_xml2::xmlStrEqual((*ns).href, (*(*mi).newNs).href) != 0
})
{
(*mi).oldNs = ns;
*ret_ns = (*mi).newNs;
return 0;
}
mi = (*mi).next;
}
}
if elem.is_null() {
let tmpns = unsafe { store_ns(doc, (*ns).href, (*ns).prefix) };
if tmpns.is_null() {
return -1;
}
if unsafe { ns_map_add_item(ns_map, -1, ns, tmpns, XML_TREE_NSMAP_DOC) }.is_null() {
return -1;
}
*ret_ns = tmpns;
} else {
let tmpns = unsafe { declare_ns_forced(doc, elem, (*ns).href, (*ns).prefix, 0) };
if tmpns.is_null() {
return -1;
}
if unsafe { ns_map_not_empty(*ns_map) } {
let mut mi = (*(*ns_map)).first;
while !mi.is_null() {
if (*mi).depth < depth
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& unsafe { str_eq_or_ptr((*ns).prefix, (*(*mi).newNs).prefix) }
{
(*mi).shadowDepth = depth;
break;
}
mi = (*mi).next;
}
}
if unsafe { ns_map_add_item(ns_map, -1, ns, tmpns, depth) }.is_null() {
return -1;
}
*ret_ns = tmpns;
}
0
}
unsafe fn ns_map_pop_depth(ns_map: *mut NsMap, depth: c_int) {
if ns_map.is_null() {
return;
}
if unsafe { ns_map_not_empty(ns_map) } {
while !(*ns_map).last.is_null() && (*(*ns_map).last).depth >= depth {
unsafe { ns_map_pop(ns_map) };
}
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).shadowDepth >= depth {
(*mi).shadowDepth = -1;
}
mi = (*mi).next;
}
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeNs(cur: *mut _xmlNs) {
unsafe { free_ns_impl(cur) };
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeNsList(cur: *mut _xmlNs) {
let mut c = cur;
while !c.is_null() {
let next = (*c).next;
unsafe { free_ns_impl(c) };
c = next;
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeProp(cur: *mut _xmlAttr) {
unsafe { free_prop_impl(cur) };
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreePropList(cur: *mut _xmlAttr) {
let mut c = cur;
while !c.is_null() {
let next = (*c).next;
unsafe { free_prop_impl(c) };
c = next;
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewNodeEatName(ns: *mut _xmlNs, name: *mut xmlChar) -> *mut _xmlNode {
unsafe { new_doc_node_eat_name(ptr::null_mut(), ns, name, ptr::null()) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewDocNode(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
unsafe { new_doc_node(doc, ns, name, content) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewDocNodeEatName(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *mut xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
unsafe { new_doc_node_eat_name(doc, ns, name, content) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewDocRawNode(
doc: *mut _xmlDoc,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
unsafe { new_doc_raw_node(doc, ns, name, content) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewDocFragment(doc: *mut _xmlDoc) -> *mut _xmlNode {
let cur = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if cur.is_null() {
return ptr::null_mut();
}
(*cur).type_ = XML_DOCUMENT_FRAG_NODE as c_int;
(*cur).doc = doc;
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewProp(
node: *mut _xmlNode,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if name.is_null() {
return ptr::null_mut();
}
unsafe { new_prop_internal(node, ptr::null_mut(), name, value, 0) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewNsProp(
node: *mut _xmlNode,
ns: *mut _xmlNs,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if name.is_null() {
return ptr::null_mut();
}
unsafe { new_prop_internal(node, ns, name, value, 0) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewNsPropEatName(
node: *mut _xmlNode,
ns: *mut _xmlNs,
name: *mut xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if name.is_null() {
return ptr::null_mut();
}
unsafe { new_prop_internal(node, ns, name, value, 1) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewDocProp(
doc: *mut _xmlDoc,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlAttr {
if name.is_null() {
return ptr::null_mut();
}
let cur = unsafe { xmlMallocZero(size_of::<_xmlAttr>()) } as *mut _xmlAttr;
if cur.is_null() {
return ptr::null_mut();
}
(*cur).type_ = XML_ATTRIBUTE_NODE as c_int;
(*cur).name = unsafe { dup_str(name) };
if (*cur).name.is_null() {
unsafe { xmlFree(cur as *mut c_void) };
return ptr::null_mut();
}
(*cur).doc = doc;
if !value.is_null() {
if unsafe { node_parse_att_value(doc, cur as *mut _xmlNode, value, usize::MAX) } < 0 {
unsafe { free_prop_impl(cur) };
return ptr::null_mut();
}
}
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewReference(
doc: *const _xmlDoc,
name: *const xmlChar,
) -> *mut _xmlNode {
if name.is_null() {
return ptr::null_mut();
}
let cur = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if cur.is_null() {
return ptr::null_mut();
}
(*cur).type_ = XML_ENTITY_REF_NODE as c_int;
(*cur).doc = doc as *mut _xmlDoc;
let mut nm = name;
if *nm == b'&' {
nm = nm.add(1);
let len = unsafe { str_len(nm) } as usize;
(*cur).name = if len > 0 && unsafe { *nm.add(len - 1) } == b';' {
unsafe { crate::abi::exports_xml2::xmlStrndup(nm, (len - 1) as c_int) }
} else {
unsafe { crate::abi::exports_xml2::xmlStrndup(nm, len as c_int) }
};
} else {
(*cur).name = unsafe { dup_str(nm) };
}
if (*cur).name.is_null() {
unsafe { tree::free_node(cur) };
return ptr::null_mut();
}
let ent = unsafe { tree::get_doc_entity(doc as *mut _xmlDoc, (*cur).name) };
if !ent.is_null() {
(*cur).content = (*ent).content;
(*cur).children = ent as *mut _xmlNode;
(*cur).last = ent as *mut _xmlNode;
}
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewTextChild(
parent: *mut _xmlNode,
ns: *mut _xmlNs,
name: *const xmlChar,
content: *const xmlChar,
) -> *mut _xmlNode {
if parent.is_null() || name.is_null() {
return ptr::null_mut();
}
let mut ns = ns;
match (*parent).type_ as u32 {
t if t == XML_DOCUMENT_NODE as u32
|| t == XML_HTML_DOCUMENT_NODE as u32
|| t == XML_DOCUMENT_FRAG_NODE as u32 => {}
t if t == XML_ELEMENT_NODE as u32 => {
if ns.is_null() {
ns = (*parent).ns;
}
}
_ => return ptr::null_mut(),
}
let cur = unsafe { new_doc_raw_node((*parent).doc, ns, name, content) };
if cur.is_null() {
return ptr::null_mut();
}
(*cur).parent = parent;
if (*parent).children.is_null() {
(*parent).children = cur;
(*parent).last = cur;
} else {
let prev = (*parent).last;
(*prev).next = cur;
(*cur).prev = prev;
(*parent).last = cur;
}
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewTextLen(content: *const xmlChar, len: c_int) -> *mut _xmlNode {
let cur = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if cur.is_null() {
return ptr::null_mut();
}
(*cur).type_ = XML_TEXT_NODE as c_int;
(*cur).name = unsafe { dup_str(TEXT_NAME.as_ptr() as *const xmlChar) };
if !content.is_null() {
(*cur).content = unsafe { crate::abi::exports_xml2::xmlStrndup(content, len) };
if (*cur).content.is_null() {
unsafe { tree::free_node(cur) };
return ptr::null_mut();
}
}
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetContent(cur: *mut _xmlNode, content: *const xmlChar) -> c_int {
unsafe { node_set_content_internal(cur, content, -1) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetContentLen(
cur: *mut _xmlNode,
content: *const xmlChar,
len: c_int,
) -> c_int {
unsafe { node_set_content_internal(cur, content, len) }
}
unsafe fn node_set_content_internal(
cur: *mut _xmlNode,
content: *const xmlChar,
len: c_int,
) -> c_int {
if cur.is_null() {
return 1;
}
match (*cur).type_ as u32 {
t if t == XML_DOCUMENT_FRAG_NODE as u32
|| t == XML_ELEMENT_NODE as u32
|| t == XML_ATTRIBUTE_NODE as u32 =>
{
let max_size = if len < 0 { usize::MAX } else { len as usize };
if unsafe { node_parse_att_value((*cur).doc, cur, content, max_size) } < 0 {
return -1;
}
}
t if t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32 =>
{
let mut copy: *mut xmlChar = ptr::null_mut();
if !content.is_null() {
copy = if len < 0 {
unsafe { dup_str(content) }
} else {
unsafe { crate::abi::exports_xml2::xmlStrndup(content, len) }
};
if copy.is_null() {
return -1;
}
}
unsafe { text_set_content(cur, copy) };
}
_ => {}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeAddContent(cur: *mut _xmlNode, content: *const xmlChar) -> c_int {
let len = unsafe { str_len(content) };
unsafe { xmlNodeAddContentLen(cur, content, len) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeAddContentLen(
cur: *mut _xmlNode,
content: *const xmlChar,
len: c_int,
) -> c_int {
if cur.is_null() {
return 1;
}
if content.is_null() || len <= 0 {
return 0;
}
match (*cur).type_ as u32 {
t if t == XML_DOCUMENT_FRAG_NODE as u32
|| t == XML_ELEMENT_NODE as u32
|| t == XML_ATTRIBUTE_NODE as u32 =>
{
let new_node = unsafe { new_doc_text_len((*cur).doc, content, len) };
if new_node.is_null() {
return -1;
}
let tmp = unsafe { add_child_coalesce(cur, new_node) };
if tmp.is_null() {
unsafe { tree::free_node(new_node) };
return -1;
}
}
t if t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32 =>
{
return unsafe { text_add_content(cur, content, len) };
}
_ => {}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeGetContent(cur: *const _xmlNode) -> *mut xmlChar {
unsafe { tree::node_get_content(cur as *mut _xmlNode) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetLang(cur: *mut _xmlNode, lang: *const xmlChar) -> c_int {
if cur.is_null() || (*cur).type_ != XML_ELEMENT_NODE as c_int {
return 1;
}
let ns = unsafe { ensure_xml_decl((*cur).doc) };
if ns.is_null() {
return -1;
}
let attr = unsafe { set_ns_prop_impl(cur, ns, b"lang\0".as_ptr() as *const xmlChar, lang) };
if attr.is_null() {
return -1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeGetLang(cur: *const _xmlNode) -> *mut xmlChar {
if cur.is_null() || (*cur).type_ == XML_NAMESPACE_DECL as c_int {
return ptr::null_mut();
}
let mut c = cur;
while !c.is_null() {
let lang = unsafe {
get_attr_value(
c as *mut _xmlNode,
b"lang\0".as_ptr() as *const xmlChar,
XML_XML_NAMESPACE.as_ptr() as *const xmlChar,
)
};
if !lang.is_null() {
return lang;
}
c = (*c).parent;
}
ptr::null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetSpacePreserve(cur: *mut _xmlNode, val: c_int) -> c_int {
if cur.is_null() || (*cur).type_ != XML_ELEMENT_NODE as c_int {
return 1;
}
let ns = unsafe { ensure_xml_decl((*cur).doc) };
if ns.is_null() {
return -1;
}
let string: &[u8] = if val == 0 {
b"default\0"
} else {
b"preserve\0"
};
let attr = unsafe {
set_ns_prop_impl(
cur,
ns,
b"space\0".as_ptr() as *const xmlChar,
string.as_ptr() as *const xmlChar,
)
};
if attr.is_null() {
return -1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeGetSpacePreserve(cur: *const _xmlNode) -> c_int {
if cur.is_null() || (*cur).type_ != XML_ELEMENT_NODE as c_int {
return -1;
}
let mut c = cur;
while !c.is_null() {
let space = unsafe {
get_attr_value(
c as *mut _xmlNode,
b"space\0".as_ptr() as *const xmlChar,
XML_XML_NAMESPACE.as_ptr() as *const xmlChar,
)
};
if !space.is_null() {
if unsafe {
crate::abi::exports_xml2::xmlStrEqual(
space,
b"preserve\0".as_ptr() as *const xmlChar,
) != 0
} {
unsafe { xmlFree(space as *mut c_void) };
return 1;
}
if unsafe {
crate::abi::exports_xml2::xmlStrEqual(
space,
b"default\0".as_ptr() as *const xmlChar,
) != 0
} {
unsafe { xmlFree(space as *mut c_void) };
return 0;
}
unsafe { xmlFree(space as *mut c_void) };
}
c = (*c).parent;
}
-1
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetName(cur: *mut _xmlNode, name: *const xmlChar) {
if cur.is_null() || name.is_null() {
return;
}
match (*cur).type_ as u32 {
t if t == XML_ELEMENT_NODE as u32
|| t == XML_ATTRIBUTE_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_ENTITY_REF_NODE as u32 => {}
_ => return,
}
let copy = unsafe { dup_str(name) };
if copy.is_null() {
return;
}
let old = (*cur).name;
(*cur).name = copy;
if !old.is_null() {
unsafe { xmlFree(old as *mut c_void) };
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeSetBase(cur: *mut _xmlNode, uri: *const xmlChar) -> c_int {
if cur.is_null() {
return -1;
}
match (*cur).type_ as u32 {
t if t == XML_ELEMENT_NODE as u32 || t == XML_ATTRIBUTE_NODE as u32 => {}
t if t == XML_DOCUMENT_NODE as u32 || t == XML_HTML_DOCUMENT_NODE as u32 => {
let doc = cur as *mut _xmlDoc;
if !(*doc).URL.is_null() {
unsafe { xmlFree((*doc).URL as *mut c_void) };
}
if uri.is_null() {
(*doc).URL = ptr::null_mut();
} else {
(*doc).URL = unsafe { crate::abi::exports_uri::xmlPathToURI(uri as *const c_char) };
if (*doc).URL.is_null() {
return -1;
}
}
return 0;
}
_ => return -1,
}
let ns = unsafe { ensure_xml_decl((*cur).doc) };
if ns.is_null() {
return -1;
}
let fixed = unsafe { crate::abi::exports_uri::xmlPathToURI(uri as *const c_char) };
if fixed.is_null() {
return -1;
}
let attr = unsafe { set_ns_prop_impl(cur, ns, b"base\0".as_ptr() as *const xmlChar, fixed) };
if attr.is_null() {
unsafe { xmlFree(fixed as *mut c_void) };
return -1;
}
unsafe { xmlFree(fixed as *mut c_void) };
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeGetBaseSafe(
doc: *const _xmlDoc,
cur: *const _xmlNode,
baseOut: *mut *mut xmlChar,
) -> c_int {
if baseOut.is_null() {
return 1;
}
*baseOut = ptr::null_mut();
if cur.is_null() && doc.is_null() {
return 1;
}
if !cur.is_null() && (*cur).type_ == XML_NAMESPACE_DECL as c_int {
return 1;
}
let mut doc = doc;
if doc.is_null() {
doc = (*cur).doc;
}
let mut ret: *mut xmlChar = ptr::null_mut();
if !doc.is_null() && (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
let mut c = (*doc).children;
while !c.is_null() {
if (*c).type_ != XML_ELEMENT_NODE as c_int {
c = (*c).next;
continue;
}
if unsafe { strcasecmp_eq((*c).name, b"html") } {
c = (*c).children;
continue;
}
if unsafe { strcasecmp_eq((*c).name, b"head") } {
c = (*c).children;
continue;
}
if unsafe { strcasecmp_eq((*c).name, b"base") } {
ret =
unsafe { get_attr_value(c, b"href\0".as_ptr() as *const xmlChar, ptr::null()) };
if ret.is_null() {
return 1;
}
*baseOut = ret;
return 0;
}
c = (*c).next;
}
return 0;
}
let mut c = cur;
while !c.is_null() {
if (*c).type_ == XML_ENTITY_DECL as c_int {
let ent = c as *const _xmlEntity as *mut _xmlEntity;
if (*ent).URI.is_null() {
break;
}
if !ret.is_null() {
unsafe { xmlFree(ret as *mut c_void) };
}
ret = unsafe { dup_str((*ent).URI) };
if ret.is_null() {
return -1;
}
*baseOut = ret;
return 0;
}
if (*c).type_ == XML_ELEMENT_NODE as c_int {
let base = unsafe {
get_attr_value(
c as *mut _xmlNode,
b"base\0".as_ptr() as *const xmlChar,
XML_XML_NAMESPACE.as_ptr() as *const xmlChar,
)
};
if !base.is_null() {
if !ret.is_null() {
let mut newbase: *mut xmlChar = ptr::null_mut();
let res = unsafe {
crate::abi::exports_uri::xmlBuildURISafe(
ret as *const c_char,
base as *const c_char,
&mut newbase,
)
};
unsafe { xmlFree(ret as *mut c_void) };
unsafe { xmlFree(base as *mut c_void) };
if res != 0 {
return res;
}
ret = newbase;
} else {
ret = base;
}
if !ret.is_null()
&& (unsafe { *ret } == b'h'
|| unsafe { *ret } == b'f'
|| unsafe { *ret } == b'u')
{
if unsafe {
crate::abi::exports_xml2::xmlStrncmp(
ret,
b"http://\0".as_ptr() as *const xmlChar,
7,
) == 0
} || unsafe {
crate::abi::exports_xml2::xmlStrncmp(
ret,
b"ftp://\0".as_ptr() as *const xmlChar,
6,
) == 0
} || unsafe {
crate::abi::exports_xml2::xmlStrncmp(
ret,
b"urn:\0".as_ptr() as *const xmlChar,
4,
) == 0
} {
*baseOut = ret;
return 0;
}
}
}
}
c = (*c).parent;
}
if !doc.is_null() && !(*doc).URL.is_null() {
if ret.is_null() {
ret = unsafe { dup_str((*doc).URL) };
if ret.is_null() {
return -1;
}
} else {
let mut newbase: *mut xmlChar = ptr::null_mut();
let res = unsafe {
crate::abi::exports_uri::xmlBuildURISafe(
ret as *const c_char,
(*doc).URL as *const c_char,
&mut newbase,
)
};
unsafe { xmlFree(ret as *mut c_void) };
if res != 0 {
return res;
}
ret = newbase;
}
}
*baseOut = ret;
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeGetBase(doc: *const _xmlDoc, cur: *const _xmlNode) -> *mut xmlChar {
let mut base: *mut xmlChar = ptr::null_mut();
unsafe { xmlNodeGetBaseSafe(doc, cur, &mut base) };
base
}
#[no_mangle]
pub unsafe extern "C" fn xmlNodeIsText(node: *const _xmlNode) -> c_int {
if node.is_null() {
return 0;
}
if (*node).type_ == XML_TEXT_NODE as c_int {
1
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlSetTreeDoc(tree: *mut _xmlNode, doc: *mut _xmlDoc) -> c_int {
unsafe { set_tree_doc_impl(tree, doc) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlAddNextSibling(
prev: *mut _xmlNode,
cur: *mut _xmlNode,
) -> *mut _xmlNode {
if prev.is_null()
|| (*prev).type_ == XML_NAMESPACE_DECL as c_int
|| cur.is_null()
|| (*cur).type_ == XML_NAMESPACE_DECL as c_int
|| cur == prev
{
return ptr::null_mut();
}
if cur == (*prev).next {
return cur;
}
unsafe { insert_node((*prev).doc, cur, (*prev).parent, prev, (*prev).next, 0) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlAddPrevSibling(
next: *mut _xmlNode,
cur: *mut _xmlNode,
) -> *mut _xmlNode {
if next.is_null()
|| (*next).type_ == XML_NAMESPACE_DECL as c_int
|| cur.is_null()
|| (*cur).type_ == XML_NAMESPACE_DECL as c_int
|| cur == next
{
return ptr::null_mut();
}
if cur == (*next).prev {
return cur;
}
unsafe { insert_node((*next).doc, cur, (*next).parent, (*next).prev, next, 0) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlAddChildList(
parent: *mut _xmlNode,
cur: *mut _xmlNode,
) -> *mut _xmlNode {
if parent.is_null() || (*parent).type_ == XML_NAMESPACE_DECL as c_int {
return ptr::null_mut();
}
if cur.is_null() || (*cur).type_ == XML_NAMESPACE_DECL as c_int {
return ptr::null_mut();
}
let mut oom = 0;
let mut iter = cur;
while !iter.is_null() {
if (*iter).doc != (*parent).doc {
if unsafe { set_tree_doc_impl(iter, (*parent).doc) } < 0 {
oom = 1;
}
}
iter = (*iter).next;
}
if oom != 0 {
return ptr::null_mut();
}
let mut cur = cur;
if (*parent).children.is_null() {
(*parent).children = cur;
} else {
let prev = (*parent).last;
if (*cur).type_ == XML_TEXT_NODE as c_int
&& (*prev).type_ == XML_TEXT_NODE as c_int
&& unsafe { str_eq_or_ptr((*cur).name, (*prev).name) }
{
if unsafe { text_add_content(prev, (*cur).content, -1) } < 0 {
return ptr::null_mut();
}
let next = (*cur).next;
unsafe { tree::free_node(cur) };
if next.is_null() {
return prev;
}
cur = next;
}
(*prev).next = cur;
(*cur).prev = prev;
}
while !(*cur).next.is_null() {
(*cur).parent = parent;
cur = (*cur).next;
}
(*cur).parent = parent;
(*parent).last = cur;
cur
}
#[no_mangle]
pub unsafe extern "C" fn xmlReplaceNode(old: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
if old == cur {
return ptr::null_mut();
}
if old.is_null() || (*old).type_ == XML_NAMESPACE_DECL as c_int || (*old).parent.is_null() {
return ptr::null_mut();
}
if cur.is_null() || (*cur).type_ == XML_NAMESPACE_DECL as c_int {
unsafe { tree::unlink_node(old) };
return old;
}
if (*old).type_ == XML_ATTRIBUTE_NODE as c_int && (*cur).type_ != XML_ATTRIBUTE_NODE as c_int {
return old;
}
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int && (*old).type_ != XML_ATTRIBUTE_NODE as c_int {
return old;
}
unsafe { tree::unlink_node(cur) };
if unsafe { set_tree_doc_impl(cur, (*old).doc) } < 0 {
return ptr::null_mut();
}
(*cur).parent = (*old).parent;
(*cur).next = (*old).next;
if !(*cur).next.is_null() {
(*(*cur).next).prev = cur;
}
(*cur).prev = (*old).prev;
if !(*cur).prev.is_null() {
(*(*cur).prev).next = cur;
}
if !(*cur).parent.is_null() {
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
if (*(*cur).parent).properties == old as *mut _xmlAttr {
(*(*cur).parent).properties = cur as *mut _xmlAttr;
}
} else {
if (*(*cur).parent).children == old {
(*(*cur).parent).children = cur;
}
if (*(*cur).parent).last == old {
(*(*cur).parent).last = cur;
}
}
}
(*old).next = ptr::null_mut();
(*old).prev = ptr::null_mut();
(*old).parent = ptr::null_mut();
old
}
#[no_mangle]
pub unsafe extern "C" fn xmlGetNsListSafe(
doc: *const _xmlDoc,
node: *const _xmlNode,
out: *mut *mut *mut _xmlNs,
) -> c_int {
let _ = doc;
if out.is_null() {
return 1;
}
*out = ptr::null_mut();
if node.is_null() || (*node).type_ == XML_NAMESPACE_DECL as c_int {
return 1;
}
let mut namespaces: *mut *mut _xmlNs = ptr::null_mut();
let mut nbns: c_int = 0;
let mut maxns: c_int = 0;
let mut n = node;
while !n.is_null() {
if (*n).type_ == XML_ELEMENT_NODE as c_int {
let mut cur = (*n).nsDef;
while !cur.is_null() {
let mut i = 0;
let mut found = false;
while i < nbns {
if unsafe {
str_eq_or_ptr((*cur).prefix, (*(*namespaces).add(i as usize)).prefix)
} {
found = true;
break;
}
i += 1;
}
if !found {
if nbns >= maxns {
let new_size = if maxns <= 0 { 10 } else { maxns * 2 };
let tmp = unsafe {
xmlRealloc(
namespaces as *mut c_void,
((new_size + 1) as usize) * size_of::<*mut _xmlNs>(),
)
} as *mut *mut _xmlNs;
if tmp.is_null() {
unsafe { xmlFree(namespaces as *mut c_void) };
return -1;
}
namespaces = tmp;
maxns = new_size;
}
*namespaces.add(nbns as usize) = cur;
nbns += 1;
*namespaces.add(nbns as usize) = ptr::null_mut();
}
cur = (*cur).next;
}
}
n = (*n).parent;
}
*out = namespaces;
if namespaces.is_null() {
1
} else {
0
}
}
unsafe fn new_reconciled_ns(tree: *mut _xmlNode, ns: *mut _xmlNs) -> *mut _xmlNs {
if tree.is_null() || (*tree).type_ != XML_ELEMENT_NODE as c_int {
return ptr::null_mut();
}
if ns.is_null() || (*ns).type_ != XML_NAMESPACE_DECL as c_int {
return ptr::null_mut();
}
let def = unsafe { tree::search_ns_by_href(ptr::null_mut(), tree, (*ns).href) };
if !def.is_null() {
return def;
}
let prefix_base: Vec<u8> = if (*ns).prefix.is_null() {
b"default\0".to_vec()
} else {
unsafe { str_prefix((*ns).prefix, 20) }
};
let mut counter: c_int = 1;
let mut buf: Vec<u8> = prefix_base.clone();
loop {
let res = unsafe { tree::search_ns(ptr::null_mut(), tree, buf.as_ptr() as *const xmlChar) };
if res.is_null() {
break;
}
if counter > 1000 {
return ptr::null_mut();
}
let base = &prefix_base[..prefix_base.len().saturating_sub(1)];
let s = format!("{}{}", String::from_utf8_lossy(base), counter);
buf = s.into_bytes();
buf.push(0);
counter += 1;
}
unsafe { tree::new_ns(tree, (*ns).href, buf.as_ptr() as *const xmlChar) }
}
#[no_mangle]
pub unsafe extern "C" fn xmlReconciliateNs(doc: *mut _xmlDoc, tree: *mut _xmlNode) -> c_int {
let mut cache: Vec<(*mut _xmlNs, *mut _xmlNs)> = Vec::new();
let mut ret = 0;
if tree.is_null() || (*tree).type_ != XML_ELEMENT_NODE as c_int {
return -1;
}
if (*tree).doc != doc {
return -1;
}
let mut node = tree;
loop {
if !(*node).ns.is_null() {
let mut i = 0;
let mut found = false;
while i < cache.len() {
if cache[i].0 == (*node).ns {
(*node).ns = cache[i].1;
found = true;
break;
}
i += 1;
}
if !found {
let n = unsafe { new_reconciled_ns(tree, (*node).ns) };
if n.is_null() {
ret = -1;
} else {
cache.push(((*node).ns, n));
}
(*node).ns = n;
}
}
if (*node).type_ == XML_ELEMENT_NODE as c_int {
let mut attr = (*node).properties;
while !attr.is_null() {
if !(*attr).ns.is_null() {
let mut i = 0;
let mut found = false;
while i < cache.len() {
if cache[i].0 == (*attr).ns {
(*attr).ns = cache[i].1;
found = true;
break;
}
i += 1;
}
if !found {
let n = unsafe { new_reconciled_ns(tree, (*attr).ns) };
if n.is_null() {
ret = -1;
} else {
cache.push(((*attr).ns, n));
}
(*attr).ns = n;
}
}
attr = (*attr).next;
}
}
if !(*node).children.is_null() && (*node).type_ != XML_ENTITY_REF_NODE as c_int {
node = (*node).children;
} else if node != tree && !(*node).next.is_null() {
node = (*node).next;
} else if node != tree {
loop {
if node == tree {
break;
}
if !(*node).parent.is_null() {
node = (*node).parent;
}
if node != tree && !(*node).next.is_null() {
node = (*node).next;
break;
}
if (*node).parent.is_null() {
node = ptr::null_mut();
break;
}
}
if node == tree {
node = ptr::null_mut();
}
} else {
break;
}
if node.is_null() {
break;
}
}
ret
}
static XML_COMPRESS_MODE: AtomicI32 = AtomicI32::new(0);
#[no_mangle]
pub unsafe extern "C" fn xmlGetCompressMode() -> c_int {
XML_COMPRESS_MODE.load(Ordering::Relaxed)
}
#[no_mangle]
pub unsafe extern "C" fn xmlSetCompressMode(mode: c_int) {
let m = if mode < 0 {
0
} else if mode > 9 {
9
} else {
mode
};
XML_COMPRESS_MODE.store(m, Ordering::Relaxed);
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapNewCtxt() -> *mut _xmlDOMWrapCtxt {
unsafe { xmlMallocZero(size_of::<_xmlDOMWrapCtxt>()) as *mut _xmlDOMWrapCtxt }
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapFreeCtxt(ctxt: *mut _xmlDOMWrapCtxt) {
if ctxt.is_null() {
return;
}
if !(*ctxt).namespaceMap.is_null() {
unsafe { ns_map_free((*ctxt).namespaceMap as *mut NsMap) };
}
unsafe { xmlFree(ctxt as *mut c_void) };
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapRemoveNode(
ctxt: *mut _xmlDOMWrapCtxt,
doc: *mut _xmlDoc,
node: *mut _xmlNode,
options: c_int,
) -> c_int {
let _ = options;
let mut list: *mut *mut _xmlNs = ptr::null_mut();
let mut size_list: c_int = 0;
let mut nb_list: c_int = 0;
let mut ret = 0;
if node.is_null() || doc.is_null() || (*node).doc != doc {
return -1;
}
if (*node).parent.is_null() {
return 0;
}
match (*node).type_ as u32 {
t if t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_ENTITY_REF_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32 =>
{
unsafe { tree::unlink_node(node) };
return 0;
}
t if t == XML_ELEMENT_NODE as u32 || t == XML_ATTRIBUTE_NODE as u32 => {}
_ => return 1,
}
unsafe { tree::unlink_node(node) };
let mut cur = node;
'outer: loop {
let node_type = (*cur).type_;
match node_type as u32 {
t if t == XML_ELEMENT_NODE as u32 => {
if ctxt.is_null() && !(*cur).nsDef.is_null() {
let mut ns = (*cur).nsDef;
loop {
if unsafe {
ns_norm_add_ns_map_item2(
&mut list,
&mut size_list,
&mut nb_list,
ns,
ns,
)
} == -1
{
ret = -1;
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
}
if !(*cur).ns.is_null() {
let mut mapped = false;
if !list.is_null() {
let mut i = 0;
let mut j = 0;
while i < nb_list {
if (*cur).ns == *list.add(j as usize) {
(*cur).ns = *list.add((j + 1) as usize);
mapped = true;
break;
}
i += 1;
j += 2;
}
}
if !mapped {
let mut ns: *mut _xmlNs = ptr::null_mut();
if ctxt.is_null() {
ns = unsafe { store_ns(doc, (*(*cur).ns).href, (*(*cur).ns).prefix) };
if ns.is_null() {
ret = -1;
}
}
if !ns.is_null() {
if unsafe {
ns_norm_add_ns_map_item2(
&mut list,
&mut size_list,
&mut nb_list,
(*cur).ns,
ns,
)
} == -1
{
ret = -1;
}
}
(*cur).ns = ns;
}
}
if !(*cur).properties.is_null() {
cur = (*cur).properties as *mut _xmlNode;
continue 'outer;
}
}
t if t == XML_ATTRIBUTE_NODE as u32 => {
if !(*cur).ns.is_null() {
let mut mapped = false;
if !list.is_null() {
let mut i = 0;
let mut j = 0;
while i < nb_list {
if (*cur).ns == *list.add(j as usize) {
(*cur).ns = *list.add((j + 1) as usize);
mapped = true;
break;
}
i += 1;
j += 2;
}
}
if !mapped {
let mut ns: *mut _xmlNs = ptr::null_mut();
if ctxt.is_null() {
ns = unsafe { store_ns(doc, (*(*cur).ns).href, (*(*cur).ns).prefix) };
if ns.is_null() {
ret = -1;
}
}
if !ns.is_null() {
if unsafe {
ns_norm_add_ns_map_item2(
&mut list,
&mut size_list,
&mut nb_list,
(*cur).ns,
ns,
)
} == -1
{
ret = -1;
}
}
(*cur).ns = ns;
}
}
}
_ => {}
}
if node_type == XML_ELEMENT_NODE as c_int && !(*cur).children.is_null() {
cur = (*cur).children;
continue 'outer;
}
loop {
if cur.is_null() {
break 'outer;
}
if !(*cur).next.is_null() {
cur = (*cur).next;
break;
}
let t = (*cur).type_;
cur = (*cur).parent;
if t == XML_ATTRIBUTE_NODE as c_int && !cur.is_null() && !(*cur).children.is_null() {
cur = (*cur).children;
break;
}
if cur.is_null() {
break 'outer;
}
}
}
if !list.is_null() {
unsafe { xmlFree(list as *mut c_void) };
}
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapReconcileNamespaces(
ctxt: *mut _xmlDOMWrapCtxt,
elem: *mut _xmlNode,
options: c_int,
) -> c_int {
let _ = ctxt;
let mut depth: c_int = -1;
let mut adoptns: c_int = 0;
let mut parnsdone: c_int = 0;
let mut ns_map: *mut NsMap = ptr::null_mut();
let ancestors_only: c_int = 0;
let opt_remove_redundant = (options & XML_DOM_RECONNS_REMOVEREDUND) != 0;
let mut list_redund: *mut *mut _xmlNs = ptr::null_mut();
let mut size_redund: c_int = 0;
let mut nb_redund: c_int = 0;
let mut ret = 0;
if elem.is_null() || (*elem).doc.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
return -1;
}
let doc = (*elem).doc;
let mut cur = elem;
let mut cur_elem: *mut _xmlNode = ptr::null_mut();
'outer: loop {
match (*cur).type_ as u32 {
t if t == XML_ELEMENT_NODE as u32 => {
adoptns = 1;
cur_elem = cur;
depth += 1;
if !(*cur).nsDef.is_null() {
let mut prevns: *mut _xmlNs = ptr::null_mut();
let mut ns = (*cur).nsDef;
loop {
if parnsdone == 0 {
if !(*elem).parent.is_null()
&& (*elem).parent != (*(*elem).parent).doc as *mut _xmlNode
{
if unsafe { gather_in_scope_ns(&mut ns_map, (*elem).parent) } == -1
{
ret = -1;
}
}
parnsdone = 1;
}
if opt_remove_redundant && unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
let mut removed = false;
while !mi.is_null() {
if (*mi).depth >= XML_TREE_NSMAP_PARENT
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& unsafe { str_eq_or_ptr((*ns).prefix, (*(*mi).newNs).prefix) }
&& unsafe { str_eq_or_ptr((*ns).href, (*(*mi).newNs).href) }
{
if unsafe {
ns_norm_add_ns_map_item2(
&mut list_redund,
&mut size_redund,
&mut nb_redund,
ns,
(*mi).newNs,
)
} == -1
{
ret = -1;
} else {
let next_ns = (*ns).next;
if !prevns.is_null() {
(*prevns).next = next_ns;
} else {
(*cur).nsDef = next_ns;
}
ns = next_ns;
removed = true;
break;
}
}
mi = (*mi).next;
}
if removed {
if ns.is_null() {
break;
}
continue;
}
}
if !(*cur).ns.is_null() && adoptns != 0 && (*cur).ns == ns {
adoptns = 0;
}
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).depth >= XML_TREE_NSMAP_PARENT
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& unsafe { str_eq_or_ptr((*ns).prefix, (*(*mi).newNs).prefix) }
{
(*mi).shadowDepth = depth;
}
mi = (*mi).next;
}
}
if unsafe { ns_map_add_item(&mut ns_map, -1, ns, ns, depth) }.is_null() {
ret = -1;
}
prevns = ns;
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
}
if adoptns == 0 {
} else {
let _ = unsafe {
reconcile_ns_reference(
doc,
elem,
cur,
cur_elem,
&mut ns_map,
depth,
ancestors_only,
&mut ret,
&mut parnsdone,
&mut list_redund,
&mut size_redund,
&mut nb_redund,
)
};
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int && !(*cur).properties.is_null() {
cur = (*cur).properties as *mut _xmlNode;
continue 'outer;
}
}
t if t == XML_ATTRIBUTE_NODE as u32 => {
let _ = unsafe {
reconcile_ns_reference(
doc,
elem,
cur,
cur_elem,
&mut ns_map,
depth,
ancestors_only,
&mut ret,
&mut parnsdone,
&mut list_redund,
&mut size_redund,
&mut nb_redund,
)
};
}
_ => {
}
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int && !(*cur).children.is_null() {
cur = (*cur).children;
continue 'outer;
}
if cur == elem {
break;
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int {
unsafe { ns_map_pop_depth(ns_map, depth) };
depth -= 1;
}
if !(*cur).next.is_null() {
cur = (*cur).next;
} else {
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
cur = (*cur).parent;
if (*cur).type_ == XML_ELEMENT_NODE as c_int && !(*cur).children.is_null() {
cur = (*cur).children;
continue 'outer;
}
if cur == elem {
break;
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int {
unsafe { ns_map_pop_depth(ns_map, depth) };
depth -= 1;
}
if !(*cur).next.is_null() {
cur = (*cur).next;
} else {
cur = (*cur).parent;
if cur.is_null() {
break;
}
}
continue 'outer;
}
cur = (*cur).parent;
if cur.is_null() {
break;
}
}
}
if !list_redund.is_null() {
let mut i = 0;
let mut j = 0;
while i < nb_redund {
unsafe { free_ns_impl(*list_redund.add(j as usize)) };
i += 1;
j += 2;
}
unsafe { xmlFree(list_redund as *mut c_void) };
}
if !ns_map.is_null() {
unsafe { ns_map_free(ns_map) };
}
ret
}
unsafe fn reconcile_ns_reference(
doc: *mut _xmlDoc,
elem: *mut _xmlNode,
cur: *mut _xmlNode,
cur_elem: *mut _xmlNode,
ns_map: *mut *mut NsMap,
depth: c_int,
ancestors_only: c_int,
ret: &mut c_int,
parnsdone: &mut c_int,
list_redund: *mut *mut *mut _xmlNs,
_size_redund: *mut c_int,
nb_redund: *mut c_int,
) -> c_int {
if (*cur).ns.is_null() {
return 0;
}
if *parnsdone == 0 {
if !elem.is_null()
&& !(*elem).parent.is_null()
&& (*elem).parent != (*(*elem).parent).doc as *mut _xmlNode
{
if unsafe { gather_in_scope_ns(ns_map, (*elem).parent) } == -1 {
*ret = -1;
}
}
*parnsdone = 1;
}
if !list_redund.is_null() && !(*list_redund).is_null() && *nb_redund > 0 {
let list = *list_redund;
let mut i = 0;
let mut j = 0;
while i < *nb_redund {
if (*cur).ns == *list.add(j as usize) {
(*cur).ns = *list.add((j + 1) as usize);
return 0;
}
i += 1;
j += 2;
}
}
if unsafe { ns_map_not_empty(*ns_map) } {
let mut mi = (*(*ns_map)).first;
while !mi.is_null() {
if (*mi).shadowDepth == -1 && (*cur).ns == (*mi).oldNs {
(*cur).ns = (*mi).newNs;
return 0;
}
mi = (*mi).next;
}
}
let mut ns: *mut _xmlNs = ptr::null_mut();
if unsafe {
acquire_normalized_ns(
doc,
cur_elem,
(*cur).ns,
&mut ns,
ns_map,
depth,
ancestors_only,
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
1
} else {
0
},
)
} == -1
{
*ret = -1;
}
(*cur).ns = ns;
0
}
unsafe fn domwrap_adopt_branch(
ctxt: *mut _xmlDOMWrapCtxt,
node: *mut _xmlNode,
dest_doc: *mut _xmlDoc,
dest_parent: *mut _xmlNode,
) -> c_int {
let mut ret = 0;
let mut cur = node;
let mut cur_elem: *mut _xmlNode = ptr::null_mut();
let mut ns_map: *mut NsMap = ptr::null_mut();
let mut ns: *mut _xmlNs = ptr::null_mut();
let mut depth: c_int = -1;
let mut parnsdone: c_int;
let ancestors_only: c_int = 0;
let mut leave = false;
if !ctxt.is_null() {
ns_map = (*ctxt).namespaceMap as *mut NsMap;
}
if dest_parent.is_null() || (!ctxt.is_null() && (*ctxt).getNsForNodeFunc.is_some()) {
parnsdone = 1;
} else {
parnsdone = 0;
}
'outer: loop {
if !leave {
if (*cur).doc != dest_doc {
if unsafe { node_set_doc_impl(cur, dest_doc) } < 0 {
ret = -1;
}
}
match (*cur).type_ as u32 {
t if t == XML_XINCLUDE_START as u32 || t == XML_XINCLUDE_END as u32 => {
ret = -1;
leave = true;
}
t if t == XML_ELEMENT_NODE as u32 => {
cur_elem = cur;
depth += 1;
if !(*cur).nsDef.is_null()
&& (ctxt.is_null() || (*ctxt).getNsForNodeFunc.is_none())
{
if parnsdone == 0 {
if unsafe { gather_in_scope_ns(&mut ns_map, dest_parent) } == -1 {
ret = -1;
}
parnsdone = 1;
}
let mut ns2 = (*cur).nsDef;
loop {
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).depth >= XML_TREE_NSMAP_PARENT
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& unsafe {
str_eq_or_ptr((*ns2).prefix, (*(*mi).newNs).prefix)
}
{
(*mi).shadowDepth = depth;
}
mi = (*mi).next;
}
}
if unsafe { ns_map_add_item(&mut ns_map, -1, ns2, ns2, depth) }
.is_null()
{
ret = -1;
}
if (*ns2).next.is_null() {
break;
}
ns2 = (*ns2).next;
}
}
if !(*cur).ns.is_null() {
if parnsdone == 0 {
if unsafe { gather_in_scope_ns(&mut ns_map, dest_parent) } == -1 {
ret = -1;
}
parnsdone = 1;
}
let mut mapped = false;
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).shadowDepth == -1 && (*cur).ns == (*mi).oldNs {
(*cur).ns = (*mi).newNs;
mapped = true;
break;
}
mi = (*mi).next;
}
}
if !mapped {
if !ctxt.is_null() && (*ctxt).getNsForNodeFunc.is_some() {
let f = (*ctxt).getNsForNodeFunc.unwrap();
ns =
unsafe { f(ctxt, cur, (*(*cur).ns).href, (*(*cur).ns).prefix) };
unsafe {
ns_map_add_item(
&mut ns_map,
-1,
(*cur).ns,
ns,
XML_TREE_NSMAP_CUSTOM,
)
};
(*cur).ns = ns;
} else {
if unsafe {
acquire_normalized_ns(
dest_doc,
if dest_parent.is_null() {
ptr::null_mut()
} else {
cur_elem
},
(*cur).ns,
&mut ns,
&mut ns_map,
depth,
ancestors_only,
0,
)
} == -1
{
ret = -1;
}
(*cur).ns = ns;
}
}
}
(*cur).psvi = ptr::null_mut();
(*cur).line = 0;
(*cur).extra = 0;
if !(*cur).properties.is_null() {
cur = (*cur).properties as *mut _xmlNode;
continue 'outer;
}
}
t if t == XML_ATTRIBUTE_NODE as u32 => {
if !(*cur).ns.is_null() {
if parnsdone == 0 {
if unsafe { gather_in_scope_ns(&mut ns_map, dest_parent) } == -1 {
ret = -1;
}
parnsdone = 1;
}
let mut mapped = false;
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).shadowDepth == -1 && (*cur).ns == (*mi).oldNs {
(*cur).ns = (*mi).newNs;
mapped = true;
break;
}
mi = (*mi).next;
}
}
if !mapped {
if !ctxt.is_null() && (*ctxt).getNsForNodeFunc.is_some() {
let f = (*ctxt).getNsForNodeFunc.unwrap();
ns =
unsafe { f(ctxt, cur, (*(*cur).ns).href, (*(*cur).ns).prefix) };
unsafe {
ns_map_add_item(
&mut ns_map,
-1,
(*cur).ns,
ns,
XML_TREE_NSMAP_CUSTOM,
)
};
(*cur).ns = ns;
} else {
if unsafe {
acquire_normalized_ns(
dest_doc,
if dest_parent.is_null() {
ptr::null_mut()
} else {
cur_elem
},
(*cur).ns,
&mut ns,
&mut ns_map,
depth,
ancestors_only,
1,
)
} == -1
{
ret = -1;
}
(*cur).ns = ns;
}
}
}
}
t if t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32
|| t == XML_ENTITY_REF_NODE as u32 =>
{
leave = true;
}
_ => {
ret = -1;
leave = true;
}
}
if !leave {
if !(*cur).children.is_null() {
cur = (*cur).children;
continue 'outer;
}
leave = true;
}
}
leave = false;
if cur == node {
break;
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int
|| (*cur).type_ == XML_XINCLUDE_START as c_int
|| (*cur).type_ == XML_XINCLUDE_END as c_int
{
unsafe { ns_map_pop_depth(ns_map, depth) };
depth -= 1;
}
if !(*cur).next.is_null() {
cur = (*cur).next;
} else if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int
&& !(*cur).parent.is_null()
&& !(*(*cur).parent).children.is_null()
{
cur = (*(*cur).parent).children;
} else {
cur = (*cur).parent;
if cur.is_null() {
break;
}
leave = true;
}
}
if !ns_map.is_null() {
if !ctxt.is_null() && (*ctxt).namespaceMap == ns_map as *mut c_void {
if !(*ns_map).first.is_null() {
if !(*ns_map).pool.is_null() {
(*(*ns_map).last).next = (*ns_map).pool;
}
(*ns_map).pool = (*ns_map).first;
(*ns_map).first = ptr::null_mut();
}
} else {
unsafe { ns_map_free(ns_map) };
}
}
ret
}
unsafe fn domwrap_adopt_attr(
ctxt: *mut _xmlDOMWrapCtxt,
attr: *mut _xmlAttr,
dest_doc: *mut _xmlDoc,
dest_parent: *mut _xmlNode,
) -> c_int {
let _ = ctxt;
let mut ret = 0;
if attr.is_null() || dest_doc.is_null() {
return -1;
}
if (*attr).doc != dest_doc {
if unsafe { set_tree_doc_impl(attr as *mut _xmlNode, dest_doc) } < 0 {
ret = -1;
}
}
if !(*attr).ns.is_null() {
let mut ns: *mut _xmlNs = ptr::null_mut();
if unsafe { is_str_xml((*(*attr).ns).prefix) } {
ns = unsafe { ensure_xml_decl(dest_doc) };
} else if dest_parent.is_null() {
ns = unsafe { store_ns(dest_doc, (*(*attr).ns).href, (*(*attr).ns).prefix) };
} else {
if unsafe {
search_ns_by_namespace_strict(dest_doc, dest_parent, (*(*attr).ns).href, &mut ns, 1)
} == -1
{
ret = -1;
}
if ns.is_null() {
ns = unsafe {
declare_ns_forced(
dest_doc,
dest_parent,
(*(*attr).ns).href,
(*(*attr).ns).prefix,
1,
)
};
}
}
if ns.is_null() {
ret = -1;
}
(*attr).ns = ns;
}
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapAdoptNode(
ctxt: *mut _xmlDOMWrapCtxt,
sourceDoc: *mut _xmlDoc,
node: *mut _xmlNode,
destDoc: *mut _xmlDoc,
destParent: *mut _xmlNode,
options: c_int,
) -> c_int {
let _ = options;
let mut ret = 0;
if node.is_null()
|| (*node).type_ == XML_NAMESPACE_DECL as c_int
|| destDoc.is_null()
|| (!destParent.is_null() && (*destParent).doc != destDoc)
{
return -1;
}
let mut sourceDoc = sourceDoc;
if sourceDoc.is_null() {
sourceDoc = (*node).doc;
} else if (*node).doc != sourceDoc {
return -1;
}
if sourceDoc == destDoc {
return -1;
}
match (*node).type_ as u32 {
t if t == XML_ELEMENT_NODE as u32
|| t == XML_ATTRIBUTE_NODE as u32
|| t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_ENTITY_REF_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32 => {}
t if t == XML_DOCUMENT_FRAG_NODE as u32 => return 2,
_ => return 1,
}
if !(*node).parent.is_null() && destParent != (*node).parent {
unsafe { tree::unlink_node(node) };
}
if (*node).type_ == XML_ELEMENT_NODE as c_int {
return unsafe { domwrap_adopt_branch(ctxt, node, destDoc, destParent) };
} else if (*node).type_ == XML_ATTRIBUTE_NODE as c_int {
return unsafe { domwrap_adopt_attr(ctxt, node as *mut _xmlAttr, destDoc, destParent) };
} else {
if (*node).doc != destDoc {
if unsafe { node_set_doc_impl(node, destDoc) } < 0 {
ret = -1;
}
}
}
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlDOMWrapCloneNode(
ctxt: *mut _xmlDOMWrapCtxt,
sourceDoc: *mut _xmlDoc,
node: *mut _xmlNode,
resNode: *mut *mut _xmlNode,
destDoc: *mut _xmlDoc,
destParent: *mut _xmlNode,
deep: c_int,
options: c_int,
) -> c_int {
let _ = options;
const ST_NORMAL: u8 = 0;
const ST_INTO_CONTENT: u8 = 1;
const ST_LEAVE: u8 = 2;
let mut ret = 0;
let mut cur = node;
let mut clone_elem: *mut _xmlNode = ptr::null_mut();
let mut ns_map: *mut NsMap = ptr::null_mut();
let mut depth: c_int = -1;
let mut parnsdone: c_int = 0;
let ancestors_only: c_int = 0;
let mut result_clone: *mut _xmlNode = ptr::null_mut();
let mut clone: *mut _xmlNode = ptr::null_mut();
let mut parent_clone: *mut _xmlNode = ptr::null_mut();
let mut prev_clone: *mut _xmlNode = ptr::null_mut();
let mut clone_ns: *mut _xmlNs = ptr::null_mut();
let mut clone_ns_def_slot: *mut *mut _xmlNs = ptr::null_mut();
let mut state: u8 = ST_NORMAL;
if node.is_null()
|| resNode.is_null()
|| destDoc.is_null()
|| (!destParent.is_null() && (*destParent).doc != destDoc)
{
return -1;
}
if (*node).type_ != XML_ELEMENT_NODE as c_int {
return 1;
}
if !(*node).doc.is_null() && !sourceDoc.is_null() && (*node).doc != sourceDoc {
return -1;
}
let mut sourceDoc = sourceDoc;
if sourceDoc.is_null() {
sourceDoc = (*node).doc;
}
if sourceDoc.is_null() {
return -1;
}
if !ctxt.is_null() {
ns_map = (*ctxt).namespaceMap as *mut NsMap;
}
*resNode = ptr::null_mut();
'outer: loop {
if state == ST_NORMAL {
if (*cur).doc != sourceDoc {
ret = -1;
break;
}
let cur_type = (*cur).type_;
match cur_type as u32 {
t if t == XML_XINCLUDE_START as u32 || t == XML_XINCLUDE_END as u32 => {
ret = -1;
break;
}
t if t == XML_ELEMENT_NODE as u32
|| t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32
|| t == XML_COMMENT_NODE as u32
|| t == XML_PI_NODE as u32
|| t == XML_DOCUMENT_FRAG_NODE as u32
|| t == XML_ENTITY_REF_NODE as u32 =>
{
clone = unsafe { xmlMallocZero(size_of::<_xmlNode>()) } as *mut _xmlNode;
if clone.is_null() {
ret = -1;
break;
}
if !result_clone.is_null() {
(*clone).parent = parent_clone;
if !prev_clone.is_null() {
(*prev_clone).next = clone;
(*clone).prev = prev_clone;
} else {
(*parent_clone).children = clone;
}
(*parent_clone).last = clone;
} else {
result_clone = clone;
}
}
t if t == XML_ATTRIBUTE_NODE as u32 => {
clone = unsafe { xmlMallocZero(size_of::<_xmlAttr>()) } as *mut _xmlNode;
if clone.is_null() {
ret = -1;
break;
}
if !result_clone.is_null() {
(*clone).parent = parent_clone;
if !prev_clone.is_null() {
(*prev_clone).next = clone;
(*clone).prev = prev_clone;
} else {
(*parent_clone).properties = clone as *mut _xmlAttr;
}
} else {
result_clone = clone;
}
}
_ => {
ret = -1;
break;
}
}
if ret == -1 {
break;
}
(*clone).type_ = cur_type;
(*clone).doc = destDoc;
if !(*cur).name.is_null() {
(*clone).name = unsafe { dup_str((*cur).name) };
if (*clone).name.is_null() {
ret = -1;
break;
}
}
match cur_type as u32 {
t if t == XML_ELEMENT_NODE as u32 => {
clone_elem = clone;
depth += 1;
if !(*cur).nsDef.is_null() {
if parnsdone == 0 {
if !destParent.is_null() && ctxt.is_null() {
if unsafe { gather_in_scope_ns(&mut ns_map, destParent) } == -1 {
ret = -1;
break;
}
}
parnsdone = 1;
}
clone_ns_def_slot = core::ptr::addr_of_mut!((*clone).nsDef);
let mut ns = (*cur).nsDef;
loop {
clone_ns = unsafe { xmlMallocZero(size_of::<_xmlNs>()) } as *mut _xmlNs;
if clone_ns.is_null() {
ret = -1;
break;
}
(*clone_ns).type_ = XML_LOCAL_NAMESPACE as c_int;
if !(*ns).href.is_null() {
(*clone_ns).href = unsafe { dup_str((*ns).href) };
if (*clone_ns).href.is_null() {
unsafe { free_ns_impl(clone_ns) };
ret = -1;
break;
}
}
if !(*ns).prefix.is_null() {
(*clone_ns).prefix = unsafe { dup_str((*ns).prefix) };
if (*clone_ns).prefix.is_null() {
unsafe { free_ns_impl(clone_ns) };
ret = -1;
break;
}
}
*clone_ns_def_slot = clone_ns;
clone_ns_def_slot = core::ptr::addr_of_mut!((*clone_ns).next);
if ctxt.is_null() || (*ctxt).getNsForNodeFunc.is_none() {
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).depth >= XML_TREE_NSMAP_PARENT
&& (*mi).shadowDepth == -1
&& !(*mi).newNs.is_null()
&& unsafe {
str_eq_or_ptr((*ns).prefix, (*(*mi).newNs).prefix)
}
{
(*mi).shadowDepth = depth;
}
mi = (*mi).next;
}
}
if unsafe { ns_map_add_item(&mut ns_map, -1, ns, clone_ns, depth) }
.is_null()
{
ret = -1;
break;
}
}
if (*ns).next.is_null() {
break;
}
ns = (*ns).next;
}
if ret == -1 {
break;
}
}
}
t if t == XML_PI_NODE as u32
|| t == XML_COMMENT_NODE as u32
|| t == XML_TEXT_NODE as u32
|| t == XML_CDATA_SECTION_NODE as u32 =>
{
if !(*cur).content.is_null() {
(*clone).content = unsafe { dup_str((*cur).content) };
if (*clone).content.is_null() {
ret = -1;
break;
}
}
state = ST_LEAVE;
continue 'outer;
}
t if t == XML_ENTITY_REF_NODE as u32 => {
if sourceDoc != destDoc {
if !(*destDoc).intSubset.is_null() || !(*destDoc).extSubset.is_null() {
let ent = unsafe { tree::get_doc_entity(destDoc, (*cur).name) };
if !ent.is_null() {
(*clone).content = (*ent).content;
(*clone).children = ent as *mut _xmlNode;
(*clone).last = ent as *mut _xmlNode;
}
}
} else {
(*clone).content = (*cur).content;
(*clone).children = (*cur).children;
(*clone).last = (*cur).last;
}
state = ST_LEAVE;
continue 'outer;
}
_ => {
ret = -1;
break;
}
}
if ret == -1 {
break;
}
if !(*cur).ns.is_null() {
if parnsdone == 0 {
if !destParent.is_null() && ctxt.is_null() {
if unsafe { gather_in_scope_ns(&mut ns_map, destParent) } == -1 {
ret = -1;
break;
}
}
parnsdone = 1;
}
let mut mapped = false;
if unsafe { ns_map_not_empty(ns_map) } {
let mut mi = (*ns_map).first;
while !mi.is_null() {
if (*mi).shadowDepth == -1 && (*cur).ns == (*mi).oldNs {
(*clone).ns = (*mi).newNs;
mapped = true;
break;
}
mi = (*mi).next;
}
}
if !mapped {
if !ctxt.is_null() && (*ctxt).getNsForNodeFunc.is_some() {
let f = (*ctxt).getNsForNodeFunc.unwrap();
let ns = unsafe { f(ctxt, cur, (*(*cur).ns).href, (*(*cur).ns).prefix) };
unsafe {
ns_map_add_item(&mut ns_map, -1, (*cur).ns, ns, XML_TREE_NSMAP_CUSTOM)
};
(*clone).ns = ns;
} else {
let mut ns: *mut _xmlNs = ptr::null_mut();
if unsafe {
acquire_normalized_ns(
destDoc,
if destParent.is_null() {
ptr::null_mut()
} else {
clone_elem
},
(*cur).ns,
&mut ns,
&mut ns_map,
depth,
ancestors_only,
if (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
1
} else {
0
},
)
} == -1
{
ret = -1;
break;
}
(*clone).ns = ns;
}
}
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int && !(*cur).properties.is_null() {
prev_clone = ptr::null_mut();
parent_clone = clone;
cur = (*cur).properties as *mut _xmlNode;
continue 'outer; }
state = ST_INTO_CONTENT;
continue 'outer;
} else if state == ST_INTO_CONTENT {
if !(*cur).children.is_null() {
if deep != 0 || (*cur).type_ == XML_ATTRIBUTE_NODE as c_int {
prev_clone = ptr::null_mut();
parent_clone = clone;
cur = (*cur).children;
state = ST_NORMAL;
continue 'outer;
}
}
state = ST_LEAVE;
}
if cur == node {
break;
}
if (*cur).type_ == XML_ELEMENT_NODE as c_int
|| (*cur).type_ == XML_XINCLUDE_START as c_int
|| (*cur).type_ == XML_XINCLUDE_END as c_int
{
unsafe { ns_map_pop_depth(ns_map, depth) };
depth -= 1;
}
if !(*cur).next.is_null() {
prev_clone = clone;
cur = (*cur).next;
state = ST_NORMAL;
} else if (*cur).type_ != XML_ATTRIBUTE_NODE as c_int {
clone = (*clone).parent;
if !clone.is_null() {
parent_clone = (*clone).parent;
}
cur = (*cur).parent;
if cur.is_null() {
break;
}
state = ST_LEAVE;
} else {
clone = (*clone).parent;
parent_clone = (*clone).parent;
cur = (*cur).parent;
if cur.is_null() {
break;
}
state = ST_INTO_CONTENT;
}
}
if !ns_map.is_null() {
if !ctxt.is_null() && (*ctxt).namespaceMap == ns_map as *mut c_void {
if !(*ns_map).first.is_null() {
if !(*ns_map).pool.is_null() {
(*(*ns_map).last).next = (*ns_map).pool;
}
(*ns_map).pool = (*ns_map).first;
(*ns_map).first = ptr::null_mut();
}
} else {
unsafe { ns_map_free(ns_map) };
}
}
*resNode = result_clone;
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlCreateEntitiesTable() -> *mut c_void {
hash::hash_create(0) as *mut c_void
}
unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut xmlChar) {
if !payload.is_null() {
unsafe { entities::free_entity(payload as *mut _xmlEntity) };
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeEntitiesTable(table: *mut c_void) {
unsafe { hash::hash_free(table as *mut hash::HashTable, Some(free_entity_wrapper)) };
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewEntityInputStream(
ctxt: *mut _xmlParserCtxt,
entity: *mut _xmlEntity,
) -> *mut _xmlParserInput {
if ctxt.is_null() || entity.is_null() {
return ptr::null_mut();
}
if !(*entity).content.is_null() {
let input = unsafe { xmlMallocZero(size_of::<_xmlParserInput>()) } as *mut _xmlParserInput;
if input.is_null() {
return ptr::null_mut();
}
let len = unsafe { str_len((*entity).content) } as usize;
(*input).line = 1;
(*input).col = 1;
(*input).base = (*entity).content;
(*input).cur = (*entity).content;
(*input).end = (*entity).content.add(len);
(*input).length = len as c_int;
(*input).entity = entity;
(*input).buf = ptr::null_mut();
return input;
}
if !(*entity).URI.is_null() {
return ptr::null_mut();
}
ptr::null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn xmlCreateEnumeration(name: *const xmlChar) -> *mut _xmlEnumeration {
let ret = unsafe { xmlMallocZero(size_of::<_xmlEnumeration>()) } as *mut _xmlEnumeration;
if ret.is_null() {
return ptr::null_mut();
}
if !name.is_null() {
(*ret).name = unsafe { dup_str(name) };
if (*ret).name.is_null() {
unsafe { xmlFree(ret as *mut c_void) };
return ptr::null_mut();
}
}
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeEnumeration(cur: *mut _xmlEnumeration) {
let mut c = cur;
while !c.is_null() {
let next = (*c).next;
if !(*c).name.is_null() {
unsafe { xmlFree((*c).name as *mut c_void) };
}
unsafe { xmlFree(c as *mut c_void) };
c = next;
}
}
unsafe fn free_elem_content_internal(cur: *mut _xmlElementContent) {
if cur.is_null() {
return;
}
let mut depth: usize = 0;
let mut cur = cur;
loop {
while !(*cur).c1.is_null() || !(*cur).c2.is_null() {
cur = if !(*cur).c1.is_null() {
(*cur).c1
} else {
(*cur).c2
};
depth += 1;
}
if !(*cur).name.is_null() {
unsafe { xmlFree((*cur).name as *mut c_void) };
}
if !(*cur).prefix.is_null() {
unsafe { xmlFree((*cur).prefix as *mut c_void) };
}
let parent = (*cur).parent;
if depth == 0 || parent.is_null() {
unsafe { xmlFree(cur as *mut c_void) };
break;
}
if cur == (*parent).c1 {
(*parent).c1 = ptr::null_mut();
} else {
(*parent).c2 = ptr::null_mut();
}
unsafe { xmlFree(cur as *mut c_void) };
if !(*parent).c2.is_null() {
cur = (*parent).c2;
} else {
depth -= 1;
cur = parent;
}
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeDocElementContent(doc: *mut _xmlDoc, cur: *mut _xmlElementContent) {
let _ = doc;
unsafe { free_elem_content_internal(cur) };
}
unsafe extern "C" fn free_attribute_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
if !payload.is_null() {
unsafe { crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute) };
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeAttributeTable(table: *mut c_void) {
unsafe {
hash::hash_free(
table as *mut hash::HashTable,
Some(free_attribute_table_entry),
)
};
}
unsafe extern "C" fn free_element_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
if !payload.is_null() {
unsafe { crate::xml::dtd::free_element(payload as *mut _xmlElement) };
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeElementTable(table: *mut c_void) {
unsafe {
hash::hash_free(
table as *mut hash::HashTable,
Some(free_element_table_entry),
)
};
}
unsafe extern "C" fn free_notation_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
if !payload.is_null() {
unsafe { crate::xml::dtd::free_notation(payload as *mut _xmlNotation) };
}
}
#[no_mangle]
pub unsafe extern "C" fn xmlFreeNotationTable(table: *mut c_void) {
unsafe {
hash::hash_free(
table as *mut hash::HashTable,
Some(free_notation_table_entry),
)
};
}
unsafe extern "C" fn writer_push_write_cb(
ctx: *mut c_void,
buffer: *const c_char,
len: c_int,
) -> c_int {
let ctxt = ctx as *mut _xmlParserCtxt;
if ctxt.is_null() || buffer.is_null() {
return -1;
}
let rc = unsafe { crate::abi::exports_xml2::xmlParseChunk(ctxt, buffer, len, 0) };
if rc != 0 {
return -1;
}
len
}
unsafe extern "C" fn writer_push_close_cb(ctx: *mut c_void) -> c_int {
let ctxt = ctx as *mut _xmlParserCtxt;
if ctxt.is_null() {
return -1;
}
let rc = unsafe { crate::abi::exports_xml2::xmlParseChunk(ctxt, ptr::null(), 0, 1) };
if rc != 0 {
return -1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewTextWriterPushParser(
ctxt: *mut _xmlParserCtxt,
compression: c_int,
) -> *mut crate::xml::writer::XmlTextWriter {
let _ = compression;
if ctxt.is_null() {
return ptr::null_mut();
}
let out = crate::xml::io::output_buffer_create_io(
Some(writer_push_write_cb),
Some(writer_push_close_cb),
ctxt as *mut c_void,
ptr::null_mut(),
);
if out.is_null() {
return ptr::null_mut();
}
let ret = crate::xml::writer::xmlNewTextWriter(out);
if ret.is_null() {
crate::xml::io::output_buffer_close(out);
return ptr::null_mut();
}
ret
}
#[no_mangle]
pub unsafe extern "C" fn xmlNewGlobalNs(
_doc: *mut _xmlDoc,
_href: *const xmlChar,
_prefix: *const xmlChar,
) -> *mut _xmlNs {
ptr::null_mut()
}