1use std::{borrow::Cow, mem::take, os::raw::c_void, ptr::null_mut};
28
29use crate::{
30 chvalid::XmlCharValid,
31 encoding::{XmlCharEncoding, get_encoding_handler},
32 error::{__xml_raise_error, XmlErrorDomain, XmlErrorLevel, XmlParserErrors},
33 io::xml_parser_get_directory,
34 parser::{
35 XML_DETECT_IDS, XmlParserCtxt, XmlParserOption, xml_init_parser, xml_load_external_entity,
36 },
37 tree::{
38 NodeCommon, XML_XML_NAMESPACE, XmlDocPtr, XmlElementType, XmlEntityPtr, XmlEntityType,
39 XmlGenericNodePtr, XmlNodePtr, xml_add_doc_entity, xml_create_int_subset,
40 xml_doc_copy_node, xml_free_doc, xml_free_node, xml_free_node_list, xml_get_doc_entity,
41 xml_new_doc_node, xml_new_doc_text, xml_static_copy_node, xml_static_copy_node_list,
42 },
43 uri::{XmlURI, build_relative_uri, build_uri, escape_url},
44 xpath::{XmlXPathObject, XmlXPathObjectType},
45 xpointer::{xml_xptr_eval, xml_xptr_new_context},
46};
47
48pub const XINCLUDE_NS: &str = "http://www.w3.org/2003/XInclude";
50pub const XINCLUDE_OLD_NS: &str = "http://www.w3.org/2001/XInclude";
52pub const XINCLUDE_NODE: &str = "include";
54pub const XINCLUDE_FALLBACK: &str = "fallback";
56pub const XINCLUDE_HREF: &str = "href";
58pub const XINCLUDE_PARSE: &str = "parse";
60pub const XINCLUDE_PARSE_XML: &str = "xml";
62pub const XINCLUDE_PARSE_TEXT: &str = "text";
64pub const XINCLUDE_PARSE_ENCODING: &str = "encoding";
66pub const XINCLUDE_PARSE_XPOINTER: &str = "xpointer";
68
69#[doc(alias = "xmlXIncludeErr")]
71macro_rules! xml_xinclude_err {
72 ($ctxt:expr, $node:expr, $error:expr, $msg:expr) => {
73 xml_xinclude_err!(@inner, $ctxt, $node, $error, $msg, None);
74 };
75 ($ctxt:expr, $node:expr, $error:expr, $msg:expr, $extra:expr) => {
76 let msg = format!($msg, $extra);
77 xml_xinclude_err!(@inner, $ctxt, $node, $error, &msg, Some($extra.to_owned().into()));
78 };
79 (@inner, $ctxt:expr, $node:expr, $error:expr, $msg:expr, $extra:expr) => {
80 let ctxt = $ctxt as *mut XmlXIncludeCtxt;
81 if !ctxt.is_null() {
82 (*ctxt).nb_errors += 1;
83 }
84 __xml_raise_error!(
85 None,
86 None,
87 None,
88 ctxt as _,
89 $node,
90 XmlErrorDomain::XmlFromXInclude,
91 $error,
92 XmlErrorLevel::XmlErrError,
93 None,
94 0,
95 $extra,
96 None,
97 None,
98 0,
99 0,
100 Some($msg),
101 );
102 };
103}
104
105#[doc(alias = "xmlXIncludeRef")]
106#[repr(C)]
107#[derive(Default)]
108pub struct XmlXIncludeRef {
109 uri: Option<Box<str>>, fragment: Option<Box<str>>, elem: Option<XmlNodePtr>, inc: Option<XmlNodePtr>, xml: i32, fallback: i32, empty_fb: i32, expanding: i32, replace: i32, }
119
120#[doc(alias = "xmlXIncludeDoc")]
121#[repr(C)]
122pub struct XmlXIncludeDoc {
123 doc: Option<XmlDocPtr>, url: Box<str>, expanding: i32, }
127
128#[doc(alias = "xmlXIncludeTxt")]
129#[repr(C)]
130pub struct XmlXIncludeTxt {
131 text: Box<str>, url: Box<str>, }
134
135#[doc(alias = "xmlXIncludeCtxt")]
137#[repr(C)]
138pub struct XmlXIncludeCtxt {
139 doc: XmlDocPtr, inc_tab: Vec<XmlXIncludeRef>, txt_tab: Vec<XmlXIncludeTxt>, url_tab: Vec<XmlXIncludeDoc>, nb_errors: i32, fatal_err: i32, legacy: i32, parse_flags: i32, base: Option<Box<str>>, _private: *mut c_void, depth: i32, is_stream: i32, }
157
158impl XmlXIncludeCtxt {
159 #[doc(alias = "xmlXIncludeNewContext")]
163 pub fn new(doc: XmlDocPtr) -> Self {
164 XmlXIncludeCtxt {
165 doc,
166 inc_tab: vec![],
167 txt_tab: vec![],
168 url_tab: vec![],
169 nb_errors: 0,
170 fatal_err: 0,
171 legacy: 0,
172 parse_flags: 0,
173 base: None,
174 _private: null_mut(),
175 depth: 0,
176 is_stream: 0,
177 }
178 }
179
180 #[doc(alias = "xmlXIncludeGetProp")]
184 fn get_prop(&self, cur: XmlNodePtr, name: &str) -> Option<String> {
185 if let Some(ret) = cur.get_ns_prop(XINCLUDE_NS, Some(name)) {
186 return Some(ret);
187 }
188 if self.legacy != 0 {
189 if let Some(ret) = cur.get_ns_prop(XINCLUDE_OLD_NS, Some(name)) {
190 return Some(ret);
191 }
192 }
193 cur.get_prop(name)
194 }
195
196 #[doc(alias = "xmlXIncludeSetStreamingMode")]
200 pub(crate) fn set_streaming_mode(&mut self, mode: i32) -> i32 {
201 self.is_stream = (mode != 0) as i32;
202 0
203 }
204
205 #[doc(alias = "xmlXIncludeSetFlags")]
209 pub fn set_flags(&mut self, flags: i32) -> i32 {
210 self.parse_flags = flags;
211 0
212 }
213
214 #[doc(alias = "xmlXIncludeAddNode")]
216 unsafe fn add_node(&mut self, cur: XmlNodePtr) -> usize {
217 unsafe {
218 let mut xml: i32 = 1;
219 let mut local: i32 = 0;
220
221 let href = self.get_prop(cur, XINCLUDE_HREF).unwrap_or("".to_owned());
223 let parse = self.get_prop(cur, XINCLUDE_PARSE);
224 if let Some(parse) = parse {
225 if parse == XINCLUDE_PARSE_XML {
226 xml = 1;
227 } else if parse == XINCLUDE_PARSE_TEXT {
228 xml = 0;
229 } else {
230 xml_xinclude_err!(
231 self,
232 Some(cur.into()),
233 XmlParserErrors::XmlXIncludeParseValue,
234 "invalid value {} for 'parse'\n",
235 parse
236 );
237 return usize::MAX;
238 }
239 }
240
241 let mut base = None;
243 let mut uri = if let Some(b) = cur.get_base(Some(self.doc)) {
244 base = Some(b);
245 build_uri(&href, base.as_deref().unwrap())
246 } else {
247 self.doc
248 .url
249 .as_deref()
250 .and_then(|base| build_uri(&href, base))
251 };
252 if uri.is_none() {
253 if let Some(base) = base.as_deref() {
254 if let (Some(escbase), Some(eschref)) = (escape_url(base), escape_url(&href)) {
256 uri = build_uri(&eschref, &escbase);
257 }
258 }
259 }
260 let Some(uri) = uri else {
261 xml_xinclude_err!(
262 self,
263 Some(cur.into()),
264 XmlParserErrors::XmlXIncludeHrefURI,
265 "failed build URL\n"
266 );
267 return usize::MAX;
268 };
269 let mut fragment = self.get_prop(cur, XINCLUDE_PARSE_XPOINTER);
270
271 let Some(mut parsed_uri) = XmlURI::parse(&uri) else {
273 xml_xinclude_err!(
274 self,
275 Some(cur.into()),
276 XmlParserErrors::XmlXIncludeHrefURI,
277 "invalid value URI {}\n",
278 uri
279 );
280 return usize::MAX;
281 };
282
283 if parsed_uri.fragment.is_some() {
284 if self.legacy != 0 {
285 if fragment.is_none() {
286 fragment = parsed_uri.fragment.as_deref().map(|f| f.to_owned());
287 }
288 } else {
289 xml_xinclude_err!(
290 self,
291 Some(cur.into()),
292 XmlParserErrors::XmlXIncludeFragmentID,
293 "Invalid fragment identifier in URI {} use the xpointer attribute\n",
294 uri
295 );
296 return usize::MAX;
297 }
298 parsed_uri.fragment = None;
299 }
300 let url = parsed_uri.save();
301
302 if self.doc.url.as_deref() == Some(url.as_str()) {
303 local = 1;
304 }
305
306 if local == 1 && xml == 1 && fragment.as_deref().is_none_or(|f| f.is_empty()) {
308 xml_xinclude_err!(
309 self,
310 Some(cur.into()),
311 XmlParserErrors::XmlXIncludeRecursion,
312 "detected a local recursion with no xpointer in {}\n",
313 url
314 );
315 return usize::MAX;
316 }
317
318 let refe = self.add_ref(Some(&url), cur);
319 self.inc_tab[refe].fragment = fragment.map(|fragment| fragment.into());
320 self.inc_tab[refe].xml = xml;
321 refe
322 }
323 }
324
325 #[doc(alias = "xmlXIncludeNewRef")]
329 fn add_ref(&mut self, uri: Option<&str>, elem: XmlNodePtr) -> usize {
330 self.inc_tab.push(XmlXIncludeRef {
331 uri: uri.map(|uri| uri.into()),
332 fragment: None,
333 elem: Some(elem),
334 xml: 0,
335 inc: None,
336 ..Default::default()
337 });
338 self.inc_tab.len() - 1
339 }
340
341 #[doc(alias = "xmlXIncludeCopyNode")]
345 unsafe fn copy_node(&mut self, elem: XmlNodePtr, copy_children: i32) -> Option<XmlNodePtr> {
346 unsafe {
347 let mut result: Option<XmlNodePtr> = None;
348 let mut insert_parent: Option<XmlNodePtr> = None;
349 let mut insert_last: Option<XmlNodePtr> = None;
350
351 let mut cur = if copy_children != 0 {
352 elem.children.map(|c| XmlNodePtr::try_from(c).unwrap())?
353 } else {
354 elem
355 };
356
357 loop {
358 let mut copy = None;
359 let mut recurse: i32 = 0;
360
361 if matches!(
362 cur.element_type(),
363 XmlElementType::XmlDocumentNode | XmlElementType::XmlDTDNode
364 ) {
365 } else if cur.element_type() == XmlElementType::XmlElementNode
366 && cur.name().as_deref() == Some(XINCLUDE_NODE)
367 && cur.ns.is_some_and(|ns| {
368 ns.href().as_deref() == Some(XINCLUDE_NS)
369 || ns.href().as_deref() == Some(XINCLUDE_OLD_NS)
370 })
371 {
372 let ref_index = self.expand_node(cur);
373
374 if ref_index == usize::MAX {
375 xml_free_node_list(result);
377 return None;
378 }
379 if let Some(inc) = self.inc_tab[ref_index].inc {
381 let Some(res) = xml_static_copy_node_list(
382 Some(XmlGenericNodePtr::from(inc)),
383 Some(self.doc),
384 insert_parent.map(|parent| parent.into()),
385 ) else {
386 xml_free_node_list(result);
388 return None;
389 };
390 copy = Some(XmlNodePtr::try_from(res).unwrap());
391 }
392 } else {
393 let Some(res) = xml_static_copy_node(
394 XmlGenericNodePtr::from(cur),
395 Some(self.doc),
396 insert_parent.map(|parent| parent.into()),
397 2,
398 ) else {
399 xml_free_node_list(result);
401 return None;
402 };
403 copy = Some(XmlNodePtr::try_from(res).unwrap());
404
405 recurse = (cur.element_type() != XmlElementType::XmlEntityRefNode
406 && cur.children().is_some()) as i32;
407 }
408
409 if let Some(mut copy) = copy {
410 if result.is_none() {
411 result = Some(copy);
412 }
413 if let Some(mut insert_last) = insert_last {
414 insert_last.next = Some(copy.into());
415 copy.prev = Some(insert_last.into());
416 } else if let Some(mut insert_parent) = insert_parent {
417 insert_parent.children = Some(copy.into());
418 }
419 let mut now = copy;
420 while let Some(next) = now.next.map(|node| XmlNodePtr::try_from(node).unwrap())
421 {
422 now = next;
423 }
424 insert_last = Some(now);
425 }
426
427 if recurse != 0 {
428 cur = cur
429 .children
430 .map(|c| XmlNodePtr::try_from(c).unwrap())
431 .unwrap();
432 insert_parent = insert_last.take();
433 continue;
434 }
435
436 if cur == elem {
437 return result;
438 }
439
440 while cur.next.is_none() {
441 if let Some(mut insert_parent) = insert_parent {
442 insert_parent.last = insert_last.map(|node| node.into());
443 }
444 cur = cur
445 .parent
446 .map(|p| XmlNodePtr::try_from(p).unwrap())
447 .unwrap();
448 if cur == elem {
449 return result;
450 }
451 insert_last = insert_parent;
452 insert_parent = insert_parent
453 .unwrap()
454 .parent
455 .map(|p| XmlNodePtr::try_from(p).unwrap());
456 }
457
458 cur = cur
459 .next
460 .map(|node| XmlNodePtr::try_from(node).unwrap())
461 .unwrap();
462 }
463
464 }
468 }
469
470 #[doc(alias = "xmlXIncludeTestNode")]
474 unsafe fn test_node(&mut self, node: XmlNodePtr) -> i32 {
475 unsafe {
476 if node.element_type() != XmlElementType::XmlElementNode {
477 return 0;
478 }
479 let Some(node_ns) = node.ns else {
480 return 0;
481 };
482 if node_ns.href().as_deref() == Some(XINCLUDE_NS)
483 || node_ns.href().as_deref() == Some(XINCLUDE_OLD_NS)
484 {
485 if node_ns.href().as_deref() == Some(XINCLUDE_OLD_NS) && self.legacy == 0 {
486 self.legacy = 1;
487 }
488 if node.name().as_deref() == Some(XINCLUDE_NODE) {
489 let mut child = node.children.map(|c| XmlNodePtr::try_from(c).unwrap());
490 let mut nb_fallback: i32 = 0;
491
492 while let Some(cur_node) = child {
493 if cur_node.element_type() == XmlElementType::XmlElementNode
494 && cur_node.ns.is_some_and(|ns| {
495 ns.href().as_deref() == Some(XINCLUDE_NS)
496 || ns.href().as_deref() == Some(XINCLUDE_OLD_NS)
497 })
498 {
499 if cur_node.name().as_deref() == Some(XINCLUDE_NODE) {
500 xml_xinclude_err!(
501 self,
502 Some(node.into()),
503 XmlParserErrors::XmlXIncludeIncludeInInclude,
504 "{} has an 'include' child\n",
505 XINCLUDE_NODE
506 );
507 return 0;
508 }
509 if cur_node.name().as_deref() == Some(XINCLUDE_FALLBACK) {
510 nb_fallback += 1;
511 }
512 }
513 child = cur_node
514 .next
515 .map(|node| XmlNodePtr::try_from(node).unwrap());
516 }
517 if nb_fallback > 1 {
518 xml_xinclude_err!(
519 self,
520 Some(node.into()),
521 XmlParserErrors::XmlXIncludeFallbacksInInclude,
522 "{} has multiple fallback children\n",
523 XINCLUDE_NODE
524 );
525 return 0;
526 }
527 return 1;
528 }
529 if node.name().as_deref() == Some(XINCLUDE_FALLBACK)
530 && (node.parent().is_none()
531 || node.parent().unwrap().element_type() != XmlElementType::XmlElementNode
532 || XmlNodePtr::try_from(node.parent().unwrap())
533 .unwrap()
534 .ns
535 .is_none_or(|ns| {
536 ns.href().as_deref() != Some(XINCLUDE_NS)
537 && ns.href().as_deref() != Some(XINCLUDE_OLD_NS)
538 })
539 || node.parent().unwrap().name().as_deref() != Some(XINCLUDE_NODE))
540 {
541 xml_xinclude_err!(
542 self,
543 Some(node.into()),
544 XmlParserErrors::XmlXIncludeFallbackNotInInclude,
545 "{} is not the child of an 'include'\n",
546 XINCLUDE_FALLBACK
547 );
548 }
549 }
550 0
551 }
552 }
553
554 #[doc(alias = "xmlXIncludeExpandNode")]
559 unsafe fn expand_node(&mut self, node: XmlNodePtr) -> usize {
560 unsafe {
561 if self.fatal_err != 0 {
562 return usize::MAX;
563 }
564 if self.depth >= XINCLUDE_MAX_DEPTH {
565 xml_xinclude_err!(
566 self,
567 Some(node.into()),
568 XmlParserErrors::XmlXIncludeRecursion,
569 "maximum recursion depth exceeded\n"
570 );
571 self.fatal_err = 1;
572 return usize::MAX;
573 }
574
575 for (i, inc) in self.inc_tab.iter().enumerate() {
576 if inc.elem == Some(node) {
577 if inc.expanding != 0 {
578 xml_xinclude_err!(
579 self,
580 Some(node.into()),
581 XmlParserErrors::XmlXIncludeRecursion,
582 "inclusion loop detected\n"
583 );
584 return usize::MAX;
585 }
586 return i;
587 }
588 }
589
590 let refe = self.add_node(node);
591 if refe == usize::MAX {
592 return usize::MAX;
593 }
594 self.inc_tab[refe].expanding = 1;
595 self.depth += 1;
596 self.load_node(refe);
597 self.depth -= 1;
598 self.inc_tab[refe].expanding = 0;
599
600 refe
601 }
602 }
603
604 #[doc(alias = "xmlXIncludeIncludeNode")]
608 unsafe fn include_node(&mut self, ref_index: usize) -> i32 {
609 unsafe {
610 if ref_index == usize::MAX {
611 return -1;
612 }
613 let cur = self.inc_tab[ref_index].elem;
614 let Some(mut cur) =
615 cur.filter(|cur| cur.element_type() != XmlElementType::XmlNamespaceDecl)
616 else {
617 return -1;
618 };
619
620 let mut list = self.inc_tab[ref_index].inc.take();
621 self.inc_tab[ref_index].empty_fb = 0;
622
623 if cur
625 .parent()
626 .filter(|p| p.element_type() != XmlElementType::XmlElementNode)
627 .is_some()
628 {
629 let mut nb_elem: i32 = 0;
630
631 let mut tmp = list;
632 while let Some(cur) = tmp {
633 if cur.element_type() == XmlElementType::XmlElementNode {
634 nb_elem += 1;
635 }
636 tmp = cur.next.map(|node| XmlNodePtr::try_from(node).unwrap());
637 }
638 if nb_elem > 1 {
639 xml_xinclude_err!(
640 self,
641 self.inc_tab[ref_index].elem.map(|node| node.into()),
642 XmlParserErrors::XmlXIncludeMultipleRoot,
643 "XInclude error: would result in multiple root nodes\n"
644 );
645 xml_free_node_list(list);
646 return -1;
647 }
648 }
649
650 if self.parse_flags & XmlParserOption::XmlParseNoXIncnode as i32 != 0 {
651 while let Some(cur_node) = list {
653 list = cur_node
654 .next
655 .map(|node| XmlNodePtr::try_from(node).unwrap());
656
657 cur.add_prev_sibling(XmlGenericNodePtr::from(cur_node));
658 }
659 cur.unlink();
661 xml_free_node(cur);
662 } else {
663 if self.inc_tab[ref_index].fallback != 0 {
665 cur.unset_prop("href");
666 }
667 cur.typ = XmlElementType::XmlXIncludeStart;
668 let mut child = cur.children();
670 while let Some(mut now) = child {
671 let next = now.next();
672 now.unlink();
673 xml_free_node(now);
674 child = next;
675 }
676 let Some(mut end) = xml_new_doc_node(cur.doc, cur.ns, &cur.name().unwrap(), None)
677 else {
678 xml_xinclude_err!(
679 self,
680 self.inc_tab[ref_index].elem.map(|node| node.into()),
681 XmlParserErrors::XmlXIncludeBuildFailed,
682 "failed to build node\n"
683 );
684 xml_free_node_list(list);
685 return -1;
686 };
687 end.typ = XmlElementType::XmlXIncludeEnd;
688 cur.add_next_sibling(end.into());
689
690 while let Some(cur_node) = list {
692 list = cur_node
693 .next
694 .map(|node| XmlNodePtr::try_from(node).unwrap());
695
696 end.add_prev_sibling(XmlGenericNodePtr::from(cur_node));
697 }
698 }
699
700 0
701 }
702 }
703
704 #[doc(alias = "xmlXIncludeMergeEntities")]
708 unsafe fn merge_entities(&mut self, doc: XmlDocPtr, from: XmlDocPtr) -> i32 {
709 unsafe {
710 if from.int_subset.is_none() {
711 return 0;
712 }
713
714 let Some(target) = doc.int_subset.or_else(|| {
715 let cur = doc.get_root_element()?;
716 xml_create_int_subset(Some(doc), cur.name().as_deref(), None, None)
717 }) else {
718 return -1;
719 };
720
721 let source = from.int_subset;
722 if let Some(source) = source {
723 for &entity in source.entities.values() {
724 self.merge_entity(entity, doc);
725 }
726 }
727 let source = from.ext_subset;
728 if let Some(source) = source {
729 if target.external_id != source.external_id && target.system_id != source.system_id
731 {
732 for &entity in source.entities.values() {
733 self.merge_entity(entity, doc);
734 }
735 }
736 }
737 0
738 }
739 }
740
741 #[doc(alias = "xmlXIncludeMergeOneEntity")]
743 unsafe fn merge_entity(&mut self, ent: XmlEntityPtr, doc: XmlDocPtr) {
744 unsafe {
745 match ent.etype {
746 XmlEntityType::XmlInternalParameterEntity
747 | XmlEntityType::XmlExternalParameterEntity
748 | XmlEntityType::XmlInternalPredefinedEntity => return,
749 XmlEntityType::XmlInternalGeneralEntity
750 | XmlEntityType::XmlExternalGeneralParsedEntity
751 | XmlEntityType::XmlExternalGeneralUnparsedEntity => {}
752 }
753
754 let ret = xml_add_doc_entity(
755 doc,
756 &ent.name().unwrap(),
757 ent.etype,
758 ent.external_id.as_deref(),
759 ent.system_id.as_deref(),
760 ent.content.as_deref(),
761 );
762 if let Some(mut ret) = ret {
763 ret.uri = ent.uri.clone();
764 return;
765 }
766
767 'error: {
768 let prev = xml_get_doc_entity(Some(doc), &ent.name().unwrap());
769 if let Some(prev) = prev {
770 if ent.etype != prev.etype {
771 break 'error;
772 }
773
774 if ent.system_id.is_some() && prev.system_id.is_some() {
775 if ent.system_id != prev.system_id {
776 break 'error;
777 }
778 } else if ent.external_id.is_some() && prev.external_id.is_some() {
779 if ent.external_id != prev.external_id {
780 break 'error;
781 }
782 } else if ent.content.is_some() && prev.content.is_some() {
783 if ent.content != prev.content {
784 break 'error;
785 }
786 } else {
787 break 'error;
788 }
789 }
790 return;
791 }
792 match ent.etype {
793 XmlEntityType::XmlInternalParameterEntity
794 | XmlEntityType::XmlExternalParameterEntity
795 | XmlEntityType::XmlInternalPredefinedEntity
796 | XmlEntityType::XmlInternalGeneralEntity
797 | XmlEntityType::XmlExternalGeneralParsedEntity => return,
798 XmlEntityType::XmlExternalGeneralUnparsedEntity => {}
799 }
800 xml_xinclude_err!(
801 self,
802 Some(ent.into()),
803 XmlParserErrors::XmlXIncludeEntityDefMismatch,
804 "mismatch in redefinition of entity {}\n",
805 ent.name().unwrap().into_owned()
806 );
807 }
808 }
809
810 #[doc(alias = "xmlXIncludeCopyXPointer")]
816 unsafe fn copy_xpointer(&mut self, obj: &XmlXPathObject) -> Option<XmlNodePtr> {
817 unsafe {
818 let mut list: Option<XmlNodePtr> = None;
819
820 match obj.typ {
821 XmlXPathObjectType::XPathNodeset => {
822 let set = obj.nodesetval.as_deref()?;
823 let mut last: Option<XmlNodePtr> = None;
824 for &now in &set.node_tab {
825 let node = match now.element_type() {
826 XmlElementType::XmlDocumentNode
827 | XmlElementType::XmlHTMLDocumentNode => {
828 let Some(node) =
829 XmlDocPtr::try_from(now).unwrap().get_root_element()
830 else {
831 xml_xinclude_err!(
832 self,
833 Some(now),
834 XmlParserErrors::XmlErrInternalError,
835 "document without root\n"
836 );
837 continue;
838 };
839 node
840 }
841 XmlElementType::XmlTextNode
842 | XmlElementType::XmlCDATASectionNode
843 | XmlElementType::XmlElementNode
844 | XmlElementType::XmlPINode
845 | XmlElementType::XmlCommentNode => XmlNodePtr::try_from(now).unwrap(),
846 _ => {
847 xml_xinclude_err!(
848 self,
849 Some(now),
850 XmlParserErrors::XmlXIncludeXPtrResult,
851 "invalid node type in XPtr result\n"
852 );
853 continue;
854 }
855 };
856 let Some(mut copy) = self.copy_node(node, 0) else {
860 xml_free_node_list(list);
861 return None;
862 };
863 if let Some(mut last) = last {
864 while let Some(next) =
865 last.next.map(|node| XmlNodePtr::try_from(node).unwrap())
866 {
867 last = next;
868 }
869 copy.prev = Some(last.into());
870 last.next = Some(copy.into());
871 } else {
872 list = Some(copy);
873 }
874 last = Some(copy);
875 }
876 }
877 #[cfg(feature = "libxml_xptr_locs")]
878 XmlXPathObjectType::XPathLocationset => {
879 let set = obj.user.as_ref().and_then(|user| user.as_location_set())?;
880
881 let mut last: Option<XmlNodePtr> = None;
882 for loc in &set.loc_tab {
883 if let Some(mut last) = last {
884 last.add_next_sibling(self.copy_xpointer(loc).unwrap().into());
885 } else {
886 list = self.copy_xpointer(loc);
887 last = list;
888 }
889 if let Some(mut l) = last {
890 while let Some(next) =
891 l.next.map(|node| XmlNodePtr::try_from(node).unwrap())
892 {
893 l = next;
894 }
895 last = Some(l);
896 }
897 }
898 }
899 #[cfg(feature = "libxml_xptr_locs")]
900 XmlXPathObjectType::XPathRange => {
901 return self
902 .copy_range(obj)
903 .map(|node| XmlNodePtr::try_from(node).unwrap());
904 }
905 #[cfg(feature = "libxml_xptr_locs")]
906 XmlXPathObjectType::XPathPoint => { }
907 _ => {}
908 }
909 list
910 }
911 }
912
913 #[doc(alias = "xmlXIncludeCopyRange")]
918 #[cfg(feature = "libxml_xptr_locs")]
919 unsafe fn copy_range(&self, range: &XmlXPathObject) -> Option<XmlGenericNodePtr> {
920 unsafe {
921 use crate::{tree::xml_new_doc_text, xpointer::xml_xptr_advance_node};
922
923 let mut list = None;
925 let mut last = None;
926 let mut list_parent = None;
927 let mut level: i32 = 0;
928 let mut last_level: i32 = 0;
929 let mut end_level: i32 = 0;
930 let mut end_flag: i32 = 0;
931
932 if range.typ != XmlXPathObjectType::XPathRange {
933 return None;
934 }
935 let start = range
936 .user
937 .as_ref()
938 .and_then(|user| user.as_node())
939 .copied()
940 .filter(|node| node.element_type() != XmlElementType::XmlNamespaceDecl)?;
941
942 let Some(mut end) = range
943 .user2
944 .as_ref()
945 .and_then(|user| user.as_node())
946 .copied()
947 else {
948 return xml_doc_copy_node(start, Some(self.doc), 1);
949 };
950 if end.element_type() == XmlElementType::XmlNamespaceDecl {
951 return None;
952 }
953
954 let mut cur = Some(start);
955 let mut index1 = range.index;
956 let mut index2 = range.index2;
957 while let Some(cur_node) = cur {
964 if level < 0 {
966 while level < 0 {
967 let mut tmp2 =
969 xml_doc_copy_node(list_parent.unwrap(), Some(self.doc), 2).unwrap();
970 tmp2.add_child(list.unwrap());
971 list = Some(tmp2);
972 list_parent = list_parent.unwrap().parent();
973 level += 1;
974 }
975 last = list;
976 last_level = 0;
977 }
978 while level < last_level {
980 last = last.unwrap().parent();
981 last_level -= 1;
982 }
983 if cur_node == end {
984 if cur_node.element_type() == XmlElementType::XmlTextNode {
986 let cur_node = XmlNodePtr::try_from(cur_node).unwrap();
987
988 let tmp = if let Some(mut content) = cur_node.content.as_deref() {
989 let mut len = index2 as usize;
990 if start == XmlGenericNodePtr::from(cur_node) && index1 > 1 {
991 content = &content[index1 as usize - 1..];
992 len -= index1 as usize - 1;
993 }
994 xml_new_doc_text(Some(self.doc), Some(&content[..len]))
995 } else {
996 xml_new_doc_text(Some(self.doc), None)
997 };
998 if list.is_none() {
1000 return tmp.map(|node| node.into());
1001 }
1002 if level == last_level {
1004 last.unwrap().add_next_sibling(tmp.unwrap().into());
1005 } else {
1006 last.unwrap().add_child(tmp.unwrap().into());
1007 }
1008 return list;
1009 } else {
1010 end_level = level; end_flag = 1;
1013 let tmp = xml_doc_copy_node(cur_node, Some(self.doc), 2);
1015 if list.is_none() {
1016 list = tmp;
1017 list_parent = cur_node.parent();
1018 last = tmp;
1019 } else if level == last_level {
1020 last = last.unwrap().add_next_sibling(tmp.unwrap());
1021 } else {
1022 last = last.unwrap().add_child(tmp.unwrap());
1023 last_level = level;
1024 }
1025
1026 if index2 > 1 {
1027 end = xml_xinclude_get_nth_child(cur_node, index2 - 1).unwrap();
1028 index2 = 0;
1029 }
1030 if cur_node == start && index1 > 1 {
1031 cur = xml_xinclude_get_nth_child(cur_node, index1 - 1);
1032 index1 = 0;
1033 } else {
1034 cur = cur_node.children();
1035 }
1036 level += 1;
1038 continue; }
1041 } else if cur_node == start {
1042 if matches!(
1044 cur_node.element_type(),
1045 XmlElementType::XmlTextNode | XmlElementType::XmlCDATASectionNode
1046 ) {
1047 let cur_node = XmlNodePtr::try_from(cur_node).unwrap();
1048
1049 let tmp = if let Some(mut content) = cur_node.content.as_deref() {
1050 if index1 > 1 {
1051 content = &content[index1 as usize - 1..];
1052 index1 = 0;
1053 }
1054 xml_new_doc_text(Some(self.doc), Some(content))
1055 } else {
1056 xml_new_doc_text(Some(self.doc), None)
1057 };
1058 last = tmp.map(|node| node.into());
1059 list = tmp.map(|node| node.into());
1060 list_parent = cur_node.parent();
1061 } else {
1062 let tmp = xml_doc_copy_node(cur_node, Some(self.doc), 2);
1067 list = tmp;
1068 last = tmp;
1069 list_parent = cur_node.parent();
1070 if index1 > 1 {
1071 cur = xml_xinclude_get_nth_child(cur_node, index1 - 1);
1073 level = 1;
1074 last_level = 1;
1075 index1 = 0;
1076 continue; }
1079 }
1080 } else {
1081 let mut tmp = None;
1082 match cur_node.element_type() {
1083 XmlElementType::XmlDTDNode
1084 | XmlElementType::XmlElementDecl
1085 | XmlElementType::XmlAttributeDecl
1086 | XmlElementType::XmlEntityNode => { }
1087 XmlElementType::XmlEntityDecl => { }
1089 XmlElementType::XmlXIncludeStart | XmlElementType::XmlXIncludeEnd => {
1090 }
1092 XmlElementType::XmlAttributeNode => { }
1093 _ => {
1094 tmp = xml_doc_copy_node(cur_node, Some(self.doc), 2);
1097 }
1098 }
1099 if let Some(tmp) = tmp {
1100 if level == last_level {
1101 last = last.unwrap().add_next_sibling(tmp);
1102 } else {
1103 last = last.unwrap().add_child(tmp);
1104 last_level = level;
1105 }
1106 }
1107 }
1108 cur = xml_xptr_advance_node(cur_node, &mut level);
1110 if end_flag != 0 && level >= end_level {
1111 break;
1112 }
1113 }
1114 list
1115 }
1116 }
1117
1118 #[doc(alias = "xmlXIncludeRecurseDoc")]
1120 unsafe fn recurse_doc(&mut self, doc: XmlDocPtr, _url: &str) {
1121 unsafe {
1122 let old_doc = self.doc;
1123 let old_inc_tab = take(&mut self.inc_tab);
1124 let old_is_stream: i32 = self.is_stream;
1125 self.doc = doc;
1126 self.is_stream = 0;
1127
1128 self.do_process(doc.get_root_element().unwrap());
1129
1130 self.doc = old_doc;
1131 self.inc_tab = old_inc_tab;
1132 self.is_stream = old_is_stream;
1133 }
1134 }
1135
1136 #[doc(alias = "xmlXIncludeLoadDoc")]
1140 unsafe fn load_doc(&mut self, url: &str, ref_index: usize) -> i32 {
1141 unsafe {
1142 let ret: i32 = -1;
1143 #[cfg(feature = "xpointer")]
1144 let save_flags: i32;
1145
1146 let Some(mut uri) = XmlURI::parse(url) else {
1148 xml_xinclude_err!(
1149 self,
1150 self.inc_tab[ref_index].elem.map(|node| node.into()),
1151 XmlParserErrors::XmlXIncludeHrefURI,
1152 "invalid value URI {}\n",
1153 url
1154 );
1155 return ret;
1156 };
1157 let mut fragment = uri.fragment.take();
1158 if let Some(frag) = self.inc_tab[ref_index].fragment.as_deref() {
1159 fragment = Some(Cow::Owned(frag.to_owned()));
1160 }
1161 let mut url = uri.save();
1162
1163 let doc = 'load: {
1166 if url.is_empty() || url.starts_with('#') || self.doc.url.as_deref() == Some(&url) {
1167 break 'load self.doc;
1168 }
1169 for inc_doc in &self.url_tab {
1171 if *url == *inc_doc.url {
1172 if inc_doc.expanding != 0 {
1173 xml_xinclude_err!(
1174 self,
1175 self.inc_tab[ref_index].elem.map(|node| node.into()),
1176 XmlParserErrors::XmlXIncludeRecursion,
1177 "inclusion loop detected\n"
1178 );
1179 return ret;
1180 }
1181 let Some(doc) = inc_doc.doc else {
1182 return ret;
1183 };
1184 break 'load doc;
1185 }
1186 }
1187
1188 #[cfg(feature = "xpointer")]
1190 {
1191 save_flags = self.parse_flags;
1195 if fragment.is_some() {
1196 self.parse_flags |= XmlParserOption::XmlParseNoEnt as i32;
1198 }
1199 }
1200
1201 let doc = self.parse_file(&url);
1202 #[cfg(feature = "xpointer")]
1203 {
1204 self.parse_flags = save_flags;
1205 }
1206
1207 let cache_nr = self.url_tab.len();
1209 self.url_tab.push(XmlXIncludeDoc {
1210 doc,
1211 url: url.clone().into_boxed_str(),
1212 expanding: 0,
1213 });
1214
1215 let Some(doc) = doc else {
1216 return ret;
1217 };
1218 if doc.url.as_deref() != Some(&url) {
1223 url = doc.url.clone().unwrap();
1224 }
1225
1226 self.merge_entities(self.doc, doc);
1228
1229 self.url_tab[cache_nr].expanding = 1;
1241 self.recurse_doc(doc, &url);
1242 self.url_tab[cache_nr].expanding = 0;
1244 doc
1245 };
1246
1247 if let Some(fragment) = fragment {
1249 #[cfg(feature = "xpointer")]
1250 {
1251 if self.is_stream != 0 && doc == self.doc {
1255 xml_xinclude_err!(
1256 self,
1257 self.inc_tab[ref_index].elem.map(|node| node.into()),
1258 XmlParserErrors::XmlXIncludeXPtrFailed,
1259 "XPointer expressions not allowed in streaming mode\n"
1260 );
1261 return ret;
1262 }
1263
1264 let mut xptrctxt = xml_xptr_new_context(Some(doc), None, None);
1265 let Some(mut xptr) = xml_xptr_eval(&fragment, &mut xptrctxt) else {
1266 xml_xinclude_err!(
1267 self,
1268 self.inc_tab[ref_index].elem.map(|node| node.into()),
1269 XmlParserErrors::XmlXIncludeXPtrFailed,
1270 "XPointer evaluation failed: #{}\n",
1271 fragment
1272 );
1273 return ret;
1274 };
1275 match xptr.typ {
1276 XmlXPathObjectType::XPathUndefined
1277 | XmlXPathObjectType::XPathBoolean
1278 | XmlXPathObjectType::XPathNumber
1279 | XmlXPathObjectType::XPathString
1280 | XmlXPathObjectType::XPathUsers
1281 | XmlXPathObjectType::XPathXSLTTree => {
1282 xml_xinclude_err!(
1283 self,
1284 self.inc_tab[ref_index].elem.map(|node| node.into()),
1285 XmlParserErrors::XmlXIncludeXPtrResult,
1286 "XPointer is not a range: #{}\n",
1287 fragment
1288 );
1289 return ret;
1290 }
1291 #[cfg(feature = "libxml_xptr_locs")]
1292 XmlXPathObjectType::XPathPoint => {
1293 xml_xinclude_err!(
1294 self,
1295 self.inc_tab[ref_index].elem.map(|node| node.into()),
1296 XmlParserErrors::XmlXIncludeXPtrResult,
1297 "XPointer is not a range: #{}\n",
1298 fragment
1299 );
1300 return ret;
1301 }
1302 XmlXPathObjectType::XPathNodeset => {
1303 if xptr.nodesetval.as_deref().is_none_or(|n| n.is_empty()) {
1304 return ret;
1305 }
1306 }
1307 #[cfg(feature = "libxml_xptr_locs")]
1308 XmlXPathObjectType::XPathRange | XmlXPathObjectType::XPathLocationset => {} }
1310 if let Some(set) = xptr.nodesetval.as_deref_mut() {
1311 let mut i = 0;
1312 while i < set.node_tab.len() {
1313 let node = set.node_tab[i];
1314 match node.element_type() {
1315 XmlElementType::XmlElementNode
1316 | XmlElementType::XmlTextNode
1317 | XmlElementType::XmlCDATASectionNode
1318 | XmlElementType::XmlEntityRefNode
1319 | XmlElementType::XmlEntityNode
1320 | XmlElementType::XmlPINode
1321 | XmlElementType::XmlCommentNode
1322 | XmlElementType::XmlDocumentNode
1323 | XmlElementType::XmlHTMLDocumentNode => {
1324 }
1326
1327 XmlElementType::XmlAttributeNode => {
1328 xml_xinclude_err!(
1329 self,
1330 self.inc_tab[ref_index].elem.map(|node| node.into()),
1331 XmlParserErrors::XmlXIncludeXPtrResult,
1332 "XPointer selects an attribute: #{}\n",
1333 fragment
1334 );
1335 set.node_tab.swap_remove(i);
1336 continue;
1337 }
1338 XmlElementType::XmlNamespaceDecl => {
1339 xml_xinclude_err!(
1340 self,
1341 self.inc_tab[ref_index].elem.map(|node| node.into()),
1342 XmlParserErrors::XmlXIncludeXPtrResult,
1343 "XPointer selects a namespace: #{}\n",
1344 fragment
1345 );
1346 set.node_tab.swap_remove(i);
1347 continue;
1348 }
1349 XmlElementType::XmlDocumentTypeNode
1350 | XmlElementType::XmlDocumentFragNode
1351 | XmlElementType::XmlNotationNode
1352 | XmlElementType::XmlDTDNode
1353 | XmlElementType::XmlElementDecl
1354 | XmlElementType::XmlAttributeDecl
1355 | XmlElementType::XmlEntityDecl
1356 | XmlElementType::XmlXIncludeStart
1357 | XmlElementType::XmlXIncludeEnd => {
1358 xml_xinclude_err!(
1359 self,
1360 self.inc_tab[ref_index].elem.map(|node| node.into()),
1361 XmlParserErrors::XmlXIncludeXPtrResult,
1362 "XPointer selects unexpected nodes: #{}\n",
1363 fragment
1364 );
1365 set.node_tab.swap_remove(i);
1366 continue; }
1368 _ => unreachable!(),
1369 }
1370 i += 1;
1371 }
1372 }
1373 self.inc_tab[ref_index].inc = self.copy_xpointer(&xptr);
1374 }
1375 } else {
1376 self.inc_tab[ref_index].inc =
1378 xml_doc_copy_node(doc.get_root_element().unwrap().into(), Some(self.doc), 1)
1379 .and_then(|node| XmlNodePtr::try_from(node).ok());
1380 }
1381
1382 if doc.parse_flags & XmlParserOption::XmlParseNoBasefix as i32 == 0
1384 && self.parse_flags & XmlParserOption::XmlParseNoBasefix as i32 == 0
1385 {
1386 let mut base = self.inc_tab[ref_index]
1389 .elem
1390 .unwrap()
1391 .get_ns_prop("base", Some(XML_XML_NAMESPACE));
1392 if base.is_none() {
1393 if let Some(cur_base) = build_relative_uri(&url, self.base.as_deref()) {
1396 if cur_base.contains('/') {
1398 base = Some(cur_base.into_owned());
1399 }
1400 } else {
1401 xml_xinclude_err!(
1403 self,
1404 self.inc_tab[ref_index].elem.map(|node| node.into()),
1405 XmlParserErrors::XmlXIncludeHrefURI,
1406 "trying to build relative URI from {}\n",
1407 url
1408 );
1409 }
1410 }
1411 if let Some(base) = base {
1412 let mut node = self.inc_tab[ref_index].inc;
1414 while let Some(mut cur_node) = node {
1415 if cur_node.element_type() == XmlElementType::XmlElementNode {
1417 if let Some(cur_base) = cur_node.get_base(cur_node.doc) {
1418 if cur_node.doc.as_deref().and_then(|doc| doc.url.as_deref())
1422 == Some(cur_base.as_str())
1423 {
1424 cur_node.set_base(Some(&base));
1425 } else {
1426 if let Some(xml_base) =
1430 cur_node.get_ns_prop("base", Some(XML_XML_NAMESPACE))
1431 {
1432 let rel_base = build_uri(&xml_base, &base);
1433 if let Some(rel_base) = rel_base {
1434 cur_node.set_base(Some(&rel_base));
1435 } else {
1436 xml_xinclude_err!(
1438 self,
1439 self.inc_tab[ref_index]
1440 .elem
1441 .map(|node| node.into()),
1442 XmlParserErrors::XmlXIncludeHrefURI,
1443 "trying to rebuild base from {}\n",
1444 xml_base
1445 );
1446 }
1447 }
1448 }
1449 } else {
1450 cur_node.set_base(Some(&base));
1452 }
1453 }
1454 node = cur_node
1455 .next
1456 .map(|node| XmlNodePtr::try_from(node).unwrap());
1457 }
1458 }
1459 }
1460 0
1461 }
1462 }
1463
1464 #[doc(alias = "xmlXIncludeLoadTxt")]
1468 unsafe fn load_txt(&mut self, mut url: &str, ref_index: usize) -> i32 {
1469 unsafe {
1470 let ret: i32 = -1;
1471 let mut enc = XmlCharEncoding::None;
1472
1473 if url == "-" {
1475 url = "./-";
1476 }
1477
1478 let Some(uri) = XmlURI::parse(url) else {
1480 xml_xinclude_err!(
1481 self,
1482 self.inc_tab[ref_index].elem.map(|node| node.into()),
1483 XmlParserErrors::XmlXIncludeHrefURI,
1484 "invalid value URI {}\n",
1485 url
1486 );
1487 return ret;
1488 };
1489 if let Some(fragment) = uri.fragment.as_deref() {
1490 xml_xinclude_err!(
1491 self,
1492 self.inc_tab[ref_index].elem.map(|node| node.into()),
1493 XmlParserErrors::XmlXIncludeTextFragment,
1494 "fragment identifier forbidden for text: {}\n",
1495 fragment
1496 );
1497 return ret;
1498 }
1499 let url = uri.save();
1500
1501 if url.is_empty() {
1503 xml_xinclude_err!(
1504 self,
1505 self.inc_tab[ref_index].elem.map(|node| node.into()),
1506 XmlParserErrors::XmlXIncludeTextDocument,
1507 "text serialization of document not available\n"
1508 );
1509 return ret;
1510 }
1511
1512 for txt in &self.txt_tab {
1514 if *url == *txt.url {
1515 let node = xml_new_doc_text(Some(self.doc), Some(&txt.text));
1516 self.inc_tab[ref_index].inc = node;
1517 return 0;
1518 }
1519 }
1520
1521 let mut encoding = None;
1523 if let Some(elem) = self.inc_tab[ref_index].elem {
1524 encoding = elem.get_prop(XINCLUDE_PARSE_ENCODING);
1525 }
1526 if let Some(encoding) = encoding {
1527 match encoding.parse::<XmlCharEncoding>() {
1532 Ok(e) => enc = e,
1533 _ => {
1534 xml_xinclude_err!(
1535 self,
1536 self.inc_tab[ref_index].elem.map(|node| node.into()),
1537 XmlParserErrors::XmlXIncludeUnknownEncoding,
1538 "encoding {} not supported\n",
1539 encoding
1540 );
1541 return ret;
1542 }
1543 }
1544 }
1545
1546 let mut pctxt = XmlParserCtxt::new().unwrap();
1548 let Some(mut input_stream) = xml_load_external_entity(Some(&url), None, &mut pctxt)
1549 else {
1550 return ret;
1551 };
1552 let Some(buf) = input_stream.buf.as_mut() else {
1553 return ret;
1554 };
1555 buf.encoder = get_encoding_handler(enc);
1556 let Some(mut node) = xml_new_doc_text(Some(self.doc), None) else {
1557 let node = self.inc_tab[ref_index].elem.map(|node| node.into());
1558 xml_xinclude_err_memory(Some(self), node, None);
1559 return ret;
1560 };
1561
1562 while buf.grow(4096) > 0 {}
1564
1565 let content = buf.buffer.as_ref();
1566 match std::str::from_utf8(content) {
1567 Ok(content) if content.chars().all(|c| c.is_xml_char()) => {
1568 node.add_content(content);
1569 }
1570 _ => {
1571 xml_xinclude_err!(
1572 self,
1573 self.inc_tab[ref_index].elem.map(|node| node.into()),
1574 XmlParserErrors::XmlXIncludeInvalidChar,
1575 "{} contains invalid char\n",
1576 url
1577 );
1578 xml_free_node(node);
1580 return ret;
1581 }
1582 }
1583
1584 self.txt_tab.push(XmlXIncludeTxt {
1585 text: node.content.as_deref().unwrap().into(),
1586 url: url.into_boxed_str(),
1587 });
1588
1589 self.inc_tab[ref_index].inc = Some(node);
1592 0
1593 }
1594 }
1595
1596 #[doc(alias = "xmlXIncludeLoadFallback")]
1600 unsafe fn load_fallback(&mut self, fallback: XmlNodePtr, ref_index: usize) -> i32 {
1601 unsafe {
1602 let mut ret: i32 = 0;
1603
1604 if fallback.element_type() == XmlElementType::XmlNamespaceDecl {
1605 return -1;
1606 }
1607 if fallback.children().is_some() {
1608 let old_nb_errors = self.nb_errors;
1611 self.inc_tab[ref_index].inc = self.copy_node(fallback, 1);
1612 if self.nb_errors > old_nb_errors {
1613 ret = -1;
1614 } else if self.inc_tab[ref_index].inc.is_none() {
1615 self.inc_tab[ref_index].empty_fb = 1;
1616 }
1617 } else {
1618 self.inc_tab[ref_index].inc = None;
1619 self.inc_tab[ref_index].empty_fb = 1; }
1621 self.inc_tab[ref_index].fallback = 1;
1622 ret
1623 }
1624 }
1625
1626 #[doc(alias = "xmlXIncludeLoadNode")]
1630 unsafe fn load_node(&mut self, ref_index: usize) -> i32 {
1631 unsafe {
1632 let mut xml: i32 = 1; let mut ret: i32;
1634
1635 if ref_index == usize::MAX {
1636 return -1;
1637 }
1638 let Some(cur) = self.inc_tab[ref_index].elem else {
1639 return -1;
1640 };
1641
1642 let href = self.get_prop(cur, XINCLUDE_HREF).unwrap_or("".to_owned());
1644 let parse = self.get_prop(cur, XINCLUDE_PARSE);
1645 if let Some(parse) = parse {
1646 if parse == XINCLUDE_PARSE_XML {
1647 xml = 1;
1648 } else if parse == XINCLUDE_PARSE_TEXT {
1649 xml = 0;
1650 } else {
1651 xml_xinclude_err!(
1652 self,
1653 Some(cur.into()),
1654 XmlParserErrors::XmlXIncludeParseValue,
1655 "invalid value {} for 'parse'\n",
1656 parse
1657 );
1658 return -1;
1659 }
1660 }
1661
1662 let mut base = None;
1664 let mut uri = if let Some(b) = cur.get_base(Some(self.doc)) {
1665 base = Some(b);
1666 build_uri(&href, base.as_deref().unwrap())
1667 } else {
1668 self.doc
1669 .url
1670 .as_deref()
1671 .and_then(|base| build_uri(&href, base))
1672 };
1673 if uri.is_none() {
1674 if let Some(base) = base.as_deref() {
1675 if let (Some(escbase), Some(eschref)) = (escape_url(base), escape_url(&href)) {
1677 uri = build_uri(&eschref, &escbase);
1678 }
1679 }
1680 }
1681 let Some(uri) = uri else {
1682 xml_xinclude_err!(
1683 self,
1684 Some(cur.into()),
1685 XmlParserErrors::XmlXIncludeHrefURI,
1686 "failed build URL\n"
1687 );
1688 return -1;
1689 };
1690
1691 let old_base = self.base.take();
1693 self.base = base.map(|base| base.into());
1694
1695 if xml != 0 {
1696 ret = self.load_doc(&uri, ref_index);
1697 } else {
1699 ret = self.load_txt(&uri, ref_index);
1700 }
1701
1702 self.base = old_base;
1704
1705 if ret < 0 {
1706 let mut children = cur.children.map(|c| XmlNodePtr::try_from(c).unwrap());
1708 while let Some(cur_node) = children {
1709 if cur_node.element_type() == XmlElementType::XmlElementNode
1710 && cur_node.name().as_deref() == Some(XINCLUDE_FALLBACK)
1711 && cur_node.ns.is_some_and(|ns| {
1712 ns.href().as_deref() == Some(XINCLUDE_NS)
1713 || ns.href().as_deref() == Some(XINCLUDE_OLD_NS)
1714 })
1715 {
1716 ret = self.load_fallback(cur_node, ref_index);
1717 break;
1718 }
1719 children = cur_node
1720 .next
1721 .map(|node| XmlNodePtr::try_from(node).unwrap());
1722 }
1723 }
1724 if ret < 0 {
1725 xml_xinclude_err!(
1726 self,
1727 Some(cur.into()),
1728 XmlParserErrors::XmlXIncludeNoFallback,
1729 "could not load {}, and no fallback was found\n",
1730 uri
1731 );
1732 }
1733
1734 0
1735 }
1736 }
1737
1738 #[doc(alias = "xmlXIncludeParseFile")]
1740 unsafe fn parse_file(&mut self, mut url: &str) -> Option<XmlDocPtr> {
1741 unsafe {
1742 xml_init_parser();
1743
1744 let Some(mut pctxt) = XmlParserCtxt::new() else {
1745 xml_xinclude_err_memory(Some(self), None, Some("cannot allocate parser context"));
1746 return None;
1747 };
1748
1749 pctxt._private = self._private;
1751
1752 pctxt.use_options(self.parse_flags | XmlParserOption::XmlParseDTDLoad as i32);
1753
1754 if url == "-" {
1756 url = "./-";
1757 }
1758
1759 let input_stream = xml_load_external_entity(Some(url), None, &mut pctxt)?;
1760 pctxt.input_push(input_stream);
1761
1762 if pctxt.directory.is_none() {
1763 if let Some(dir) = xml_parser_get_directory(url) {
1764 pctxt.directory = Some(dir.to_string_lossy().into_owned());
1765 }
1766 }
1767
1768 pctxt.loadsubset |= XML_DETECT_IDS as i32;
1769 pctxt.parse_document();
1770
1771 if pctxt.well_formed {
1772 pctxt.my_doc
1773 } else {
1774 if let Some(my_doc) = pctxt.my_doc.take() {
1775 xml_free_doc(my_doc);
1776 }
1777 None
1778 }
1779 }
1780 }
1781
1782 #[doc(alias = "xmlXIncludeDoProcess")]
1787 unsafe fn do_process(&mut self, tree: XmlNodePtr) -> i32 {
1788 unsafe {
1789 let mut ret: i32 = 0;
1790
1791 if tree.element_type() == XmlElementType::XmlNamespaceDecl {
1792 return -1;
1793 }
1794
1795 let start = self.inc_tab.len();
1797 let mut cur = tree;
1798 'main: while {
1799 'inner: {
1800 if self.test_node(cur) == 1 {
1802 let ref_index = self.expand_node(cur);
1803 if ref_index != usize::MAX {
1805 self.inc_tab[ref_index].replace = 1;
1806 }
1807 } else if let Some(children) = cur
1808 .children()
1809 .filter(|_| {
1810 matches!(
1811 cur.element_type(),
1812 XmlElementType::XmlDocumentNode | XmlElementType::XmlElementNode
1813 )
1814 })
1815 .map(|children| XmlNodePtr::try_from(children).unwrap())
1816 {
1817 cur = children;
1818 break 'inner;
1819 }
1820 'b: loop {
1821 if cur == tree {
1822 break 'main;
1823 }
1824 if let Some(next) = cur.next.map(|node| XmlNodePtr::try_from(node).unwrap())
1825 {
1826 cur = next;
1827 break 'b;
1828 }
1829 let Some(next) = cur.parent.map(|p| XmlNodePtr::try_from(p).unwrap())
1830 else {
1831 break 'main;
1832 };
1833
1834 cur = next;
1835 }
1836 }
1837
1838 cur != tree
1839 } {}
1840
1841 let len = self.inc_tab.len();
1843 for i in start..len {
1844 if self.inc_tab[i].replace != 0 {
1845 if self.inc_tab[i].inc.is_some() || self.inc_tab[i].empty_fb != 0 {
1846 self.include_node(i);
1848 }
1849 self.inc_tab[i].replace = 0;
1850 } else {
1851 if let Some(inc) = self.inc_tab[i].inc.take() {
1854 xml_free_node_list(Some(inc));
1855 }
1856 }
1857 ret += 1;
1858 }
1859
1860 if self.is_stream != 0 {
1861 self.inc_tab.clear();
1865 }
1866
1867 ret
1868 }
1869 }
1870
1871 #[doc(alias = "xmlXIncludeProcessNode")]
1877 pub unsafe fn process_node(&mut self, node: XmlNodePtr) -> i32 {
1878 unsafe {
1879 if node.element_type() == XmlElementType::XmlNamespaceDecl || node.doc.is_none() {
1880 return -1;
1881 }
1882 let mut ret = self.do_process(node);
1883 if ret >= 0 && self.nb_errors > 0 {
1884 ret = -1;
1885 }
1886 ret
1887 }
1888 }
1889}
1890
1891impl Drop for XmlXIncludeCtxt {
1892 #[doc(alias = "xmlXIncludeFreeContext")]
1894 fn drop(&mut self) {
1895 for inc_doc in self.url_tab.drain(..) {
1896 if let Some(doc) = inc_doc.doc {
1897 unsafe {
1898 xml_free_doc(doc);
1899 }
1900 }
1901 }
1902 }
1903}
1904
1905#[doc(alias = "xmlXIncludeProcess")]
1910pub unsafe fn xml_xinclude_process(doc: XmlDocPtr) -> i32 {
1911 unsafe { xml_xinclude_process_flags(doc, 0) }
1912}
1913
1914#[doc(alias = "xmlXIncludeProcessFlags")]
1919pub unsafe fn xml_xinclude_process_flags(doc: XmlDocPtr, flags: i32) -> i32 {
1920 unsafe { xml_xinclude_process_flags_data(doc, flags, null_mut()) }
1921}
1922
1923#[doc(alias = "xmlXIncludeProcessFlagsData")]
1928pub unsafe fn xml_xinclude_process_flags_data(
1929 doc: XmlDocPtr,
1930 flags: i32,
1931 data: *mut c_void,
1932) -> i32 {
1933 unsafe {
1934 let Some(tree) = doc.get_root_element() else {
1935 return -1;
1936 };
1937 xml_xinclude_process_tree_flags_data(tree, flags, data)
1938 }
1939}
1940
1941const XINCLUDE_MAX_DEPTH: i32 = 40;
1942
1943#[doc(alias = "xmlXIncludeErrMemory")]
1945unsafe fn xml_xinclude_err_memory(
1946 ctxt: Option<&mut XmlXIncludeCtxt>,
1947 node: Option<XmlGenericNodePtr>,
1948 extra: Option<&str>,
1949) {
1950 let mut ptr = null_mut();
1951 if let Some(ctxt) = ctxt {
1952 ctxt.nb_errors += 1;
1953 ptr = ctxt as *mut XmlXIncludeCtxt;
1954 }
1955 if let Some(extra) = extra {
1956 __xml_raise_error!(
1957 None,
1958 None,
1959 None,
1960 ptr as _,
1961 node,
1962 XmlErrorDomain::XmlFromXInclude,
1963 XmlParserErrors::XmlErrNoMemory,
1964 XmlErrorLevel::XmlErrError,
1965 None,
1966 0,
1967 Some(extra.to_owned().into()),
1968 None,
1969 None,
1970 0,
1971 0,
1972 "Memory allocation failed : {}\n",
1973 extra
1974 );
1975 } else {
1976 __xml_raise_error!(
1977 None,
1978 None,
1979 None,
1980 ptr as _,
1981 node,
1982 XmlErrorDomain::XmlFromXInclude,
1983 XmlParserErrors::XmlErrNoMemory,
1984 XmlErrorLevel::XmlErrError,
1985 None,
1986 0,
1987 None,
1988 None,
1989 None,
1990 0,
1991 0,
1992 "Memory allocation failed\n",
1993 );
1994 }
1995}
1996
1997#[doc(alias = "xmlXIncludeGetNthChild")]
1999#[cfg(feature = "libxml_xptr_locs")]
2000fn xml_xinclude_get_nth_child(cur: XmlGenericNodePtr, no: i32) -> Option<XmlGenericNodePtr> {
2001 if cur.element_type() == XmlElementType::XmlNamespaceDecl {
2002 return None;
2003 }
2004 let mut cur = cur.children();
2005 let mut i = 0;
2006 while i <= no {
2007 let now = cur?;
2008 if matches!(
2009 now.element_type(),
2010 XmlElementType::XmlElementNode
2011 | XmlElementType::XmlDocumentNode
2012 | XmlElementType::XmlHTMLDocumentNode
2013 ) {
2014 i += 1;
2015 if i == no {
2016 break;
2017 }
2018 }
2019
2020 cur = now.next();
2021 }
2022 cur
2023}
2024
2025#[doc(alias = "xmlXIncludeProcessTreeFlagsData")]
2030pub unsafe fn xml_xinclude_process_tree_flags_data(
2031 tree: XmlNodePtr,
2032 flags: i32,
2033 data: *mut c_void,
2034) -> i32 {
2035 unsafe {
2036 if tree.element_type() == XmlElementType::XmlNamespaceDecl {
2037 return -1;
2038 }
2039 let Some(doc) = tree.doc else {
2040 return -1;
2041 };
2042
2043 let mut ctxt = XmlXIncludeCtxt::new(doc);
2044 ctxt._private = data;
2045 ctxt.base = doc.url.as_deref().map(|url| url.into());
2046 ctxt.set_flags(flags);
2047 let mut ret = ctxt.do_process(tree);
2048 if ret >= 0 && ctxt.nb_errors > 0 {
2049 ret = -1;
2050 }
2051
2052 ret
2053 }
2054}
2055
2056#[doc(alias = "xmlXIncludeProcessTree")]
2061pub unsafe fn xml_xinclude_process_tree(tree: XmlNodePtr) -> i32 {
2062 unsafe { xml_xinclude_process_tree_flags(tree, 0) }
2063}
2064
2065#[doc(alias = "xmlXIncludeProcessTreeFlags")]
2070pub unsafe fn xml_xinclude_process_tree_flags(tree: XmlNodePtr, flags: i32) -> i32 {
2071 unsafe {
2072 if tree.element_type() == XmlElementType::XmlNamespaceDecl {
2073 return -1;
2074 }
2075 let Some(doc) = tree.doc else {
2076 return -1;
2077 };
2078 let mut ctxt = XmlXIncludeCtxt::new(doc);
2079 ctxt.base = tree.get_base(Some(doc)).map(|base| base.into());
2080 ctxt.set_flags(flags);
2081 let mut ret = ctxt.do_process(tree);
2082 if ret >= 0 && ctxt.nb_errors > 0 {
2083 ret = -1;
2084 }
2085
2086 ret
2087 }
2088}