libxml_rs/xslt/extensions/
mod.rs1use crate::abi::allocator::xmlFree;
18use crate::abi::structs::*;
19use crate::abi::types::*;
20use std::os::raw::c_int;
21use std::ptr;
22
23#[repr(C)]
25pub struct _xsltExtFunction {
26 pub next: *mut _xsltExtFunction,
27 pub name: *mut xmlChar,
28 pub ns: *mut xmlChar,
29 pub func: *mut c_void,
30}
31
32#[repr(C)]
34pub struct _xsltExtElement {
35 pub next: *mut _xsltExtElement,
36 pub name: *mut xmlChar,
37 pub ns: *mut xmlChar,
38 pub func: *mut c_void,
39}
40
41#[no_mangle]
49pub unsafe extern "C" fn xsltRegisterExtFunction(
50 ctxt: *mut _xsltTransformContext,
51 name: *const xmlChar,
52 NS_uri: *const xmlChar,
53 f: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
54) -> c_int {
55 if ctxt.is_null() || name.is_null() || NS_uri.is_null() {
56 return -1;
57 }
58 let entry = libc::calloc(1, core::mem::size_of::<_xsltExtFunction>()) as *mut _xsltExtFunction;
59 if entry.is_null() {
60 return -1;
61 }
62 (*entry).name = dup_str(name);
63 (*entry).ns = dup_str(NS_uri);
64 if (*entry).name.is_null() || (*entry).ns.is_null() {
65 if !(*entry).name.is_null() {
66 libc::free((*entry).name as *mut libc::c_void);
67 }
68 if !(*entry).ns.is_null() {
69 libc::free((*entry).ns as *mut libc::c_void);
70 }
71 libc::free(entry as *mut libc::c_void);
72 return -1;
73 }
74 (*entry).func = f.map(|fp| fp as *mut c_void).unwrap_or(ptr::null_mut());
75 (*entry).next = (*ctxt).extFunctions as *mut _xsltExtFunction;
78 (*ctxt).extFunctions = entry as *mut c_void;
79 0
80}
81
82#[no_mangle]
90pub unsafe extern "C" fn xsltRegisterExtElement(
91 ctxt: *mut _xsltTransformContext,
92 name: *const xmlChar,
93 NS_uri: *const xmlChar,
94 f: Option<
95 unsafe extern "C" fn(*mut c_void, *mut c_void, *mut _xmlNode, *mut c_void, *mut _xmlNode),
96 >,
97) -> c_int {
98 if ctxt.is_null() || name.is_null() || NS_uri.is_null() {
99 return -1;
100 }
101 let entry = libc::calloc(1, core::mem::size_of::<_xsltExtElement>()) as *mut _xsltExtElement;
102 if entry.is_null() {
103 return -1;
104 }
105 (*entry).name = dup_str(name);
106 (*entry).ns = dup_str(NS_uri);
107 if (*entry).name.is_null() || (*entry).ns.is_null() {
108 if !(*entry).name.is_null() {
109 libc::free((*entry).name as *mut libc::c_void);
110 }
111 if !(*entry).ns.is_null() {
112 libc::free((*entry).ns as *mut libc::c_void);
113 }
114 libc::free(entry as *mut libc::c_void);
115 return -1;
116 }
117 (*entry).func = f.map(|fp| fp as *mut c_void).unwrap_or(ptr::null_mut());
118 (*entry).next = (*ctxt).extElements as *mut _xsltExtElement;
119 (*ctxt).extElements = entry as *mut c_void;
120 0
121}
122
123pub unsafe fn xsltFindExtFunction(
130 ctxt: *mut _xsltTransformContext,
131 name: *const xmlChar,
132 ns: *const xmlChar,
133) -> *mut c_void {
134 if ctxt.is_null() || name.is_null() || ns.is_null() {
135 return ptr::null_mut();
136 }
137 let mut cur = (*ctxt).extFunctions as *mut _xsltExtFunction;
138 while !cur.is_null() {
139 if !(*cur).name.is_null()
140 && !(*cur).ns.is_null()
141 && libc::strcmp(
142 (*cur).name as *const libc::c_char,
143 name as *const libc::c_char,
144 ) == 0
145 && libc::strcmp((*cur).ns as *const libc::c_char, ns as *const libc::c_char) == 0
146 {
147 return (*cur).func;
148 }
149 cur = (*cur).next;
150 }
151 ptr::null_mut()
152}
153
154pub unsafe fn xsltFindExtElement(
161 ctxt: *mut _xsltTransformContext,
162 name: *const xmlChar,
163 ns: *const xmlChar,
164) -> *mut c_void {
165 if ctxt.is_null() || name.is_null() || ns.is_null() {
166 return ptr::null_mut();
167 }
168 let mut cur = (*ctxt).extElements as *mut _xsltExtElement;
169 while !cur.is_null() {
170 if !(*cur).name.is_null()
171 && !(*cur).ns.is_null()
172 && libc::strcmp(
173 (*cur).name as *const libc::c_char,
174 name as *const libc::c_char,
175 ) == 0
176 && libc::strcmp((*cur).ns as *const libc::c_char, ns as *const libc::c_char) == 0
177 {
178 return (*cur).func;
179 }
180 cur = (*cur).next;
181 }
182 ptr::null_mut()
183}
184
185pub unsafe fn xsltFreeExts(ctxt: *mut _xsltTransformContext) {
191 if ctxt.is_null() {
192 return;
193 }
194 let mut cur = (*ctxt).extFunctions as *mut _xsltExtFunction;
196 (*ctxt).extFunctions = ptr::null_mut();
197 while !cur.is_null() {
198 let next = (*cur).next;
199 if !(*cur).name.is_null() {
200 libc::free((*cur).name as *mut libc::c_void);
201 }
202 if !(*cur).ns.is_null() {
203 libc::free((*cur).ns as *mut libc::c_void);
204 }
205 libc::free(cur as *mut libc::c_void);
206 cur = next;
207 }
208 let mut cur = (*ctxt).extElements as *mut _xsltExtElement;
210 (*ctxt).extElements = ptr::null_mut();
211 while !cur.is_null() {
212 let next = (*cur).next;
213 if !(*cur).name.is_null() {
214 libc::free((*cur).name as *mut libc::c_void);
215 }
216 if !(*cur).ns.is_null() {
217 libc::free((*cur).ns as *mut libc::c_void);
218 }
219 libc::free(cur as *mut libc::c_void);
220 cur = next;
221 }
222}
223
224unsafe fn dup_str(s: *const xmlChar) -> *mut xmlChar {
226 let len = libc::strlen(s as *const libc::c_char);
227 let copy = libc::malloc(len + 1) as *mut xmlChar;
228 if copy.is_null() {
229 return ptr::null_mut();
230 }
231 libc::memcpy(copy as *mut libc::c_void, s as *const libc::c_void, len);
232 *copy.add(len) = 0;
233 copy
234}
235
236use std::ffi::c_void;
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241 use core::ptr;
242
243 fn make_ctxt() -> *mut _xsltTransformContext {
244 unsafe {
245 libc::calloc(1, core::mem::size_of::<_xsltTransformContext>())
246 as *mut _xsltTransformContext
247 }
248 }
249
250 #[test]
251 fn test_register_and_find_function() {
252 unsafe {
253 let ctxt = make_ctxt();
254 extern "C" fn dummy(_ctx: *mut c_void, _n: c_int) {}
255 assert_eq!(
256 xsltRegisterExtFunction(
257 ctxt,
258 b"myfunc\0".as_ptr() as *const xmlChar,
259 b"http://example.com/ext\0".as_ptr() as *const xmlChar,
260 Some(dummy),
261 ),
262 0
263 );
264 let found = xsltFindExtFunction(
265 ctxt,
266 b"myfunc\0".as_ptr() as *const xmlChar,
267 b"http://example.com/ext\0".as_ptr() as *const xmlChar,
268 );
269 assert_eq!(found, dummy as *mut c_void);
270 let not_found = xsltFindExtFunction(
271 ctxt,
272 b"other\0".as_ptr() as *const xmlChar,
273 b"http://example.com/ext\0".as_ptr() as *const xmlChar,
274 );
275 assert!(not_found.is_null());
276 xsltFreeExts(ctxt);
277 libc::free(ctxt as *mut libc::c_void);
278 }
279 }
280
281 #[test]
282 fn test_register_null() {
283 unsafe {
284 assert_eq!(
285 xsltRegisterExtFunction(ptr::null_mut(), ptr::null(), ptr::null(), None),
286 -1
287 );
288 assert_eq!(
289 xsltRegisterExtElement(ptr::null_mut(), ptr::null(), ptr::null(), None),
290 -1
291 );
292 }
293 }
294}