1#![allow(non_snake_case)]
18#![allow(unused_variables)]
19#![allow(clippy::missing_safety_doc)]
20#![allow(clippy::not_unsafe_ptr_arg_deref)]
21
22use core::ptr;
23use std::collections::HashMap;
24use std::ffi::CStr;
25use std::os::raw::{c_char, c_int, c_void};
26
27use parking_lot::RwLock;
28
29use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl};
30use crate::abi::structs::*;
31use crate::abi::types::*;
32
33pub type xsltExtInitFunction =
37 unsafe extern "C" fn(ctxt: *mut _xsltTransformContext, URI: *const xmlChar) -> *mut c_void;
38pub type xsltExtShutdownFunction =
40 unsafe extern "C" fn(ctxt: *mut _xsltTransformContext, URI: *const xmlChar, data: *mut c_void);
41pub type xsltStyleExtInitFunction =
43 unsafe extern "C" fn(style: *mut _xsltStylesheet, URI: *const xmlChar) -> *mut c_void;
44pub type xsltStyleExtShutdownFunction =
46 unsafe extern "C" fn(style: *mut _xsltStylesheet, URI: *const xmlChar, data: *mut c_void);
47pub type xsltTopLevelFunction =
49 unsafe extern "C" fn(style: *mut _xsltStylesheet, node: *mut _xmlNode, data: *mut c_void);
50
51#[derive(Clone, Copy)]
52struct ExtModule {
53 init_func: Option<xsltExtInitFunction>,
54 shutdown_func: Option<xsltExtShutdownFunction>,
55 style_init_func: Option<xsltStyleExtInitFunction>,
56 #[allow(dead_code)]
57 style_shutdown_func: Option<xsltStyleExtShutdownFunction>,
58}
59
60#[derive(Clone, Copy)]
65struct ExtElement {
66 precomp: usize, transform: usize, }
69
70fn ext_key(name: *const xmlChar, uri: *const xmlChar) -> Option<Vec<u8>> {
72 if name.is_null() || uri.is_null() {
73 return None;
74 }
75 let n = unsafe { CStr::from_ptr(name as *const c_char).to_bytes() };
76 let u = unsafe { CStr::from_ptr(uri as *const c_char).to_bytes() };
77 let mut k = Vec::with_capacity(n.len() + 1 + u.len());
78 k.extend_from_slice(n);
79 k.push(0);
80 k.extend_from_slice(u);
81 Some(k)
82}
83
84static EXT_MODULES: once_cell::sync::Lazy<RwLock<HashMap<Vec<u8>, ExtModule>>> =
86 once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
87static EXT_ELEMENTS: once_cell::sync::Lazy<RwLock<HashMap<Vec<u8>, ExtElement>>> =
90 once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
91static EXT_FUNCTIONS: once_cell::sync::Lazy<RwLock<HashMap<Vec<u8>, usize>>> =
93 once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
94static EXT_TOPLEVELS: once_cell::sync::Lazy<RwLock<HashMap<Vec<u8>, usize>>> =
96 once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
97
98#[no_mangle]
110pub unsafe extern "C" fn xsltRegisterExtModule(
111 URI: *const xmlChar,
112 initFunc: Option<xsltExtInitFunction>,
113 shutdownFunc: Option<xsltExtShutdownFunction>,
114) -> c_int {
115 if URI.is_null() || initFunc.is_none() {
117 return -1;
118 }
119 let key = unsafe { CStr::from_ptr(URI as *const c_char).to_bytes().to_vec() };
120 EXT_MODULES.write().insert(
121 key,
122 ExtModule {
123 init_func: initFunc,
124 shutdown_func: shutdownFunc,
125 style_init_func: None,
126 style_shutdown_func: None,
127 },
128 );
129 0
130}
131
132#[no_mangle]
145pub unsafe extern "C" fn xsltRegisterExtModuleFull(
146 URI: *const xmlChar,
147 initFunc: Option<xsltExtInitFunction>,
148 shutdownFunc: Option<xsltExtShutdownFunction>,
149 styleInitFunc: Option<xsltStyleExtInitFunction>,
150 styleShutdownFunc: Option<xsltStyleExtShutdownFunction>,
151) -> c_int {
152 if URI.is_null() || initFunc.is_none() {
153 return -1;
154 }
155 let key = unsafe { CStr::from_ptr(URI as *const c_char).to_bytes().to_vec() };
156 EXT_MODULES.write().insert(
157 key,
158 ExtModule {
159 init_func: initFunc,
160 shutdown_func: shutdownFunc,
161 style_init_func: styleInitFunc,
162 style_shutdown_func: styleShutdownFunc,
163 },
164 );
165 0
166}
167
168#[no_mangle]
179pub unsafe extern "C" fn xsltRegisterExtModuleElement(
180 name: *const xmlChar,
181 URI: *const xmlChar,
182 precomp: *mut c_void,
183 transform: *mut c_void,
184) -> c_int {
185 let Some(key) = ext_key(name, URI) else {
186 return -1;
187 };
188 EXT_ELEMENTS.write().insert(
189 key,
190 ExtElement {
191 precomp: precomp as usize,
192 transform: transform as usize,
193 },
194 );
195 0
196}
197
198#[no_mangle]
208pub unsafe extern "C" fn xsltRegisterExtModuleFunction(
209 name: *const xmlChar,
210 URI: *const xmlChar,
211 function: *mut c_void,
212) -> c_int {
213 let Some(key) = ext_key(name, URI) else {
214 return -1;
215 };
216 EXT_FUNCTIONS.write().insert(key, function as usize);
217 0
218}
219
220#[no_mangle]
230pub unsafe extern "C" fn xsltRegisterExtModuleTopLevel(
231 name: *const xmlChar,
232 URI: *const xmlChar,
233 function: *mut c_void,
234) -> c_int {
235 let Some(key) = ext_key(name, URI) else {
236 return -1;
237 };
238 EXT_TOPLEVELS.write().insert(key, function as usize);
239 0
240}
241
242#[no_mangle]
251pub unsafe extern "C" fn xsltUnregisterExtModule(URI: *const xmlChar) -> c_int {
252 if URI.is_null() {
253 return -1;
254 }
255 let uri_bytes = unsafe { CStr::from_ptr(URI as *const c_char).to_bytes().to_vec() };
256 let mut mods = EXT_MODULES.write();
257 if mods.remove(&uri_bytes).is_none() {
258 return -1;
259 }
260 drop(mods);
261 let mut elems = EXT_ELEMENTS.write();
263 let mut funcs = EXT_FUNCTIONS.write();
264 let mut tops = EXT_TOPLEVELS.write();
265 let suffix: Vec<u8> = {
266 let mut s = vec![0];
267 s.extend_from_slice(&uri_bytes);
268 s
269 };
270 elems.retain(|k, _| !k.ends_with(&suffix));
271 funcs.retain(|k, _| !k.ends_with(&suffix));
272 tops.retain(|k, _| !k.ends_with(&suffix));
273 0
274}
275
276#[no_mangle]
284pub unsafe extern "C" fn xsltUnregisterExtModuleElement(
285 name: *const xmlChar,
286 URI: *const xmlChar,
287) -> c_int {
288 let Some(key) = ext_key(name, URI) else {
289 return -1;
290 };
291 if EXT_ELEMENTS.write().remove(&key).is_some() {
292 0
293 } else {
294 -1
295 }
296}
297
298#[no_mangle]
306pub unsafe extern "C" fn xsltUnregisterExtModuleFunction(
307 name: *const xmlChar,
308 URI: *const xmlChar,
309) -> c_int {
310 let Some(key) = ext_key(name, URI) else {
311 return -1;
312 };
313 if EXT_FUNCTIONS.write().remove(&key).is_some() {
314 0
315 } else {
316 -1
317 }
318}
319
320#[no_mangle]
328pub unsafe extern "C" fn xsltUnregisterExtModuleTopLevel(
329 name: *const xmlChar,
330 URI: *const xmlChar,
331) -> c_int {
332 let Some(key) = ext_key(name, URI) else {
333 return -1;
334 };
335 if EXT_TOPLEVELS.write().remove(&key).is_some() {
336 0
337 } else {
338 -1
339 }
340}
341
342#[no_mangle]
352pub unsafe extern "C" fn xsltRegisterExtPrefix(
353 style: *mut _xsltStylesheet,
354 prefix: *const xmlChar,
355 URI: *const xmlChar,
356) -> c_int {
357 if style.is_null() || prefix.is_null() || URI.is_null() {
358 return -1;
359 }
360 let mut cur = (*style).extInfos as *mut ExtPrefixEntry;
363 while !cur.is_null() {
364 if !(*cur).prefix.is_null()
365 && libc::strcmp((*cur).prefix as *const c_char, prefix as *const c_char) == 0
366 {
367 let new_uri =
369 crate::abi::allocator::xmlMemStrdupImpl(URI as *const c_char) as *mut c_char;
370 if new_uri.is_null() {
371 return -1;
372 }
373 xmlFreeImpl((*cur).uri as *mut c_void);
374 (*cur).uri = new_uri;
375 return 0;
376 }
377 cur = (*cur).next;
378 }
379 let entry = xmlMallocImpl(size_of::<ExtPrefixEntry>()) as *mut ExtPrefixEntry;
380 if entry.is_null() {
381 return -1;
382 }
383 let p = crate::abi::allocator::xmlMemStrdupImpl(prefix as *const c_char) as *mut c_char;
384 let u = crate::abi::allocator::xmlMemStrdupImpl(URI as *const c_char) as *mut c_char;
385 if p.is_null() || u.is_null() {
386 if !p.is_null() {
387 xmlFreeImpl(p as *mut c_void);
388 }
389 if !u.is_null() {
390 xmlFreeImpl(u as *mut c_void);
391 }
392 xmlFreeImpl(entry as *mut c_void);
393 return -1;
394 }
395 ptr::write(
396 entry,
397 ExtPrefixEntry {
398 next: (*style).extInfos as *mut ExtPrefixEntry,
399 prefix: p,
400 uri: u,
401 },
402 );
403 (*style).extInfos = entry as *mut c_void;
404 0
405}
406
407#[no_mangle]
417pub unsafe extern "C" fn xsltCheckExtPrefix(
418 style: *mut _xsltStylesheet,
419 prefix: *const xmlChar,
420) -> c_int {
421 if style.is_null() || prefix.is_null() {
422 return 0;
423 }
424 let mut cur = (*style).extInfos as *mut ExtPrefixEntry;
425 while !cur.is_null() {
426 if !(*cur).prefix.is_null()
427 && libc::strcmp((*cur).prefix as *const c_char, prefix as *const c_char) == 0
428 {
429 return 1;
430 }
431 cur = (*cur).next;
432 }
433 0
434}
435
436#[no_mangle]
445pub unsafe extern "C" fn xsltCheckExtURI(
446 style: *mut _xsltStylesheet,
447 URI: *const xmlChar,
448) -> c_int {
449 if style.is_null() || URI.is_null() {
450 return 0;
451 }
452 let mut cur = (*style).extInfos as *mut ExtPrefixEntry;
453 while !cur.is_null() {
454 if !(*cur).uri.is_null()
455 && libc::strcmp((*cur).uri as *const c_char, URI as *const c_char) == 0
456 {
457 return 1;
458 }
459 cur = (*cur).next;
460 }
461 0
462}
463
464#[no_mangle]
476pub unsafe extern "C" fn xsltExtElementLookup(
477 ctxt: *mut _xsltTransformContext,
478 name: *const xmlChar,
479 URI: *const xmlChar,
480) -> *mut c_void {
481 if ctxt.is_null() || name.is_null() || URI.is_null() {
482 return ptr::null_mut();
483 }
484 let found = crate::xslt::extensions::xsltFindExtElement(ctxt, name, URI);
486 if !found.is_null() {
487 return found;
488 }
489 let Some(key) = ext_key(name, URI) else {
490 return ptr::null_mut();
491 };
492 EXT_ELEMENTS
493 .read()
494 .get(&key)
495 .map(|e| e.transform as *mut c_void)
496 .unwrap_or(ptr::null_mut())
497}
498
499#[no_mangle]
508pub unsafe extern "C" fn xsltExtModuleElementLookup(
509 name: *const xmlChar,
510 URI: *const xmlChar,
511) -> *mut c_void {
512 let Some(key) = ext_key(name, URI) else {
513 return ptr::null_mut();
514 };
515 EXT_ELEMENTS
516 .read()
517 .get(&key)
518 .map(|e| e.transform as *mut c_void)
519 .unwrap_or(ptr::null_mut())
520}
521
522#[no_mangle]
531pub unsafe extern "C" fn xsltExtModuleFunctionLookup(
532 name: *const xmlChar,
533 URI: *const xmlChar,
534) -> *mut c_void {
535 let Some(key) = ext_key(name, URI) else {
536 return ptr::null_mut();
537 };
538 EXT_FUNCTIONS
539 .read()
540 .get(&key)
541 .copied()
542 .map(|p| p as *mut c_void)
543 .unwrap_or(ptr::null_mut())
544}
545
546#[no_mangle]
555pub unsafe extern "C" fn xsltExtModuleElementPreComputeLookup(
556 name: *const xmlChar,
557 URI: *const xmlChar,
558) -> *mut c_void {
559 let Some(key) = ext_key(name, URI) else {
560 return ptr::null_mut();
561 };
562 EXT_ELEMENTS
563 .read()
564 .get(&key)
565 .map(|e| e.precomp as *mut c_void)
566 .unwrap_or(ptr::null_mut())
567}
568
569#[no_mangle]
578pub unsafe extern "C" fn xsltExtModuleTopLevelLookup(
579 name: *const xmlChar,
580 URI: *const xmlChar,
581) -> *mut c_void {
582 let Some(key) = ext_key(name, URI) else {
583 return ptr::null_mut();
584 };
585 EXT_TOPLEVELS
586 .read()
587 .get(&key)
588 .copied()
589 .map(|p| p as *mut c_void)
590 .unwrap_or(ptr::null_mut())
591}
592
593#[no_mangle]
604pub unsafe extern "C" fn xsltInitCtxtExts(ctxt: *mut _xsltTransformContext) -> c_int {
605 if ctxt.is_null() || (*ctxt).style.is_null() {
606 return 0;
607 }
608 let style = (*ctxt).style;
609 let mut cur = (*style).extInfos as *mut ExtPrefixEntry;
610 while !cur.is_null() {
611 if !(*cur).uri.is_null() {
612 let key = CStr::from_ptr((*cur).uri as *const c_char)
613 .to_bytes()
614 .to_vec();
615 if let Some(module) = EXT_MODULES.read().get(&key).copied() {
616 if let Some(init) = module.init_func {
617 let data = init(ctxt, (*cur).uri as *const xmlChar);
618 if data.is_null() {
619 return -1;
620 }
621 let entry = xmlMallocImpl(size_of::<ExtDataEntry>()) as *mut ExtDataEntry;
623 if entry.is_null() {
624 return -1;
625 }
626 let u = crate::abi::allocator::xmlMemStrdupImpl((*cur).uri as *const c_char)
627 as *mut c_char;
628 if u.is_null() {
629 xmlFreeImpl(entry as *mut c_void);
630 return -1;
631 }
632 ptr::write(
633 entry,
634 ExtDataEntry {
635 next: (*ctxt).extInfos as *mut ExtDataEntry,
636 uri: u,
637 data,
638 },
639 );
640 (*ctxt).extInfos = entry as *mut c_void;
641 }
642 }
643 }
644 cur = (*cur).next;
645 }
646 0
647}
648
649#[no_mangle]
658pub unsafe extern "C" fn xsltShutdownCtxtExts(ctxt: *mut _xsltTransformContext) {
659 if ctxt.is_null() {
660 return;
661 }
662 let mut cur = (*ctxt).extInfos as *mut ExtDataEntry;
663 while !cur.is_null() {
664 if !(*cur).uri.is_null() {
665 let key = CStr::from_ptr((*cur).uri as *const c_char)
666 .to_bytes()
667 .to_vec();
668 if let Some(module) = EXT_MODULES.read().get(&key).copied() {
669 if let Some(shutdown) = module.shutdown_func {
670 shutdown(ctxt, (*cur).uri as *const xmlChar, (*cur).data);
671 }
672 }
673 }
674 cur = (*cur).next;
675 }
676}
677
678#[no_mangle]
686pub unsafe extern "C" fn xsltFreeCtxtExts(ctxt: *mut _xsltTransformContext) {
687 if ctxt.is_null() {
688 return;
689 }
690 let mut cur = (*ctxt).extInfos as *mut ExtDataEntry;
691 (*ctxt).extInfos = ptr::null_mut();
692 while !cur.is_null() {
693 let next = (*cur).next;
694 if !(*cur).uri.is_null() {
695 xmlFreeImpl((*cur).uri as *mut c_void);
696 }
697 xmlFreeImpl(cur as *mut c_void);
698 cur = next;
699 }
700}
701
702#[no_mangle]
710pub unsafe extern "C" fn xsltGetExtData(
711 ctxt: *mut _xsltTransformContext,
712 URI: *const xmlChar,
713) -> *mut c_void {
714 if ctxt.is_null() || URI.is_null() {
715 return ptr::null_mut();
716 }
717 let mut cur = (*ctxt).extInfos as *mut ExtDataEntry;
718 while !cur.is_null() {
719 if !(*cur).uri.is_null()
720 && libc::strcmp((*cur).uri as *const c_char, URI as *const c_char) == 0
721 {
722 return (*cur).data;
723 }
724 cur = (*cur).next;
725 }
726 ptr::null_mut()
727}
728
729#[no_mangle]
738pub unsafe extern "C" fn xsltStyleGetExtData(
739 style: *mut _xsltStylesheet,
740 URI: *const xmlChar,
741) -> *mut c_void {
742 if style.is_null() || URI.is_null() {
743 return ptr::null_mut();
744 }
745 let mut cur = (*style).extInfos as *mut ExtDataEntry;
746 while !cur.is_null() {
747 if !(*cur).uri.is_null()
748 && libc::strcmp((*cur).uri as *const c_char, URI as *const c_char) == 0
749 {
750 return (*cur).data;
751 }
752 cur = (*cur).next;
753 }
754 let key = CStr::from_ptr(URI as *const c_char).to_bytes().to_vec();
755 let module = EXT_MODULES.read().get(&key).copied();
756 let data = match module {
757 Some(m) => match m.style_init_func {
758 Some(init) => init(style, URI),
759 None => ptr::null_mut(),
760 },
761 None => ptr::null_mut(),
762 };
763 let entry = xmlMallocImpl(size_of::<ExtDataEntry>()) as *mut ExtDataEntry;
764 if entry.is_null() {
765 return ptr::null_mut();
766 }
767 let u = crate::abi::allocator::xmlMemStrdupImpl(URI as *const c_char) as *mut c_char;
768 if u.is_null() {
769 xmlFreeImpl(entry as *mut c_void);
770 return ptr::null_mut();
771 }
772 ptr::write(
773 entry,
774 ExtDataEntry {
775 next: (*style).extInfos as *mut ExtDataEntry,
776 uri: u,
777 data,
778 },
779 );
780 (*style).extInfos = entry as *mut c_void;
781 data
782}
783
784#[no_mangle]
796pub unsafe extern "C" fn xsltStyleStylesheetLevelGetExtData(
797 style: *mut _xsltStylesheet,
798 URI: *const xmlChar,
799) -> *mut c_void {
800 unsafe { xsltStyleGetExtData(style, URI) }
801}
802
803#[no_mangle]
812pub unsafe extern "C" fn xsltGetExtInfo(
813 style: *mut _xsltStylesheet,
814 _URI: *const xmlChar,
815) -> *mut c_void {
816 if style.is_null() {
817 return ptr::null_mut();
818 }
819 (*style).extInfos
820}
821
822#[no_mangle]
831pub unsafe extern "C" fn xsltRegisterAllExtras() {
832 xsltRegisterExtModule(
836 c"http://exslt.org/common".as_ptr() as *const xmlChar,
837 None,
838 None,
839 );
840}
841
842#[no_mangle]
851pub unsafe extern "C" fn xsltRegisterExtras(ctxt: *mut _xsltTransformContext) {
852 if ctxt.is_null() || (*ctxt).xpathCtxt.is_null() {
853 return;
854 }
855 crate::abi::exports_xslt_functions::xsltRegisterAllFunctions((*ctxt).xpathCtxt);
856}
857
858#[no_mangle]
867pub const unsafe extern "C" fn xsltRegisterAllElement(ctxt: *mut _xsltTransformContext) {
868 if ctxt.is_null() {}
869 }
873
874#[no_mangle]
883pub unsafe extern "C" fn xsltRegisterTestModule() {
884 xsltRegisterExtModule(
885 c"http://xmlsoft.org/XSLT/".as_ptr() as *const xmlChar,
886 None,
887 None,
888 );
889}
890
891#[derive(Debug)]
896#[repr(C)]
897pub struct ExtPrefixEntry {
898 pub next: *mut ExtPrefixEntry,
900 pub prefix: *mut c_char,
902 pub uri: *mut c_char,
904}
905
906#[derive(Debug)]
908#[repr(C)]
909pub struct ExtDataEntry {
910 pub next: *mut ExtDataEntry,
912 pub uri: *mut c_char,
914 pub data: *mut c_void,
916}