libxml_rs/xslt/documents/
mod.rs1use crate::abi::structs::*;
17use crate::abi::types::*;
18use std::os::raw::c_int;
19use std::ptr;
20
21#[repr(C)]
23pub struct _xsltDocCacheEntry {
24 pub next: *mut _xsltDocCacheEntry,
25 pub uri: *mut xmlChar,
26 pub doc: *mut _xmlDoc,
27}
28
29pub(crate) unsafe fn xsltRegisterRVT(ctxt: *mut _xsltTransformContext, doc: *mut _xmlDoc) {
47 if ctxt.is_null() || doc.is_null() {
48 return;
49 }
50 let entry =
51 libc::calloc(1, core::mem::size_of::<_xsltDocCacheEntry>()) as *mut _xsltDocCacheEntry;
52 if entry.is_null() {
53 return;
54 }
55 (*entry).uri = ptr::null_mut();
56 (*entry).doc = doc;
57 (*entry).next = (*ctxt).cache as *mut _xsltDocCacheEntry;
61 (*ctxt).cache = entry as *mut c_void;
62}
63
64pub unsafe extern "C" fn xsltDefaultLoader(
71 _ctxt: *mut c_void,
72 _style: *const c_char,
73 URI: *const c_char,
74 _ns: *const c_char,
75 _secondary: c_int,
76) -> *mut _xmlParserInput {
77 if URI.is_null() {
78 return ptr::null_mut();
79 }
80 ptr::null_mut()
82}
83
84static mut XSLT_LOADER: Option<
86 unsafe extern "C" fn(
87 *mut c_void,
88 *const c_char,
89 *const c_char,
90 *const c_char,
91 c_int,
92 ) -> *mut _xmlParserInput,
93> = None;
94
95#[no_mangle]
101pub unsafe extern "C" fn xsltSetLoaderFunc(
102 loader: Option<
103 unsafe extern "C" fn(
104 *mut c_void,
105 *const c_char,
106 *const c_char,
107 *const c_char,
108 c_int,
109 ) -> *mut _xmlParserInput,
110 >,
111) {
112 XSLT_LOADER = loader;
113}
114
115pub fn xsltGetLoaderFunc() -> Option<
117 unsafe extern "C" fn(
118 *mut c_void,
119 *const c_char,
120 *const c_char,
121 *const c_char,
122 c_int,
123 ) -> *mut _xmlParserInput,
124> {
125 unsafe { XSLT_LOADER }
127}
128
129pub unsafe fn xsltLoadDocument(
138 ctxt: *mut _xsltTransformContext,
139 URI: *const xmlChar,
140) -> *mut _xmlDoc {
141 if ctxt.is_null() || URI.is_null() {
142 return ptr::null_mut();
143 }
144 if let Some(cached) = cache_lookup(ctxt, URI) {
146 return cached;
147 }
148 let base = if !(*ctxt).document.is_null()
150 && !(*(*ctxt).document).doc.is_null()
151 && !(*(*(*ctxt).document).doc).URL.is_null()
152 {
153 let len = libc::strlen((*(*(*ctxt).document).doc).URL as *const libc::c_char) as usize;
154 Some(core::slice::from_raw_parts(
155 (*(*(*ctxt).document).doc).URL,
156 len,
157 ))
158 } else {
159 None
160 };
161 let uri_bytes =
162 core::slice::from_raw_parts(URI, libc::strlen(URI as *const libc::c_char) as usize);
163 let resolved: Option<Vec<u8>> = match base {
164 Some(b) => crate::xml::uri::resolve_uri(b, uri_bytes),
165 None => Some(uri_bytes.to_vec()),
166 };
167 let resolved = match resolved {
168 Some(r) if !r.is_empty() => r,
169 _ => return ptr::null_mut(),
170 };
171 let mut cstr = resolved.clone();
173 cstr.push(0);
174 let doc = load_via_loader(ctxt, cstr.as_ptr() as *mut xmlChar);
175 if !doc.is_null() {
176 cache_store(ctxt, URI, doc);
177 }
178 doc
179}
180
181unsafe fn load_via_loader(ctxt: *mut _xsltTransformContext, uri: *mut xmlChar) -> *mut _xmlDoc {
190 let loader = xsltGetLoaderFunc();
192 if let Some(loader_fn) = loader {
193 let input = loader_fn(
194 ctxt as *mut c_void,
195 ptr::null(), uri as *const c_char,
197 ptr::null(), 0, );
200 if !input.is_null() {
201 crate::xml::parser::helpers::free_parser_input(input);
204 }
205 }
206 crate::abi::exports_xml2::xmlReadFile(uri as *const c_char, ptr::null(), 0)
208}
209
210unsafe fn cache_lookup(
216 ctxt: *mut _xsltTransformContext,
217 uri: *const xmlChar,
218) -> Option<*mut _xmlDoc> {
219 let mut cur = (*ctxt).cache as *mut _xsltDocCacheEntry;
220 while !cur.is_null() {
221 if !(*cur).uri.is_null()
222 && libc::strcmp(
223 (*cur).uri as *const libc::c_char,
224 uri as *const libc::c_char,
225 ) == 0
226 {
227 return Some((*cur).doc);
228 }
229 cur = (*cur).next;
230 }
231 None
232}
233
234unsafe fn cache_store(ctxt: *mut _xsltTransformContext, uri: *const xmlChar, doc: *mut _xmlDoc) {
240 let entry =
241 libc::calloc(1, core::mem::size_of::<_xsltDocCacheEntry>()) as *mut _xsltDocCacheEntry;
242 if entry.is_null() {
243 return;
244 }
245 let len = libc::strlen(uri as *const libc::c_char);
246 let copy = libc::malloc(len + 1) as *mut xmlChar;
247 if copy.is_null() {
248 libc::free(entry as *mut libc::c_void);
249 return;
250 }
251 libc::memcpy(copy as *mut libc::c_void, uri as *const libc::c_void, len);
252 *copy.add(len) = 0;
253 (*entry).uri = copy;
254 (*entry).doc = doc;
255 (*entry).next = (*ctxt).cache as *mut _xsltDocCacheEntry;
256 (*ctxt).cache = entry as *mut c_void;
257}
258
259pub unsafe fn xsltFreeDocCache(ctxt: *mut _xsltTransformContext) {
265 if ctxt.is_null() {
266 return;
267 }
268 let mut cur = (*ctxt).cache as *mut _xsltDocCacheEntry;
269 (*ctxt).cache = ptr::null_mut();
270 while !cur.is_null() {
271 let next = (*cur).next;
272 if !(*cur).uri.is_null() {
273 libc::free((*cur).uri as *mut libc::c_void);
274 }
275 if !(*cur).doc.is_null() {
276 crate::xml::tree::free_doc((*cur).doc);
277 }
278 libc::free(cur as *mut libc::c_void);
279 cur = next;
280 }
281}
282
283use std::ffi::c_void;
284use std::os::raw::c_char;
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289 use core::ptr;
290
291 #[test]
292 fn test_null_args() {
293 unsafe {
294 assert!(xsltLoadDocument(ptr::null_mut(), ptr::null()).is_null());
295 xsltFreeDocCache(ptr::null_mut());
296 }
297 }
298}