#![allow(non_snake_case)]
#![allow(unused_variables)]
use core::ptr;
use std::os::raw::{c_char, c_double, c_int, c_uint, c_void};
use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl};
use crate::abi::exports_buffer::xmlBufferCCat;
use crate::abi::exports_html::{htmlNewDoc, htmlNewDocNoDtD};
use crate::abi::exports_uri::xmlBuildURI;
use crate::abi::exports_xml2::{
xmlBufferCat, xmlBufferContent, xmlBufferCreate, xmlBufferFree, xmlCreateIntSubset,
xmlDocGetRootElement, xmlNewDoc, xmlStrEqual, xmlStrdup, xmlStrndup,
xmlXPathCastStringToNumber, xmlXPathCastToString, xmlXPathCmpNodes, xmlXPathFreeObject,
};
use crate::abi::exports_xslt_apply::_xsltCompMatch;
use crate::abi::exports_xslt_avt::{xsltEvalAttrValueTemplate, xsltGetQNameURI};
use crate::abi::structs::*;
use crate::abi::types::xmlElementType::*;
use crate::abi::types::*;
use crate::xml::uri::xmlURIEscapeStr;
use crate::xml::xpath::exports::{xmlXPathIsInf, xmlXPathIsNaN};
const XSLT_NAMESPACE_URI: &[u8] = b"http://www.w3.org/1999/XSL/Transform\0";
const XSLT_OUTPUT_XML: c_int = 0;
const XSLT_OUTPUT_HTML: c_int = 1;
const XSLT_OUTPUT_TEXT: c_int = 2;
const XML_CHAR_ENCODING_UTF8: c_int = 3;
const XSLT_SAXON_NAMESPACE: &[u8] = b"http://icl.com/saxon\0";
const XSLT_XALAN_NAMESPACE: &[u8] = b"http://xml.apache.org/xalan\0";
const XSLT_MAX_SORT: c_int = 15;
const XSLT_FUNC_PARAM: c_int = 19;
const XSLT_FUNC_VARIABLE: c_int = 20;
pub type xsltSortFunc = unsafe extern "C" fn(*mut _xsltTransformContext, *mut *mut _xmlNode, c_int);
static mut XSLT_SORT_FUNCTION: Option<xsltSortFunc> = None;
unsafe fn emit_generic_error(msg: &[u8]) {
let handler = crate::abi::data_globals::xsltGenericError;
if let Some(f) = handler {
let mut cmsg = msg.to_vec();
cmsg.push(0);
f(
crate::abi::data_globals::xsltGenericErrorContext,
cmsg.as_ptr() as *const c_char,
);
} else {
let _ = libc::write(2, msg.as_ptr() as *const c_void, msg.len());
}
}
#[allow(dead_code)]
unsafe fn xml_chars_equal(a: *const xmlChar, b: *const xmlChar) -> bool {
if a.is_null() || b.is_null() {
return false;
}
libc::strcmp(a as *const libc::c_char, b as *const libc::c_char) == 0
}
unsafe fn xslt_get_utf8_char_z(utf: *const xmlChar, len: *mut c_int) -> c_int {
if utf.is_null() || len.is_null() {
if !len.is_null() {
*len = 0;
}
return -1;
}
let mut c: u32 = *utf as u32;
if c & 0x80 != 0 {
if (*(utf.add(1)) & 0xc0) != 0x80 {
*len = 0;
return -1;
}
if (c & 0xe0) == 0xe0 {
if (*(utf.add(2)) & 0xc0) != 0x80 {
*len = 0;
return -1;
}
if (c & 0xf0) == 0xf0 {
if (c & 0xf8) != 0xf0 || (*(utf.add(3)) & 0xc0) != 0x80 {
*len = 0;
return -1;
}
*len = 4;
c = (((*utf & 0x7) as u32) << 18)
| (((*utf.add(1) & 0x3f) as u32) << 12)
| (((*utf.add(2) & 0x3f) as u32) << 6)
| ((*(utf.add(3)) & 0x3f) as u32);
} else {
*len = 3;
c = (((*utf & 0xf) as u32) << 12)
| (((*utf.add(1) & 0x3f) as u32) << 6)
| ((*(utf.add(2)) & 0x3f) as u32);
}
} else {
*len = 2;
c = (((*utf & 0x1f) as u32) << 6) | ((*(utf.add(1)) & 0x3f) as u32);
}
} else {
*len = 1;
}
c as c_int
}
const unsafe fn xslt_is_digit_zero(ch: c_int) -> c_int {
match ch {
0x0030 | 0x0660 | 0x06f0 | 0x0966 | 0x09e6 | 0x0a66 | 0x0ae6 | 0x0b66 | 0x0c66 | 0x0ce6
| 0x0d66 | 0x0e50 | 0x0ed0 | 0x0f20 => 1,
_ => 0,
}
}
const unsafe fn xslt_is_digit_one(ch: c_int) -> c_int {
xslt_is_digit_zero(ch - 1)
}
unsafe fn xslt_is_letter_digit(val: c_int) -> bool {
if crate::xml::chvalid::xmlIsLetter(val) != 0 {
return true;
}
crate::xml::chvalid::xmlIsDigit(val as c_uint) != 0
}
unsafe fn test_comp_match(
context: *mut _xsltTransformContext,
node: *mut _xmlNode,
pat: *mut _xsltCompMatch,
) -> c_int {
if pat.is_null() {
return 0;
}
crate::xslt::patterns::xsltTestPattern(
context,
(*pat).pattern as *mut crate::xslt::patterns::_xsltPattern,
node,
)
}
unsafe fn xslt_test_comp_match_count(
context: *mut _xsltTransformContext,
node: *mut _xmlNode,
count_pat: *mut _xsltCompMatch,
cur: *mut _xmlNode,
) -> c_int {
if !count_pat.is_null() {
return test_comp_match(context, node, count_pat);
}
if (*node).type_ != (*cur).type_ {
return 0;
}
if (*node).type_ == XML_NAMESPACE_DECL as c_int {
return 1;
}
if xmlStrEqual((*node).name, (*cur).name) == 0 {
return 0;
}
if (*node).ns == (*cur).ns {
return 1;
}
if (*node).ns.is_null() || (*cur).ns.is_null() {
return 0;
}
xmlStrEqual((*(*node).ns).href, (*(*cur).ns).href)
}
#[derive(Debug)]
#[repr(C)]
pub struct _xsltNumberData {
pub level: *const xmlChar,
pub count: *const xmlChar,
pub from: *const xmlChar,
pub value: *const xmlChar,
pub format: *const xmlChar,
pub has_format: c_int,
pub digitsPerGroup: c_int,
pub groupingCharacter: c_int,
pub groupingCharacterLen: c_int,
pub doc: *mut _xmlDoc,
pub node: *mut _xmlNode,
pub countPat: *mut _xsltCompMatch,
pub fromPat: *mut _xsltCompMatch,
}
pub type xsltNumberDataPtr = *mut _xsltNumberData;
const MAX_TOKENS: usize = 1024;
#[repr(C)]
#[derive(Clone, Copy)]
struct xsltFormatToken {
separator: *mut xmlChar,
token: c_int,
width: c_int,
}
#[repr(C)]
struct xsltFormat {
start: *mut xmlChar,
tokens: [xsltFormatToken; MAX_TOKENS],
nTokens: c_int,
end: *mut xmlChar,
}
unsafe fn xslt_copy_char_multi_byte(mut out: *mut xmlChar, val: c_int) -> c_int {
if out.is_null() || val < 0 {
return 0;
}
if val >= 0x80 {
let savedout = out;
let mut bits: c_int;
if val < 0x800 {
*out = ((val >> 6) | 0xC0) as xmlChar;
out = out.add(1);
bits = 0;
} else if val < 0x10000 {
*out = ((val >> 12) | 0xE0) as xmlChar;
out = out.add(1);
bits = 6;
} else if val < 0x110000 {
*out = ((val >> 18) | 0xF0) as xmlChar;
out = out.add(1);
bits = 12;
} else {
return 0;
}
while bits >= 0 {
*out = (((val >> bits) & 0x3F) | 0x80) as u8;
out = out.add(1);
bits -= 6;
}
return (out as isize - savedout as isize) as c_int;
}
*out = val as xmlChar;
1
}
unsafe fn xslt_number_format_decimal(
buffer: *mut _xmlBuffer,
number: f64,
digit_zero: c_int,
width: c_int,
digits_per_group: c_int,
grouping_character: c_int,
grouping_character_len: c_int,
) {
let mut temp_string: [xmlChar; 500] = [0; 500];
let base = temp_string.as_mut_ptr();
let mut pointer = base.add(500).sub(1);
*pointer = 0;
let mut number = number;
let mut i: c_int = 0;
while pointer > base {
if (i >= width) && number.abs() < 1.0 {
break;
}
if (i > 0)
&& (grouping_character != 0)
&& (digits_per_group > 0)
&& ((i % digits_per_group) == 0)
{
if pointer.offset(-(grouping_character_len as isize)) < base {
i = -1;
break;
}
pointer = pointer.offset(-(grouping_character_len as isize));
xslt_copy_char_multi_byte(pointer, grouping_character);
}
let val = digit_zero + (number).rem_euclid(10.0) as c_int;
if val < 0x80 {
if pointer <= base {
i = -1;
break;
}
pointer = pointer.sub(1);
*pointer = val as xmlChar;
} else {
let mut temp_char: [xmlChar; 6] = [0; 6];
let len = xslt_copy_char_multi_byte(temp_char.as_mut_ptr(), val);
if pointer.offset(-(len as isize)) < base {
i = -1;
break;
}
pointer = pointer.offset(-(len as isize));
libc::memcpy(
pointer as *mut libc::c_void,
temp_char.as_ptr() as *const libc::c_void,
len as usize,
);
}
number /= 10.0;
i += 1;
}
if i < 0 {
emit_generic_error(b"xsltNumberFormatDecimal: Internal buffer size exceeded\n\0");
}
xmlBufferCat(buffer, pointer);
}
unsafe fn xslt_number_format_alpha(
data: *mut _xsltNumberData,
buffer: *mut _xmlBuffer,
number: f64,
is_upper: c_int,
) {
const ALPHA_UPPER: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const ALPHA_LOWER: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
let alpha_size: f64 = 26.0;
if number < 1.0 {
xslt_number_format_decimal(
buffer,
number,
b'0' as c_int,
1,
(*data).digitsPerGroup,
(*data).groupingCharacter,
(*data).groupingCharacterLen,
);
return;
}
let mut temp_string: [u8; 65] = [0; 65];
let mut pointer = temp_string.as_mut_ptr().add(65);
pointer = pointer.sub(1);
*pointer = 0;
let alpha_list: &[u8] = if is_upper != 0 {
ALPHA_UPPER
} else {
ALPHA_LOWER
};
let mut number = number;
let mut i: c_int = 1;
while i < temp_string.len() as c_int {
number -= 1.0;
pointer = pointer.sub(1);
*pointer = alpha_list[(number).rem_euclid(alpha_size) as usize];
number /= alpha_size;
if number < 1.0 {
break;
}
i += 1;
}
xmlBufferCCat(buffer, pointer as *const c_char);
}
unsafe fn xslt_number_format_roman(
data: *mut _xsltNumberData,
buffer: *mut _xmlBuffer,
number: f64,
is_upper: c_int,
) {
if number < 1.0 || number > 5000.0 {
xslt_number_format_decimal(
buffer,
number,
b'0' as c_int,
1,
(*data).digitsPerGroup,
(*data).groupingCharacter,
(*data).groupingCharacterLen,
);
return;
}
let mut number = number;
let hi = |s: &[u8]| -> Vec<u8> {
if is_upper != 0 {
s.to_vec()
} else {
s.to_ascii_lowercase()
}
};
let ccat_hi = |s: &[u8], n: &mut f64, dec: f64| {
xmlBufferCCat(buffer, hi(s).as_ptr() as *const c_char);
*n -= dec;
};
while number >= 1000.0 {
ccat_hi(b"M", &mut number, 1000.0);
}
if number >= 900.0 {
ccat_hi(b"CM", &mut number, 900.0);
}
while number >= 500.0 {
ccat_hi(b"D", &mut number, 500.0);
}
if number >= 400.0 {
ccat_hi(b"CD", &mut number, 400.0);
}
while number >= 100.0 {
ccat_hi(b"C", &mut number, 100.0);
}
if number >= 90.0 {
ccat_hi(b"XC", &mut number, 90.0);
}
while number >= 50.0 {
ccat_hi(b"L", &mut number, 50.0);
}
if number >= 40.0 {
ccat_hi(b"XL", &mut number, 40.0);
}
while number >= 10.0 {
ccat_hi(b"X", &mut number, 10.0);
}
if number >= 9.0 {
ccat_hi(b"IX", &mut number, 9.0);
}
while number >= 5.0 {
ccat_hi(b"V", &mut number, 5.0);
}
if number >= 4.0 {
ccat_hi(b"IV", &mut number, 4.0);
}
while number >= 1.0 {
ccat_hi(b"I", &mut number, 1.0);
}
}
unsafe fn xslt_number_format_tokenize(format: *const xmlChar, tokens: *mut xsltFormat) {
let mut ix: usize = 0;
let mut len: c_int = 0;
(*tokens).start = ptr::null_mut();
(*tokens).tokens[0].separator = ptr::null_mut();
(*tokens).end = ptr::null_mut();
let mut val = xslt_get_utf8_char_z(format.add(ix), &mut len);
while !xslt_is_letter_digit(val) {
if *format.add(ix) == 0 {
break;
}
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
}
if ix > 0 {
(*tokens).start = xmlStrndup(format, ix as c_int);
}
(*tokens).nTokens = 0;
while ((*tokens).nTokens as usize) < MAX_TOKENS {
if *format.add(ix) == 0 {
break;
}
if (*tokens).nTokens > 0 {
(*tokens).tokens[(*tokens).nTokens as usize].separator = (*tokens).end;
(*tokens).end = ptr::null_mut();
}
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
if xslt_is_digit_one(val) != 0 || xslt_is_digit_zero(val) != 0 {
(*tokens).tokens[(*tokens).nTokens as usize].width = 1;
while xslt_is_digit_zero(val) != 0 {
(*tokens).tokens[(*tokens).nTokens as usize].width += 1;
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
}
if xslt_is_digit_one(val) != 0 {
(*tokens).tokens[(*tokens).nTokens as usize].token = val - 1;
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
} else {
(*tokens).tokens[(*tokens).nTokens as usize].token = b'0' as c_int;
(*tokens).tokens[(*tokens).nTokens as usize].width = 1;
}
} else if val == b'A' as c_int
|| val == b'a' as c_int
|| val == b'I' as c_int
|| val == b'i' as c_int
{
(*tokens).tokens[(*tokens).nTokens as usize].token = val;
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
} else {
(*tokens).tokens[(*tokens).nTokens as usize].token = b'0' as c_int;
(*tokens).tokens[(*tokens).nTokens as usize].width = 1;
}
while xslt_is_letter_digit(val) {
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
}
let j = ix;
while !xslt_is_letter_digit(val) {
if val == 0 {
break;
}
ix += len as usize;
val = xslt_get_utf8_char_z(format.add(ix), &mut len);
}
if ix > j {
(*tokens).end = xmlStrndup(format.add(j), (ix - j) as c_int);
}
(*tokens).nTokens += 1;
}
}
unsafe fn default_token() -> xsltFormatToken {
static DEFAULT_SEPARATOR: [u8; 2] = *b".\0";
xsltFormatToken {
separator: DEFAULT_SEPARATOR.as_ptr() as *mut xmlChar,
token: b'0' as c_int,
width: 1,
}
}
unsafe fn xslt_number_format_insert_numbers(
data: *mut _xsltNumberData,
numbers: *mut f64,
numbers_max: c_int,
tokens: *mut xsltFormat,
buffer: *mut _xmlBuffer,
) {
let mut i: c_int = 0;
let mut number: f64;
let mut token: xsltFormatToken;
if !(*tokens).start.is_null() {
xmlBufferCat(buffer, (*tokens).start);
}
while i < numbers_max {
number = *numbers.offset((numbers_max - 1 - i) as isize);
number = (number + 0.5).floor();
if number < 0.0 {
crate::xslt::errors::xsltTransformError(
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
c"xsl-number : negative value\n".as_ptr() as *const c_char,
);
number = 0.0;
}
if (i as usize) < (*tokens).nTokens as usize {
token = (*tokens).tokens[i as usize];
} else if (*tokens).nTokens > 0 {
token = (*tokens).tokens[((*tokens).nTokens - 1) as usize];
} else {
token = default_token();
}
if i > 0 {
if !token.separator.is_null() {
xmlBufferCat(buffer, token.separator);
} else {
xmlBufferCCat(buffer, c".".as_ptr() as *const c_char);
}
}
let inf = xmlXPathIsInf(number as c_double);
if inf == -1 {
xmlBufferCCat(buffer, c"-Infinity".as_ptr() as *const c_char);
} else if inf == 1 {
xmlBufferCCat(buffer, c"Infinity".as_ptr() as *const c_char);
} else if xmlXPathIsNaN(number as c_double) != 0 {
xmlBufferCCat(buffer, c"NaN".as_ptr() as *const c_char);
} else {
match token.token {
65 => {
xslt_number_format_alpha(data, buffer, number, 1);
}
97 => {
xslt_number_format_alpha(data, buffer, number, 0);
}
73 => {
xslt_number_format_roman(data, buffer, number, 1);
}
105 => {
xslt_number_format_roman(data, buffer, number, 0);
}
_ => {
if xslt_is_digit_zero(token.token) != 0 {
xslt_number_format_decimal(
buffer,
number,
token.token,
token.width,
(*data).digitsPerGroup,
(*data).groupingCharacter,
(*data).groupingCharacterLen,
);
}
}
}
}
i += 1;
}
if !(*tokens).end.is_null() {
xmlBufferCat(buffer, (*tokens).end);
}
}
unsafe fn xslt_number_format_get_any_level(
context: *mut _xsltTransformContext,
node: *mut _xmlNode,
count_pat: *mut _xsltCompMatch,
from_pat: *mut _xsltCompMatch,
array: *mut f64,
) -> c_int {
let mut cnt: c_int = 0;
let mut cur = node;
while !cur.is_null() {
if xslt_test_comp_match_count(context, cur, count_pat, node) != 0 {
cnt += 1;
}
if !from_pat.is_null() && test_comp_match(context, cur, from_pat) != 0 {
break;
}
let typ = (*cur).type_;
if typ == XML_DOCUMENT_NODE as c_int || typ == XML_HTML_DOCUMENT_NODE as c_int {
break;
}
if typ == XML_NAMESPACE_DECL as c_int {
cur = (*(cur as *mut _xmlNs)).next as *mut _xmlNode;
} else if typ == XML_ATTRIBUTE_NODE as c_int {
cur = (*cur).parent;
} else {
while !(*cur).prev.is_null() {
let pt = (*(*cur).prev).type_;
if pt != XML_DTD_NODE as c_int
&& pt != XML_XINCLUDE_START as c_int
&& pt != XML_XINCLUDE_END as c_int
{
break;
}
cur = (*cur).prev;
}
if !(*cur).prev.is_null() {
cur = (*cur).prev;
while !(*cur).last.is_null() {
cur = (*cur).last;
}
} else {
cur = (*cur).parent;
}
}
}
*array.offset(0) = cnt as f64;
1
}
unsafe fn xslt_number_format_get_multiple_level(
context: *mut _xsltTransformContext,
node: *mut _xmlNode,
count_pat: *mut _xsltCompMatch,
from_pat: *mut _xsltCompMatch,
array: *mut f64,
max: c_int,
) -> c_int {
let mut amount: c_int = 0;
let mut ancestor = node;
while !ancestor.is_null() && (*ancestor).type_ != XML_DOCUMENT_NODE as c_int {
if !from_pat.is_null() && test_comp_match(context, ancestor, from_pat) != 0 {
break;
}
if xslt_test_comp_match_count(context, ancestor, count_pat, node) != 0 {
let mut cnt: c_int = 1;
let mut preceding = if (*ancestor).type_ != XML_NAMESPACE_DECL as c_int {
(*ancestor).prev
} else {
ptr::null_mut()
};
while !preceding.is_null() {
if xslt_test_comp_match_count(context, preceding, count_pat, node) != 0 {
cnt += 1;
}
preceding = (*preceding).prev;
}
*array.offset(amount as isize) = cnt as f64;
amount += 1;
if amount >= max {
break;
}
}
if !ancestor.is_null() && (*ancestor).type_ == XML_NAMESPACE_DECL as c_int {
let ns = ancestor as *mut _xmlNs;
if !(*ns).next.is_null() && (*(*ns).next).type_ != XML_NAMESPACE_DECL as c_int {
ancestor = (*ns).next as *mut _xmlNode;
} else {
ancestor = ptr::null_mut();
}
} else {
ancestor = (*ancestor).parent;
}
}
amount
}
unsafe fn xslt_number_format_get_value(
context: *mut _xsltTransformContext,
node: *mut _xmlNode,
value: *const xmlChar,
number: *mut f64,
) -> c_int {
let mut amount: c_int = 0;
let pattern = xmlBufferCreate();
if !pattern.is_null() {
xmlBufferCCat(pattern, c"number(".as_ptr() as *const c_char);
xmlBufferCat(pattern, value);
xmlBufferCCat(pattern, c")".as_ptr() as *const c_char);
let old_node = (*context).node;
(*context).node = node;
let obj = crate::xslt::transform::eval_xpath(context, xmlBufferContent(pattern));
if !obj.is_null() {
*number = (*obj).floatval;
amount += 1;
xmlXPathFreeObject(obj);
}
xmlBufferFree(pattern);
(*context).node = old_node;
}
amount
}
#[no_mangle]
pub unsafe extern "C" fn xsltAttribute(
ctxt: *mut _xsltTransformContext,
contextNode: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || contextNode.is_null() || inst.is_null() {
return;
}
if (*inst).type_ != XML_ELEMENT_NODE as c_int {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = contextNode;
crate::xslt::transform::process_attribute(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltElement(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
if (*ctxt).insert.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_element(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltText(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
comp: *mut c_void,
) {
let _ = (node, comp);
if ctxt.is_null() || inst.is_null() {
return;
}
if (*inst).children.is_null() {
return;
}
crate::xslt::transform::process_text(ctxt, inst);
}
#[no_mangle]
pub unsafe extern "C" fn xsltComment(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
comp: *mut c_void,
) {
let _ = comp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_comment(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltProcessingInstruction(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
if (*ctxt).insert.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_pi(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltCopy(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_copy(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltCopyOf(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_copy_of(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltValueOf(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_value_of(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltNumber(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = node;
crate::xslt::transform::process_number(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltChoose(
ctxt: *mut _xsltTransformContext,
contextNode: *mut _xmlNode,
inst: *mut _xmlNode,
comp: *mut c_void,
) {
let _ = comp;
if ctxt.is_null() || contextNode.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = contextNode;
crate::xslt::transform::process_choose(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltIf(
ctxt: *mut _xsltTransformContext,
contextNode: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || contextNode.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = contextNode;
crate::xslt::transform::process_if(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltForEach(
ctxt: *mut _xsltTransformContext,
contextNode: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || contextNode.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
(*ctxt).node = contextNode;
crate::xslt::transform::process_for_each(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltMessage(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
) {
if ctxt.is_null() || inst.is_null() {
return;
}
let old_node = (*ctxt).node;
if !node.is_null() {
(*ctxt).node = node;
}
crate::xslt::transform::process_message(ctxt, inst);
(*ctxt).node = old_node;
}
#[no_mangle]
pub unsafe extern "C" fn xsltNumberFormat(
ctxt: *mut _xsltTransformContext,
data: xsltNumberDataPtr,
node: *mut _xmlNode,
) {
if ctxt.is_null() || data.is_null() {
return;
}
let mut tokens: xsltFormat = core::mem::zeroed();
if !(*data).format.is_null() {
xslt_number_format_tokenize((*data).format, &mut tokens);
} else {
if (*data).has_format == 0 {
return;
}
let format = xsltEvalAttrValueTemplate(
ctxt,
(*data).node,
c"format".as_ptr() as *const xmlChar,
XSLT_NAMESPACE_URI.as_ptr() as *const xmlChar,
);
if format.is_null() {
return;
}
xslt_number_format_tokenize(format, &mut tokens);
xmlFreeImpl(format as *mut c_void);
}
let output = xmlBufferCreate();
if output.is_null() {
cleanup_tokens(&mut tokens);
return;
}
if !(*data).value.is_null() {
let mut number: f64 = 0.0;
let amount = xslt_number_format_get_value(ctxt, node, (*data).value, &mut number);
if amount == 1 {
xslt_number_format_insert_numbers(data, &mut number, 1, &mut tokens, output);
}
} else if !(*data).level.is_null() {
if xmlStrEqual((*data).level, c"single".as_ptr() as *const xmlChar) != 0 {
let mut number: f64 = 0.0;
let amount = xslt_number_format_get_multiple_level(
ctxt,
node,
(*data).countPat,
(*data).fromPat,
&mut number,
1,
);
if amount == 1 {
xslt_number_format_insert_numbers(data, &mut number, 1, &mut tokens, output);
}
} else if xmlStrEqual((*data).level, c"multiple".as_ptr() as *const xmlChar) != 0 {
let mut numarray: [f64; 1024] = [0.0; 1024];
let max = (numarray.len()) as c_int;
let amount = xslt_number_format_get_multiple_level(
ctxt,
node,
(*data).countPat,
(*data).fromPat,
numarray.as_mut_ptr(),
max,
);
if amount > 0 {
xslt_number_format_insert_numbers(
data,
numarray.as_mut_ptr(),
amount,
&mut tokens,
output,
);
}
} else if xmlStrEqual((*data).level, c"any".as_ptr() as *const xmlChar) != 0 {
let mut number: f64 = 0.0;
let amount = xslt_number_format_get_any_level(
ctxt,
node,
(*data).countPat,
(*data).fromPat,
&mut number,
);
if amount > 0 {
xslt_number_format_insert_numbers(data, &mut number, 1, &mut tokens, output);
}
}
if !(*data).countPat.is_null() {
crate::abi::exports_xslt_apply::xsltCompMatchClearCache(ctxt, (*data).countPat);
}
if !(*data).fromPat.is_null() {
crate::abi::exports_xslt_apply::xsltCompMatchClearCache(ctxt, (*data).fromPat);
}
}
crate::xslt::transform::append_text_node(ctxt, xmlBufferContent(output));
xmlBufferFree(output);
cleanup_tokens(&mut tokens);
}
unsafe fn cleanup_tokens(tokens: *mut xsltFormat) {
if !(*tokens).start.is_null() {
xmlFreeImpl((*tokens).start as *mut c_void);
}
if !(*tokens).end.is_null() {
xmlFreeImpl((*tokens).end as *mut c_void);
}
let mut i: c_int = 0;
while i < (*tokens).nTokens {
if !(*tokens).tokens[i as usize].separator.is_null() {
xmlFreeImpl((*tokens).tokens[i as usize].separator as *mut c_void);
}
i += 1;
}
}
#[no_mangle]
pub unsafe extern "C" fn xsltFormatNumberConversion(
self_: *mut _xsltDecimalFormat,
format: *mut xmlChar,
number: f64,
result: *mut *mut xmlChar,
) -> c_int {
if result.is_null() {
return XPATH_MEMORY_ERROR as c_int;
}
crate::xslt::numbering::xslt_format_number_conversion(self_, format, number, result)
}
#[no_mangle]
pub unsafe extern "C" fn xsltDecimalFormatGetByName(
style: *mut _xsltStylesheet,
name: *mut xmlChar,
) -> *mut _xsltDecimalFormat {
if style.is_null() {
return ptr::null_mut();
}
if name.is_null() {
return (*style).decimalFormat;
}
let mut cur_style = style;
while !cur_style.is_null() {
if !(*cur_style).decimalFormat.is_null() {
let mut result = (*(*cur_style).decimalFormat).next;
while !result.is_null() {
if (*result).nsUri.is_null()
&& xmlStrEqual(name as *const xmlChar, (*result).name) != 0
{
return result;
}
result = (*result).next;
}
}
cur_style = crate::abi::exports_xslt_apply::xsltNextImport(cur_style);
}
ptr::null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn xsltDecimalFormatGetByQName(
style: *mut _xsltStylesheet,
nsUri: *const xmlChar,
name: *const xmlChar,
) -> *mut _xsltDecimalFormat {
if style.is_null() {
return ptr::null_mut();
}
if name.is_null() {
return (*style).decimalFormat;
}
let mut cur_style = style;
while !cur_style.is_null() {
if !(*cur_style).decimalFormat.is_null() {
let mut result = (*(*cur_style).decimalFormat).next;
while !result.is_null() {
if xmlStrEqual(nsUri, (*result).nsUri) != 0
&& xmlStrEqual(name, (*result).name) != 0
{
return result;
}
result = (*result).next;
}
}
cur_style = crate::abi::exports_xslt_apply::xsltNextImport(cur_style);
}
ptr::null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn xsltSort(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
comp: *mut c_void,
) {
let _ = node;
if ctxt.is_null() || inst.is_null() {
return;
}
if comp.is_null() {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsl:sort : compilation failed\n".as_ptr() as *const c_char,
);
return;
}
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsl:sort : improper use this should not be reached\n".as_ptr() as *const c_char,
);
}
#[no_mangle]
pub unsafe extern "C" fn xsltDefaultSortFunction(
ctxt: *mut _xsltTransformContext,
sorts: *mut *mut _xmlNode,
nbsorts: c_int,
) {
if ctxt.is_null() || sorts.is_null() || nbsorts <= 0 || nbsorts >= XSLT_MAX_SORT {
return;
}
if (*sorts).is_null() {
return;
}
let list = (*ctxt).nodeList;
if list.is_null() || (*list).nodeNr <= 1 {
return;
}
let style = (*ctxt).style;
let mut chain_head: *mut _xsltSort = ptr::null_mut();
let mut chain_tail: *mut _xsltSort = ptr::null_mut();
let mut j: c_int = 0;
while j < nbsorts {
let inst = *sorts.offset(j as isize);
if !inst.is_null() {
let s = crate::xslt::sorting::xsltCompileSort(style, inst);
if !s.is_null() {
if chain_tail.is_null() {
chain_head = s;
chain_tail = s;
} else {
(*chain_tail).next = s;
chain_tail = s;
}
}
}
j += 1;
}
if chain_head.is_null() {
return;
}
crate::xslt::sorting::xsltSortNodeSet(ctxt, list, chain_head);
crate::xslt::sorting::xsltFreeSortList(chain_head);
}
#[no_mangle]
pub unsafe extern "C" fn xsltDoSortFunction(
ctxt: *mut _xsltTransformContext,
sorts: *mut *mut _xmlNode,
nbsorts: c_int,
) {
if ctxt.is_null() {
return;
}
let sf = (*ctxt).sortfunc;
if !sf.is_null() {
let f: xsltSortFunc = core::mem::transmute(sf);
f(ctxt, sorts, nbsorts);
return;
}
let global = unsafe { XSLT_SORT_FUNCTION };
if let Some(f) = global {
f(ctxt, sorts, nbsorts);
} else {
xsltDefaultSortFunction(ctxt, sorts, nbsorts);
}
}
#[no_mangle]
pub unsafe extern "C" fn xsltDocumentSortFunction(list: *mut _xmlNodeSet) {
if list.is_null() {
return;
}
let len = (*list).nodeNr;
if len <= 1 {
return;
}
let tab = (*list).nodeTab;
if tab.is_null() {
return;
}
let mut i: c_int = 0;
while i < len - 1 {
let mut j = i + 1;
while j < len {
let tst = xmlXPathCmpNodes(*tab.offset(i as isize), *tab.offset(j as isize));
if tst == -1 {
let node = *tab.offset(i as isize);
*tab.offset(i as isize) = *tab.offset(j as isize);
*tab.offset(j as isize) = node;
}
j += 1;
}
i += 1;
}
}
#[no_mangle]
pub unsafe extern "C" fn xsltComputeSortResult(
ctxt: *mut _xsltTransformContext,
sort: *mut _xmlNode,
) -> *mut *mut _xmlXPathObject {
if ctxt.is_null() || sort.is_null() {
return ptr::null_mut();
}
let style = (*ctxt).style;
let compiled = crate::xslt::sorting::xsltCompileSort(style, sort);
if compiled.is_null() {
emit_generic_error(b"xsl:sort : compilation failed\n\0");
return ptr::null_mut();
}
if (*compiled).select.is_null() {
crate::xslt::sorting::xsltFreeSortList(compiled);
return ptr::null_mut();
}
let list = (*ctxt).nodeList;
if list.is_null() || (*list).nodeNr <= 1 {
crate::xslt::sorting::xsltFreeSortList(compiled);
return ptr::null_mut();
}
let len = (*list).nodeNr;
let is_number = (*compiled).isText == 0;
let results = xmlMallocImpl(len as usize * core::mem::size_of::<*mut _xmlXPathObject>())
as *mut *mut _xmlXPathObject;
if results.is_null() {
emit_generic_error(b"xsltComputeSortResult: memory allocation failure\n\0");
crate::xslt::sorting::xsltFreeSortList(compiled);
return ptr::null_mut();
}
let xpath_ctxt = (*ctxt).xpathCtxt;
let old_node = (*ctxt).node;
let (old_pos, old_size) = if xpath_ctxt.is_null() {
(0, 0)
} else {
((*xpath_ctxt).proximityPosition, (*xpath_ctxt).contextSize)
};
let mut i: c_int = 0;
while i < len {
let node = *(*list).nodeTab.offset(i as isize);
(*ctxt).node = node;
if !xpath_ctxt.is_null() {
(*xpath_ctxt).node = node;
(*xpath_ctxt).contextSize = len;
(*xpath_ctxt).proximityPosition = i + 1;
}
let key = crate::xslt::sorting::xsltEvalSortKey(ctxt, node, compiled);
if key.is_null() {
(*ctxt).state = crate::xslt::transform::XSLT_STATE_STOPPED;
*results.offset(i as isize) = ptr::null_mut();
} else {
let obj =
libc::calloc(1, core::mem::size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
if obj.is_null() {
*results.offset(i as isize) = ptr::null_mut();
xmlFreeImpl(key as *mut c_void);
} else if is_number {
(*obj).type_ = xmlXPathObjectType::XPATH_NUMBER as c_int;
(*obj).floatval = xmlXPathCastStringToNumber(key);
(*obj).index = i;
*results.offset(i as isize) = obj;
xmlFreeImpl(key as *mut c_void);
} else {
(*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
(*obj).stringval = key;
(*obj).index = i;
*results.offset(i as isize) = obj;
}
}
i += 1;
}
(*ctxt).node = old_node;
if !xpath_ctxt.is_null() {
(*xpath_ctxt).node = old_node;
(*xpath_ctxt).proximityPosition = old_pos;
(*xpath_ctxt).contextSize = old_size;
}
crate::xslt::sorting::xsltFreeSortList(compiled);
results
}
#[no_mangle]
pub unsafe extern "C" fn xsltSetSortFunc(handler: Option<xsltSortFunc>) {
unsafe {
XSLT_SORT_FUNCTION = if handler.is_some() {
handler
} else {
Some(xsltDefaultSortFunction)
};
}
}
#[no_mangle]
pub unsafe extern "C" fn xsltSetCtxtSortFunc(
ctxt: *mut _xsltTransformContext,
handler: Option<xsltSortFunc>,
) {
if ctxt.is_null() {
return;
}
(*ctxt).sortfunc = match handler {
Some(f) => f as *const c_void as *mut c_void,
None => ptr::null_mut(),
};
}
#[no_mangle]
pub unsafe extern "C" fn xsltDocumentElem(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
castedComp: *mut c_void,
) {
let _ = castedComp;
if ctxt.is_null() || node.is_null() || inst.is_null() {
return;
}
let mut ret: c_int;
let mut URL: *mut xmlChar = ptr::null_mut();
let mut filename: *mut xmlChar = ptr::null_mut();
let mut prop: *mut xmlChar;
let mut style: *mut _xsltStylesheet = ptr::null_mut();
let mut res: *mut _xmlDoc = ptr::null_mut();
let mut redirect_write_append: c_int = 0;
let inst_name = (*inst).name;
if xmlStrEqual(inst_name, c"output".as_ptr() as *const xmlChar) != 0 {
URL = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"file".as_ptr() as *const xmlChar,
XSLT_SAXON_NAMESPACE.as_ptr() as *const xmlChar,
);
if URL.is_null() {
URL = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"href".as_ptr() as *const xmlChar,
XSLT_SAXON_NAMESPACE.as_ptr() as *const xmlChar,
);
}
} else if xmlStrEqual(inst_name, c"write".as_ptr() as *const xmlChar) != 0 {
URL = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"select".as_ptr() as *const xmlChar,
XSLT_XALAN_NAMESPACE.as_ptr() as *const xmlChar,
);
if !URL.is_null() {
let obj = crate::xslt::transform::eval_xpath(ctxt, URL);
let val = if obj.is_null() {
ptr::null_mut()
} else {
let v = xmlXPathCastToString(obj);
xmlXPathFreeObject(obj);
v
};
xmlFreeImpl(URL as *mut c_void);
URL = val;
}
if URL.is_null() {
URL = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"file".as_ptr() as *const xmlChar,
XSLT_XALAN_NAMESPACE.as_ptr() as *const xmlChar,
);
}
if URL.is_null() {
URL = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"href".as_ptr() as *const xmlChar,
XSLT_XALAN_NAMESPACE.as_ptr() as *const xmlChar,
);
}
} else if xmlStrEqual(inst_name, c"document".as_ptr() as *const xmlChar) != 0 {
URL =
xsltEvalAttrValueTemplate(ctxt, inst, c"href".as_ptr() as *const xmlChar, ptr::null());
}
if URL.is_null() {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: href/URI-Reference not found\n".as_ptr() as *const c_char,
);
return;
}
filename = xmlBuildURI(URL as *const c_char, (*ctxt).outputFile);
if filename.is_null() {
let esc_url = xmlURIEscapeStr(URL, c":/.?,".as_ptr() as *const xmlChar);
if !esc_url.is_null() {
filename = xmlBuildURI(esc_url as *const c_char, (*ctxt).outputFile);
xmlFreeImpl(esc_url as *mut c_void);
}
}
if filename.is_null() {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: URL computation failed\n".as_ptr() as *const c_char,
);
xmlFreeImpl(URL as *mut c_void);
return;
}
if !(*ctxt).sec.is_null() {
let check = crate::xslt::security::xsltGetSecurityPrefs(
(*ctxt).sec,
crate::xslt::security::XSLT_SECPREF_WRITE_FILE,
);
ret = match check {
Some(f) => f(ctxt as *mut c_void, (*ctxt).sec, filename as *const c_char),
None => 1,
};
if ret <= 0 {
if ret == 0 {
let path = String::from_utf8_lossy(
crate::abi::versioning::c_str_to_bytes(filename as *const c_char)
.unwrap_or_default(),
);
let fmsg = format!("File write for {} refused\n", path);
if let Ok(fc) = std::ffi::CString::new(fmsg) {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
fc.as_ptr(),
);
}
let dmsg = format!("xsltDocumentElem: write rights for {} denied\n", path);
if let Ok(dc) = std::ffi::CString::new(dmsg) {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
dc.as_ptr(),
);
}
}
xmlFreeImpl(URL as *mut c_void);
xmlFreeImpl(filename as *mut c_void);
return;
}
}
let old_output_file = (*ctxt).outputFile;
let old_output = (*ctxt).output;
let old_insert = (*ctxt).insert;
let old_type = (*ctxt).type_;
(*ctxt).outputFile = filename as *const c_char;
style = crate::xslt::stylesheet::xsltStylesheetCreate();
if style.is_null() {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: out of memory\n".as_ptr() as *const c_char,
);
goto_error(
ctxt,
old_output,
old_insert,
old_type,
old_output_file,
URL,
filename,
style,
res,
);
return;
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"version".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if !(*style).version.is_null() {
xmlFreeImpl((*style).version as *mut c_void);
}
(*style).version = prop;
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"encoding".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if !(*style).encoding.is_null() {
xmlFreeImpl((*style).encoding as *mut c_void);
}
(*style).encoding = prop;
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"method".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
let mut method_name: *mut xmlChar = prop;
let uri = xsltGetQNameURI(inst, &mut method_name);
if method_name.is_null() {
(*style).errors += 1;
} else if uri.is_null() {
if xmlStrEqual(method_name, c"xml".as_ptr() as *const xmlChar) != 0
|| xmlStrEqual(method_name, c"html".as_ptr() as *const xmlChar) != 0
|| xmlStrEqual(method_name, c"text".as_ptr() as *const xmlChar) != 0
{
(*style).method = method_name;
} else {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"invalid value for method\n".as_ptr() as *const c_char,
);
(*style).warnings += 1;
xmlFreeImpl(method_name as *mut c_void);
}
} else {
(*style).method = method_name;
(*style).methodURI = xmlStrdup(uri);
}
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"doctype-system".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if !(*style).doctypeSystem.is_null() {
xmlFreeImpl((*style).doctypeSystem as *mut c_void);
}
(*style).doctypeSystem = prop;
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"doctype-public".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if !(*style).doctypePublic.is_null() {
xmlFreeImpl((*style).doctypePublic as *mut c_void);
}
(*style).doctypePublic = prop;
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"standalone".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if xmlStrEqual(prop, c"yes".as_ptr() as *const xmlChar) != 0 {
(*style).standalone = 1;
} else if xmlStrEqual(prop, c"no".as_ptr() as *const xmlChar) != 0 {
(*style).standalone = 0;
} else {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"invalid value for standalone\n".as_ptr() as *const c_char,
);
(*style).warnings += 1;
}
xmlFreeImpl(prop as *mut c_void);
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"indent".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if xmlStrEqual(prop, c"yes".as_ptr() as *const xmlChar) != 0 {
(*style).indent = 1;
} else if xmlStrEqual(prop, c"no".as_ptr() as *const xmlChar) != 0 {
(*style).indent = 0;
} else {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"invalid value for indent\n".as_ptr() as *const c_char,
);
(*style).warnings += 1;
}
xmlFreeImpl(prop as *mut c_void);
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"omit-xml-declaration".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if xmlStrEqual(prop, c"yes".as_ptr() as *const xmlChar) != 0 {
(*style).omitXmlDeclaration = 1;
} else if xmlStrEqual(prop, c"no".as_ptr() as *const xmlChar) != 0 {
(*style).omitXmlDeclaration = 0;
} else {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"invalid value for omit-xml-declaration\n".as_ptr() as *const c_char,
);
(*style).warnings += 1;
}
xmlFreeImpl(prop as *mut c_void);
}
let elements = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"cdata-section-elements".as_ptr() as *const xmlChar,
ptr::null(),
);
if !elements.is_null() {
if (*style).stripSpaces.is_null() {
(*style).stripSpaces = crate::xml::hash::hash_create(10) as *mut c_void;
}
if !(*style).stripSpaces.is_null() {
let mut element: *mut xmlChar = elements;
while *element != 0 {
while crate::xml::chvalid::xmlIsBlank(*element as c_uint) != 0 {
element = element.add(1);
}
if *element == 0 {
break;
}
let mut end = element;
while *end != 0 && crate::xml::chvalid::xmlIsBlank(*end as c_uint) == 0 {
end = end.add(1);
}
let mut el = xmlStrndup(element, (end as isize - element as isize) as c_int);
if !el.is_null() {
let uri = xsltGetQNameURI(inst, &mut el);
crate::xml::hash::hash_add_entry2(
(*style).stripSpaces as *mut crate::xml::hash::HashTable,
el,
uri,
c"cdata".as_ptr() as *mut c_void,
);
xmlFreeImpl(el as *mut c_void);
}
element = end;
}
}
xmlFreeImpl(elements as *mut c_void);
}
let method: *const xmlChar = (*style).method;
let doctype_public: *const xmlChar = (*style).doctypePublic;
let doctype_system: *const xmlChar = (*style).doctypeSystem;
let version: *const xmlChar = (*style).version;
let encoding: *const xmlChar = (*style).encoding;
if !method.is_null() && xmlStrEqual(method, c"xml".as_ptr() as *const xmlChar) == 0 {
if xmlStrEqual(method, c"html".as_ptr() as *const xmlChar) != 0 {
(*ctxt).type_ = XSLT_OUTPUT_HTML;
if !doctype_public.is_null() || !doctype_system.is_null() {
res = htmlNewDoc(doctype_system, doctype_public);
} else {
res = htmlNewDocNoDtD(doctype_system, doctype_public);
}
} else if xmlStrEqual(method, c"xhtml".as_ptr() as *const xmlChar) != 0 {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: unsupported method xhtml\n".as_ptr() as *const c_char,
);
(*ctxt).type_ = XSLT_OUTPUT_HTML;
res = htmlNewDocNoDtD(doctype_system, doctype_public);
} else if xmlStrEqual(method, c"text".as_ptr() as *const xmlChar) != 0 {
(*ctxt).type_ = XSLT_OUTPUT_TEXT;
res = xmlNewDoc(version);
} else {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: unsupported method\n".as_ptr() as *const c_char,
);
goto_error(
ctxt,
old_output,
old_insert,
old_type,
old_output_file,
URL,
filename,
style,
res,
);
return;
}
} else {
(*ctxt).type_ = XSLT_OUTPUT_XML;
res = xmlNewDoc(version);
}
if res.is_null() {
goto_error(
ctxt,
old_output,
old_insert,
old_type,
old_output_file,
URL,
filename,
style,
res,
);
return;
}
(*res).charset = XML_CHAR_ENCODING_UTF8;
if !encoding.is_null() {
(*res).encoding = xmlStrdup(encoding);
}
(*ctxt).output = res;
(*ctxt).insert = res as *mut _xmlNode;
(*ctxt).node = node;
crate::xslt::transform::execute_content(ctxt, (*inst).children);
let root = xmlDocGetRootElement(res);
if !root.is_null() {
let mut doctype: *const xmlChar = ptr::null();
if !(*root).ns.is_null() && !(*(*root).ns).prefix.is_null() && !(*ctxt).dict.is_null() {
let plen = crate::xml::string::xml_strlen((*(*root).ns).prefix);
let nlen = crate::xml::string::xml_strlen((*root).name);
let mut qn = Vec::with_capacity(plen + 1 + nlen);
qn.extend_from_slice(core::slice::from_raw_parts((*(*root).ns).prefix, plen));
qn.push(b':');
qn.extend_from_slice(core::slice::from_raw_parts((*root).name, nlen));
qn.push(0);
doctype = crate::xml::dictionary::dict_lookup(
(*ctxt).dict as *mut crate::xml::dictionary::Dict,
qn.as_ptr() as *const xmlChar,
(plen + 1 + nlen) as c_int,
);
}
if doctype.is_null() {
doctype = (*root).name;
}
if method.is_null()
&& (*root).ns.is_null()
&& libc::strcasecmp(
(*root).name as *const c_char,
c"html".as_ptr() as *const c_char,
) == 0
{
let mut tmp = (*res).children;
while !tmp.is_null() && tmp != root {
if (*tmp).type_ == XML_ELEMENT_NODE as c_int {
break;
}
if (*tmp).type_ == XML_TEXT_NODE as c_int
&& crate::xml::chvalid::xmlIsBlankNode(tmp) == 0
{
break;
}
tmp = (*tmp).next;
}
if tmp == root {
(*ctxt).type_ = XSLT_OUTPUT_HTML;
(*res).type_ = XML_HTML_DOCUMENT_NODE as c_int;
if !doctype_public.is_null() || !doctype_system.is_null() {
(*res).intSubset =
xmlCreateIntSubset(res, doctype, doctype_public, doctype_system);
}
}
}
if (*ctxt).type_ == XSLT_OUTPUT_XML
&& (!doctype_public.is_null() || !doctype_system.is_null())
{
(*res).intSubset = xmlCreateIntSubset(res, doctype, doctype_public, doctype_system);
}
}
prop = xsltEvalAttrValueTemplate(
ctxt,
inst,
c"append".as_ptr() as *const xmlChar,
ptr::null(),
);
if !prop.is_null() {
if xmlStrEqual(prop, c"true".as_ptr() as *const xmlChar) != 0
|| xmlStrEqual(prop, c"yes".as_ptr() as *const xmlChar) != 0
{
(*style).omitXmlDeclaration = 1;
redirect_write_append = 1;
} else {
(*style).omitXmlDeclaration = 0;
}
xmlFreeImpl(prop as *mut c_void);
}
if redirect_write_append != 0 {
let f = libc::fopen(filename as *const c_char, c"ab".as_ptr() as *const c_char);
if f.is_null() {
ret = -1;
} else {
ret = crate::xslt::serialization::xsltSaveResultToFile(f as *mut c_void, res, style);
libc::fclose(f);
}
} else {
ret = crate::xslt::serialization::xsltSaveResultToFilename(
filename as *const c_char,
res,
style,
0,
);
}
if ret < 0 {
crate::xslt::errors::xsltTransformError(
ctxt,
ptr::null_mut(),
inst,
c"xsltDocumentElem: unable to save result\n".as_ptr() as *const c_char,
);
}
goto_error(
ctxt,
old_output,
old_insert,
old_type,
old_output_file,
URL,
filename,
style,
res,
);
}
#[allow(clippy::too_many_arguments)]
unsafe fn goto_error(
ctxt: *mut _xsltTransformContext,
old_output: *mut _xmlDoc,
old_insert: *mut _xmlNode,
old_type: c_int,
old_output_file: *const c_char,
url: *mut xmlChar,
filename: *mut xmlChar,
style: *mut _xsltStylesheet,
res: *mut _xmlDoc,
) {
(*ctxt).output = old_output;
(*ctxt).insert = old_insert;
(*ctxt).type_ = old_type;
(*ctxt).outputFile = old_output_file;
if !url.is_null() {
xmlFreeImpl(url as *mut c_void);
}
if !filename.is_null() {
xmlFreeImpl(filename as *mut c_void);
}
if !style.is_null() {
crate::xslt::stylesheet::xsltFreeStylesheet(style);
}
if !res.is_null() {
crate::xml::tree::free_doc(res);
}
}
#[no_mangle]
pub unsafe extern "C" fn xsltDebug(
ctxt: *mut _xsltTransformContext,
node: *mut _xmlNode,
inst: *mut _xmlNode,
comp: *mut c_void,
) {
let _ = (node, inst, comp);
if ctxt.is_null() {
return;
}
let mut i: c_int = 0;
let mut j = (*ctxt).templNr - 1;
emit_generic_error(b"Templates:\n\0");
if !(*ctxt).templTab.is_null() {
while i < 15 && j >= 0 {
let msg = format!("#{} ", i);
emit_generic_error(msg.as_bytes());
let t = *(*ctxt).templTab.offset(j as isize);
if !t.is_null() {
if !(*t).name.is_null() {
let m = format!("name {} ", bytes_to_lossy((*t).name));
emit_generic_error(m.as_bytes());
}
if !(*t).r#match.is_null() {
let m = format!("name {} ", bytes_to_lossy((*t).r#match));
emit_generic_error(m.as_bytes());
}
if !(*t).mode.is_null() {
let m = format!("name {} ", bytes_to_lossy((*t).mode));
emit_generic_error(m.as_bytes());
}
}
emit_generic_error(b"\n\0");
i += 1;
j -= 1;
}
}
emit_generic_error(b"Variables:\n\0");
i = 0;
j = (*ctxt).varsNr - 1;
if !(*ctxt).varsTab.is_null() {
while i < 15 && j >= 0 {
let cur = *(*ctxt).varsTab.offset(j as isize);
if cur.is_null() {
j -= 1;
i += 1;
continue;
}
let msg = format!("#{}\n", i);
emit_generic_error(msg.as_bytes());
let p = cur;
if (*p).comp.is_null() {
emit_generic_error(b"corrupted !!!\n\0");
} else {
let typ = *((*p).comp as *const c_int);
if typ == XSLT_FUNC_PARAM {
emit_generic_error(b"param \0");
} else if typ == XSLT_FUNC_VARIABLE {
emit_generic_error(b"var \0");
}
}
if !(*p).name.is_null() {
let m = format!("{} ", bytes_to_lossy((*p).name));
emit_generic_error(m.as_bytes());
} else {
emit_generic_error(b"noname !!!!\n\0");
}
emit_generic_error(b"\n\0");
j -= 1;
i += 1;
}
}
}
unsafe fn bytes_to_lossy(s: *const xmlChar) -> String {
if s.is_null() {
return String::new();
}
let len = libc::strlen(s as *const c_char) as usize;
String::from_utf8_lossy(core::slice::from_raw_parts(s, len)).into_owned()
}