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).docCache as *mut _xsltDocCacheEntry;
58 (*ctxt).docCache = entry as *mut c_void;
59}
60
61pub unsafe extern "C" fn xsltDefaultLoader(
68 _ctxt: *mut c_void,
69 _style: *const c_char,
70 URI: *const c_char,
71 _ns: *const c_char,
72 _secondary: c_int,
73) -> *mut _xmlParserInput {
74 if URI.is_null() {
75 return ptr::null_mut();
76 }
77 ptr::null_mut()
79}
80
81static mut XSLT_LOADER: Option<
83 unsafe extern "C" fn(
84 *mut c_void,
85 *const c_char,
86 *const c_char,
87 *const c_char,
88 c_int,
89 ) -> *mut _xmlParserInput,
90> = None;
91
92#[no_mangle]
98pub unsafe extern "C" fn xsltSetLoaderFunc(
99 loader: Option<
100 unsafe extern "C" fn(
101 *mut c_void,
102 *const c_char,
103 *const c_char,
104 *const c_char,
105 c_int,
106 ) -> *mut _xmlParserInput,
107 >,
108) {
109 XSLT_LOADER = loader;
110}
111
112pub fn xsltGetLoaderFunc() -> Option<
114 unsafe extern "C" fn(
115 *mut c_void,
116 *const c_char,
117 *const c_char,
118 *const c_char,
119 c_int,
120 ) -> *mut _xmlParserInput,
121> {
122 unsafe { XSLT_LOADER }
124}
125
126pub unsafe fn xsltLoadDocument(
135 ctxt: *mut _xsltTransformContext,
136 URI: *const xmlChar,
137) -> *mut _xmlDoc {
138 if ctxt.is_null() || URI.is_null() {
139 return ptr::null_mut();
140 }
141 if let Some(cached) = cache_lookup(ctxt, URI) {
143 return cached;
144 }
145 let base = if !(*ctxt).document.is_null() && !(*(*ctxt).document).URL.is_null() {
147 let len = libc::strlen((*(*ctxt).document).URL as *const libc::c_char) as usize;
148 Some(core::slice::from_raw_parts((*(*ctxt).document).URL, len))
149 } else {
150 None
151 };
152 let uri_bytes =
153 core::slice::from_raw_parts(URI, libc::strlen(URI as *const libc::c_char) as usize);
154 let resolved: Option<Vec<u8>> = match base {
155 Some(b) => crate::xml::uri::resolve_uri(b, uri_bytes),
156 None => Some(uri_bytes.to_vec()),
157 };
158 let resolved = match resolved {
159 Some(r) if !r.is_empty() => r,
160 _ => return ptr::null_mut(),
161 };
162 let mut cstr = resolved.clone();
164 cstr.push(0);
165 let doc = load_via_loader(ctxt, cstr.as_ptr() as *mut xmlChar);
166 if !doc.is_null() {
167 cache_store(ctxt, URI, doc);
168 }
169 doc
170}
171
172unsafe fn load_via_loader(ctxt: *mut _xsltTransformContext, uri: *mut xmlChar) -> *mut _xmlDoc {
181 let loader = xsltGetLoaderFunc();
183 if let Some(loader_fn) = loader {
184 let input = loader_fn(
185 ctxt as *mut c_void,
186 ptr::null(), uri as *const c_char,
188 ptr::null(), 0, );
191 if !input.is_null() {
192 crate::xml::parser::helpers::free_parser_input(input);
195 }
196 }
197 crate::abi::exports_xml2::xmlReadFile(uri as *const c_char, ptr::null(), 0)
199}
200
201unsafe fn cache_lookup(
207 ctxt: *mut _xsltTransformContext,
208 uri: *const xmlChar,
209) -> Option<*mut _xmlDoc> {
210 let mut cur = (*ctxt).docCache as *mut _xsltDocCacheEntry;
211 while !cur.is_null() {
212 if !(*cur).uri.is_null()
213 && libc::strcmp(
214 (*cur).uri as *const libc::c_char,
215 uri as *const libc::c_char,
216 ) == 0
217 {
218 return Some((*cur).doc);
219 }
220 cur = (*cur).next;
221 }
222 None
223}
224
225unsafe fn cache_store(ctxt: *mut _xsltTransformContext, uri: *const xmlChar, doc: *mut _xmlDoc) {
231 let entry =
232 libc::calloc(1, core::mem::size_of::<_xsltDocCacheEntry>()) as *mut _xsltDocCacheEntry;
233 if entry.is_null() {
234 return;
235 }
236 let len = libc::strlen(uri as *const libc::c_char);
237 let copy = libc::malloc(len + 1) as *mut xmlChar;
238 if copy.is_null() {
239 libc::free(entry as *mut libc::c_void);
240 return;
241 }
242 libc::memcpy(copy as *mut libc::c_void, uri as *const libc::c_void, len);
243 *copy.add(len) = 0;
244 (*entry).uri = copy;
245 (*entry).doc = doc;
246 (*entry).next = (*ctxt).docCache as *mut _xsltDocCacheEntry;
247 (*ctxt).docCache = entry as *mut c_void;
248}
249
250pub unsafe fn xsltFreeDocCache(ctxt: *mut _xsltTransformContext) {
256 if ctxt.is_null() {
257 return;
258 }
259 let mut cur = (*ctxt).docCache as *mut _xsltDocCacheEntry;
260 (*ctxt).docCache = ptr::null_mut();
261 while !cur.is_null() {
262 let next = (*cur).next;
263 if !(*cur).uri.is_null() {
264 libc::free((*cur).uri as *mut libc::c_void);
265 }
266 if !(*cur).doc.is_null() {
267 crate::xml::tree::free_doc((*cur).doc);
268 }
269 libc::free(cur as *mut libc::c_void);
270 cur = next;
271 }
272}
273
274use std::ffi::c_void;
275use std::os::raw::c_char;
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280 use core::ptr;
281
282 #[test]
283 fn test_null_args() {
284 unsafe {
285 assert!(xsltLoadDocument(ptr::null_mut(), ptr::null()).is_null());
286 xsltFreeDocCache(ptr::null_mut());
287 }
288 }
289}