use crate::abi::allocator::xmlFree;
use crate::abi::exports_xml2::{
xmlXPathCastToString, xmlXPathEvalExpression, xmlXPathFreeObject, xmlXPathNewNodeSet,
xmlXPathNodeSetCreate,
};
use crate::abi::structs::*;
use crate::abi::types::*;
use crate::xml::tree::doc_get_root_element;
use crate::xslt::patterns::{_xsltPattern, xsltCompilePattern, xsltFreePattern, xsltTestPattern};
use std::ffi::c_void;
use std::os::raw::c_int;
use std::ptr;
pub unsafe fn xsltAddKeyDef(
style: *mut _xsltStylesheet,
name: *const xmlChar,
match_pattern: *const xmlChar,
use_expr: *const xmlChar,
inst: *mut _xmlNode,
) -> c_int {
if style.is_null() || name.is_null() || match_pattern.is_null() || use_expr.is_null() {
return -1;
}
let def = libc::calloc(1, core::mem::size_of::<_xsltKeyDef>()) as *mut _xsltKeyDef;
if def.is_null() {
return -1;
}
(*def).style = style;
(*def).inst = inst;
(*def).name = name;
(*def).r#match = match_pattern;
(*def).r#use = use_expr;
(*def).next = (*style).keys;
(*style).keys = def;
0
}
pub unsafe fn xsltFreeKeyDef(key_def: *mut _xsltKeyDef) {
if key_def.is_null() {
return;
}
(*key_def).next = ptr::null_mut();
xmlFree(key_def as *mut libc::c_void);
}
pub unsafe fn xsltFreeKeys(style: *mut _xsltStylesheet) {
if style.is_null() {
return;
}
let mut cur = (*style).keys;
(*style).keys = ptr::null_mut();
while !cur.is_null() {
let next = (*cur).next;
xsltFreeKeyDef(cur);
cur = next;
}
}
pub unsafe fn xsltFreeKeyTable(key_table: *mut _xsltKeyTable) {
if key_table.is_null() {
return;
}
if !(*key_table).table.is_null() {
let mut i = 0;
while i < (*key_table).nb {
let obj = *(*key_table).table.offset(i as isize);
if !obj.is_null() {
xmlXPathFreeObject(obj);
}
i += 1;
}
libc::free((*key_table).table as *mut libc::c_void);
}
if !(*key_table).name.is_null() {
libc::free((*key_table).name as *mut libc::c_void);
}
(*key_table).next = ptr::null_mut();
xmlFree(key_table as *mut libc::c_void);
}
pub unsafe fn xsltFreeKeyTables(ctxt: *mut _xsltTransformContext) {
if ctxt.is_null() {
return;
}
let mut cur = (*ctxt).keyTables as *mut _xsltKeyTable;
(*ctxt).keyTables = ptr::null_mut();
while !cur.is_null() {
let next = (*cur).next;
xsltFreeKeyTable(cur);
cur = next;
}
}
pub unsafe fn xsltInitKeys(ctxt: *mut _xsltTransformContext, style: *mut _xsltStylesheet) -> c_int {
if ctxt.is_null() || style.is_null() {
return -1;
}
let doc = (*ctxt).document;
if doc.is_null() {
return 0;
}
let root = doc_get_root_element(doc);
if root.is_null() {
return 0;
}
let mut def = (*style).keys;
while !def.is_null() {
let pat = xsltCompilePattern((*def).r#match, doc);
if pat.is_null() {
def = (*def).next;
continue;
}
let use_expr = (*def).r#use;
let table = libc::calloc(1, core::mem::size_of::<_xsltKeyTable>()) as *mut _xsltKeyTable;
if table.is_null() {
xsltFreePattern(pat);
def = (*def).next;
continue;
}
let name_len = libc::strlen((*def).name as *const libc::c_char);
let cname = libc::malloc(name_len + 1) as *mut xmlChar;
if !cname.is_null() {
libc::memcpy(
cname as *mut libc::c_void,
(*def).name as *const libc::c_void,
name_len,
);
*cname.add(name_len) = 0;
}
(*table).name = cname;
(*table).depth = (*def).depth;
(*table).nb = 0;
(*table).max = 0;
(*table).table = ptr::null_mut();
build_key_table(ctxt, doc, root, pat, use_expr, table);
xsltFreePattern(pat);
(*table).next = (*ctxt).keyTables as *mut _xsltKeyTable;
(*ctxt).keyTables = table as *mut c_void;
def = (*def).next;
}
0
}
unsafe fn build_key_table(
ctxt: *mut _xsltTransformContext,
doc: *mut _xmlDoc,
node: *mut _xmlNode,
pattern: *mut _xsltPattern,
use_expr: *const xmlChar,
table: *mut _xsltKeyTable,
) {
if node.is_null() {
return;
}
if xsltTestPattern(ctxt, pattern, node) != 0 {
let xpath_ctxt = (*ctxt).xpathCtxt;
if !xpath_ctxt.is_null() && !use_expr.is_null() {
let saved_node = (*xpath_ctxt).node;
let saved_doc = (*xpath_ctxt).doc;
let saved_pos = (*xpath_ctxt).proximityPosition;
let saved_size = (*xpath_ctxt).contextSize;
(*xpath_ctxt).node = node;
(*xpath_ctxt).doc = doc;
(*xpath_ctxt).proximityPosition = 1;
(*xpath_ctxt).contextSize = 1;
let internal = (*xpath_ctxt).extra as *mut crate::xml::xpath::context::XPathContext;
if !internal.is_null() {
(*internal).context_node = node;
(*internal).document = doc;
(*internal).context_position = 1;
(*internal).context_size = 1;
(*internal).proximity_position = 1;
}
let obj = xmlXPathEvalExpression(use_expr, xpath_ctxt);
(*xpath_ctxt).node = saved_node;
(*xpath_ctxt).doc = saved_doc;
(*xpath_ctxt).proximityPosition = saved_pos;
(*xpath_ctxt).contextSize = saved_size;
if !internal.is_null() {
(*internal).context_node = saved_node;
(*internal).document = saved_doc;
(*internal).context_position = saved_pos;
(*internal).context_size = saved_size;
(*internal).proximity_position = saved_pos;
}
if !obj.is_null() {
let strv = xmlXPathCastToString(obj);
if !strv.is_null() {
add_key_entry(table, strv, node);
libc::free(strv as *mut libc::c_void);
}
xmlXPathFreeObject(obj);
}
}
}
let mut child = (*node).children;
while !child.is_null() {
let next = (*child).next;
build_key_table(ctxt, doc, child, pattern, use_expr, table);
child = next;
}
let mut prop = (*node).properties;
while !prop.is_null() {
let next = (*prop).next;
build_key_table(ctxt, doc, prop as *mut _xmlNode, pattern, use_expr, table);
prop = next;
}
}
unsafe fn add_key_entry(table: *mut _xsltKeyTable, value: *const xmlChar, node: *mut _xmlNode) {
if table.is_null() || value.is_null() || node.is_null() {
return;
}
let mut i = 0;
while i < (*table).nb {
let obj = *(*table).table.offset(i as isize);
if !obj.is_null()
&& (*obj).stringval != ptr::null_mut()
&& libc::strcmp(
(*obj).stringval as *const libc::c_char,
value as *const libc::c_char,
) == 0
{
let ns = (*obj).nodesetval as *mut _xmlNodeSet;
if !ns.is_null() {
if (*ns).nodeNr >= (*ns).nodeMax {
let new_max = if (*ns).nodeMax == 0 {
8
} else {
(*ns).nodeMax * 2
};
let new_tab = libc::realloc(
(*ns).nodeTab as *mut libc::c_void,
(new_max as usize) * core::mem::size_of::<*mut _xmlNode>(),
) as *mut *mut _xmlNode;
if new_tab.is_null() {
return;
}
(*ns).nodeTab = new_tab;
(*ns).nodeMax = new_max;
}
*(*ns).nodeTab.offset((*ns).nodeNr as isize) = node;
(*ns).nodeNr += 1;
}
return;
}
i += 1;
}
let obj = xmlXPathNewNodeSet(node);
if obj.is_null() {
return;
}
let vlen = libc::strlen(value as *const libc::c_char);
let vcopy = libc::malloc(vlen + 1) as *mut xmlChar;
if vcopy.is_null() {
xmlXPathFreeObject(obj);
return;
}
libc::memcpy(
vcopy as *mut libc::c_void,
value as *const libc::c_void,
vlen,
);
*vcopy.add(vlen) = 0;
(*obj).stringval = vcopy;
if (*table).nb >= (*table).max {
let new_max = if (*table).max == 0 {
16
} else {
(*table).max * 2
};
let new_tab = libc::realloc(
(*table).table as *mut libc::c_void,
(new_max as usize) * core::mem::size_of::<*mut _xmlXPathObject>(),
) as *mut *mut _xmlXPathObject;
if new_tab.is_null() {
xmlXPathFreeObject(obj);
return;
}
(*table).table = new_tab;
(*table).max = new_max;
}
*(*table).table.offset((*table).nb as isize) = obj;
(*table).nb += 1;
}
pub unsafe fn xsltEvalKeyFunction(
ctxt: *mut _xsltTransformContext,
name: *const xmlChar,
value: *const xmlChar,
) -> *mut _xmlNodeSet {
if ctxt.is_null() || name.is_null() || value.is_null() {
return ptr::null_mut();
}
let mut table = (*ctxt).keyTables as *mut _xsltKeyTable;
while !table.is_null() {
if !(*table).name.is_null()
&& libc::strcmp(
(*table).name as *const libc::c_char,
name as *const libc::c_char,
) == 0
{
let mut i = 0;
while i < (*table).nb {
let obj = *(*table).table.offset(i as isize);
if !obj.is_null()
&& !(*obj).stringval.is_null()
&& libc::strcmp(
(*obj).stringval as *const libc::c_char,
value as *const libc::c_char,
) == 0
{
let ns = (*obj).nodesetval as *mut _xmlNodeSet;
if ns.is_null() {
return ptr::null_mut();
}
let copy = xmlXPathNodeSetCreate(ptr::null_mut());
if copy.is_null() {
return ptr::null_mut();
}
let mut k = 0;
while k < (*ns).nodeNr {
let node = *(*ns).nodeTab.offset(k as isize);
add_to_node_set(copy, node);
k += 1;
}
return copy;
}
i += 1;
}
return ptr::null_mut();
}
table = (*table).next;
}
ptr::null_mut()
}
unsafe fn add_to_node_set(ns: *mut _xmlNodeSet, node: *mut _xmlNode) {
if ns.is_null() || node.is_null() {
return;
}
let mut i = 0;
while i < (*ns).nodeNr {
if *(*ns).nodeTab.offset(i as isize) == node {
return;
}
i += 1;
}
if (*ns).nodeNr >= (*ns).nodeMax {
let new_max = if (*ns).nodeMax == 0 {
8
} else {
(*ns).nodeMax * 2
};
let new_tab = libc::realloc(
(*ns).nodeTab as *mut libc::c_void,
(new_max as usize) * core::mem::size_of::<*mut _xmlNode>(),
) as *mut *mut _xmlNode;
if new_tab.is_null() {
return;
}
(*ns).nodeTab = new_tab;
(*ns).nodeMax = new_max;
}
*(*ns).nodeTab.offset((*ns).nodeNr as isize) = node;
(*ns).nodeNr += 1;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::abi::structs::*;
use core::ptr;
#[test]
fn test_add_key_def_null() {
unsafe {
assert_eq!(
xsltAddKeyDef(
ptr::null_mut(),
ptr::null(),
ptr::null(),
ptr::null(),
ptr::null_mut()
),
-1
);
}
}
#[test]
fn test_free_null() {
unsafe {
xsltFreeKeys(ptr::null_mut());
xsltFreeKeyDef(ptr::null_mut());
xsltFreeKeyTable(ptr::null_mut());
xsltFreeKeyTables(ptr::null_mut());
}
}
}