1#![allow(
24 missing_docs,
25 non_snake_case,
26 non_camel_case_types,
27 non_upper_case_globals
28)]
29
30use core::ffi::c_void;
31use core::ptr;
32use std::os::raw::{c_char, c_int, c_long, c_uint};
33
34use crate::abi::allocator::xmlFreeImpl;
35use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
36use crate::abi::structs::{_xmlAttr, _xmlDoc, _xmlNode, _xmlParserCtxt, _xmlParserInputBuffer};
37
38use crate::abi::types::xmlElementType::*;
39use crate::abi::types::*;
40use crate::xml::parser::helpers::{
41 create_parser_ctxt, free_parser_ctxt, input_from_file, input_from_io, input_from_memory,
42 input_from_memory_named, parse_document, setup_parser_input,
43};
44use crate::xml::parser::input::InputBuffer;
45use crate::xml::string::{bytes_to_xmlstr, xml_strdup, xmlstr_to_bytes, xmlstr_to_string};
46use crate::xml::tree;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79#[repr(i32)]
80pub(crate) enum ReaderNodeType {
81 NONE = 0,
82 ELEMENT = 1,
83 ATTRIBUTE = 2,
84 TEXT = 3,
85 CDATA = 4,
86 ENTITY_REFERENCE = 5,
87 ENTITY = 6,
88 PROCESSING_INSTRUCTION = 7,
89 COMMENT = 8,
90 DOCUMENT = 9,
91 DOCUMENT_TYPE = 10,
92 DOCUMENT_FRAGMENT = 11,
93 NOTATION = 12,
94 WHITESPACE = 13,
95 SIGNIFICANT_WHITESPACE = 14,
96 END_ELEMENT = 15,
97 END_ENTITY = 16,
98 XML_DECLARATION = 17,
99 NAMESPACE = 18,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[repr(i32)]
118pub(crate) enum ReadState {
119 NOT_INITIALIZED = 0,
120 INITIALIZED = 1,
121 READING = 2,
122 EOF = 3,
123 CLOSED = 4,
124 ERROR = 5,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140#[repr(i32)]
141pub(crate) enum ParserProp {
142 LOADDTD = 1,
143 DEFAULTATTRS = 2,
144 VALIDATE = 3,
145 SUBST_ENTITIES = 4,
146}
147
148#[derive(Debug, Clone)]
154struct TraversalEvent {
155 node: *mut _xmlNode,
157 is_end: bool,
159 depth: i32,
161}
162
163unsafe fn compute_depth(node: *mut _xmlNode) -> i32 {
171 if node.is_null() {
172 return 0;
173 }
174 let mut depth: i32 = 0;
175 let mut cur = unsafe { (*node).parent };
177 while !cur.is_null() {
178 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
180 depth += 1;
181 }
182 cur = unsafe { (*cur).parent };
184 }
185 depth
186}
187
188fn element_type_to_reader_type(etype: c_int) -> ReaderNodeType {
190 match etype {
191 x if x == XML_ELEMENT_NODE as c_int => ReaderNodeType::ELEMENT,
192 x if x == XML_ATTRIBUTE_NODE as c_int => ReaderNodeType::ATTRIBUTE,
193 x if x == XML_TEXT_NODE as c_int => ReaderNodeType::TEXT,
194 x if x == XML_CDATA_SECTION_NODE as c_int => ReaderNodeType::CDATA,
195 x if x == XML_ENTITY_REF_NODE as c_int => ReaderNodeType::ENTITY_REFERENCE,
196 x if x == XML_ENTITY_NODE as c_int => ReaderNodeType::ENTITY,
197 x if x == XML_PI_NODE as c_int => ReaderNodeType::PROCESSING_INSTRUCTION,
198 x if x == XML_COMMENT_NODE as c_int => ReaderNodeType::COMMENT,
199 x if x == XML_DOCUMENT_NODE as c_int => ReaderNodeType::DOCUMENT,
200 x if x == XML_DOCUMENT_TYPE_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
201 x if x == XML_DOCUMENT_FRAG_NODE as c_int => ReaderNodeType::DOCUMENT_FRAGMENT,
202 x if x == XML_NOTATION_NODE as c_int => ReaderNodeType::NOTATION,
203 x if x == XML_DTD_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
204 x if x == XML_NAMESPACE_DECL as c_int => ReaderNodeType::NONE,
205 _ => ReaderNodeType::NONE,
206 }
207}
208
209fn is_whitespace_only(text: &[u8]) -> bool {
211 text.iter()
212 .all(|&b| b == b' ' || b == b'\t' || b == b'\n' || b == b'\r')
213}
214
215#[derive(Clone, Copy)]
226enum AttrTarget {
227 None,
228 Ns(*mut crate::abi::structs::_xmlNs),
229 Prop(*mut _xmlAttr),
230}
231
232pub(crate) struct XmlTextReader {
233 doc: *mut _xmlDoc,
235 ctxt: *mut _xmlParserCtxt,
237 events: Vec<TraversalEvent>,
239 event_index: usize,
241 state: ReadState,
243 cur_node: *mut _xmlNode,
245 node_type: ReaderNodeType,
247 depth: i32,
249 name: *mut xmlChar,
251 value: *mut xmlChar,
253 attribute_count: i32,
255 cur_attribute: i32,
257 options: c_int,
259 encoding: *mut xmlChar,
261 URL: *mut xmlChar,
263 errors: Vec<String>,
265 parsed: bool,
267 error_handler: Option<xmlTextReaderErrorFunc>,
269 error_arg: *mut c_void,
271 structured_handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
273 structured_arg: *mut c_void,
275 last_err: crate::abi::structs::_xmlError,
277 max_amplification: c_int,
279 schema: *mut c_void,
281 rng: *mut c_void,
283 owns_doc: bool,
285 cur_attr_is_ns: bool,
288}
289
290impl XmlTextReader {
291 unsafe fn new(ctxt: *mut _xmlParserCtxt, URL: Option<&[u8]>, encoding: Option<&[u8]>) -> Self {
301 let url_ptr = URL
302 .map(|u| unsafe { bytes_to_xmlstr(u) })
303 .unwrap_or(ptr::null_mut());
304 let enc_ptr = encoding
305 .map(|e| unsafe { bytes_to_xmlstr(e) })
306 .unwrap_or(ptr::null_mut());
307
308 XmlTextReader {
309 doc: ptr::null_mut(),
310 ctxt,
311 events: Vec::new(),
312 event_index: 0,
313 state: ReadState::INITIALIZED,
314 cur_node: ptr::null_mut(),
315 node_type: ReaderNodeType::NONE,
316 depth: 0,
317 name: ptr::null_mut(),
318 value: ptr::null_mut(),
319 attribute_count: -1,
320 cur_attribute: -1,
321 options: 0,
322 encoding: enc_ptr,
323 URL: url_ptr,
324 errors: Vec::new(),
325 parsed: false,
326 error_handler: None,
327 error_arg: ptr::null_mut(),
328 structured_handler: None,
329 structured_arg: ptr::null_mut(),
330 last_err: unsafe { core::mem::zeroed() },
331 max_amplification: 0,
332 schema: ptr::null_mut(),
333 rng: ptr::null_mut(),
334 owns_doc: true,
335 cur_attr_is_ns: false,
336 }
337 }
338
339 unsafe fn parse_and_build_events(&mut self) -> c_int {
347 if self.ctxt.is_null() {
348 self.state = ReadState::ERROR;
349 self.errors.push("No parser context".to_string());
350 return -1;
351 }
352
353 unsafe {
355 (*self.ctxt).options = self.options;
356 }
357
358 let result = unsafe { parse_document(self.ctxt) };
360
361 let doc = unsafe { (*self.ctxt).myDoc };
363 self.doc = doc;
364
365 if !self.ctxt.is_null() {
367 unsafe { free_parser_ctxt(self.ctxt) };
368 }
369 self.ctxt = ptr::null_mut();
370
371 if result != 0 || doc.is_null() {
372 self.state = ReadState::ERROR;
373 self.errors.push("Failed to parse document".to_string());
374 return -1;
375 }
376
377 if self.encoding.is_null() && !doc.is_null() {
379 let doc_enc = unsafe { (*doc).encoding };
381 if !doc_enc.is_null() {
382 self.encoding = unsafe { xml_strdup(doc_enc as *const xmlChar) };
383 }
384 }
385
386 self.build_events();
388
389 self.parsed = true;
390 0
391 }
392
393 fn build_events(&mut self) {
398 self.events.clear();
399
400 if self.doc.is_null() {
401 return;
402 }
403
404 let root = unsafe { (*self.doc).children };
406 if root.is_null() {
407 return;
408 }
409
410 unsafe {
413 let mut n = root;
414 while !n.is_null() {
415 self.walk_tree(n, 0);
416 n = (*n).next;
417 }
418 }
419 }
420
421 unsafe fn walk_tree(&mut self, node: *mut _xmlNode, depth: i32) {
427 if node.is_null() {
428 return;
429 }
430
431 let node_type = unsafe { (*node).type_ };
433
434 if node_type == XML_ELEMENT_NODE as c_int {
438 self.events.push(TraversalEvent {
439 node,
440 is_end: false,
441 depth,
442 });
443
444 let mut child = unsafe { (*node).children };
447 while !child.is_null() {
448 let child_depth = depth + 1;
449 self.walk_tree(child, child_depth);
450 child = unsafe { (*child).next };
452 }
453
454 if !unsafe { (*node).children }.is_null() {
457 self.events.push(TraversalEvent {
458 node,
459 is_end: true,
460 depth,
461 });
462 }
463 } else if node_type == XML_TEXT_NODE as c_int
464 || node_type == XML_CDATA_SECTION_NODE as c_int
465 || node_type == XML_COMMENT_NODE as c_int
466 || node_type == XML_PI_NODE as c_int
467 || node_type == XML_ENTITY_REF_NODE as c_int
468 {
469 self.events.push(TraversalEvent {
474 node,
475 is_end: false,
476 depth,
477 });
478 } else {
479 self.events.push(TraversalEvent {
481 node,
482 is_end: false,
483 depth,
484 });
485 }
486 }
487
488 fn position_at(&mut self, index: usize) {
492 if index >= self.events.len() {
493 self.state = ReadState::EOF;
494 self.cur_node = ptr::null_mut();
495 self.node_type = ReaderNodeType::NONE;
496 self.depth = 0;
497 self.clear_cached_name();
498 self.clear_cached_value();
499 self.attribute_count = -1;
500 self.cur_attribute = -1;
501 return;
502 }
503
504 let ev_node: *mut _xmlNode;
506 let ev_is_end: bool;
507 let ev_depth: i32;
508 {
509 let event = &self.events[index];
510 ev_node = event.node;
511 ev_is_end = event.is_end;
512 ev_depth = event.depth;
513 }
514
515 self.event_index = index;
516 self.cur_node = ev_node;
517 self.depth = ev_depth;
518
519 let etype = unsafe { (*ev_node).type_ };
521
522 if ev_is_end {
523 self.node_type = ReaderNodeType::END_ELEMENT;
524 } else {
525 self.node_type = element_type_to_reader_type(etype);
526 if etype == XML_TEXT_NODE as c_int || etype == XML_CDATA_SECTION_NODE as c_int {
529 let content = unsafe { (*ev_node).content };
530 if !content.is_null() {
531 let len = unsafe { libc::strlen(content as *const libc::c_char) as usize };
533 let slice = unsafe { core::slice::from_raw_parts(content, len) };
535 if is_whitespace_only(slice) {
536 self.node_type = ReaderNodeType::SIGNIFICANT_WHITESPACE;
537 }
538 }
539 }
540 }
541
542 unsafe { self.cache_name_and_value(ev_node, ev_is_end) };
545
546 if etype == XML_ELEMENT_NODE as c_int && !ev_is_end {
548 self.attribute_count = unsafe { self.count_attributes(ev_node) };
550 } else {
551 self.attribute_count = -1;
552 }
553
554 self.cur_attribute = -1;
556 self.cur_attr_is_ns = false;
557 }
558
559 unsafe fn cache_name_and_value(&mut self, node: *mut _xmlNode, is_end: bool) {
565 self.clear_cached_name();
566 self.clear_cached_value();
567
568 if node.is_null() {
569 return;
570 }
571
572 let etype = unsafe { (*node).type_ };
574
575 let name: *mut xmlChar = if is_end {
577 unsafe { (*node).name as *mut xmlChar }
580 } else {
581 if etype == XML_ELEMENT_NODE as c_int
582 || etype == XML_PI_NODE as c_int
583 || etype == XML_ENTITY_REF_NODE as c_int
584 || etype == XML_ENTITY_NODE as c_int
585 || etype == XML_DOCUMENT_TYPE_NODE as c_int
586 || etype == XML_NOTATION_NODE as c_int
587 {
588 unsafe { (*node).name as *mut xmlChar }
590 } else if etype == XML_ATTRIBUTE_NODE as c_int {
591 ptr::null_mut()
593 } else {
594 ptr::null_mut()
595 }
596 };
597
598 if !name.is_null() {
599 let qualified: *mut xmlChar = if etype == XML_ELEMENT_NODE as c_int && !node.is_null() {
603 let ns = unsafe { (*node).ns };
604 if !ns.is_null() && !unsafe { (*ns).prefix }.is_null() {
605 let plen =
606 libc::strlen(unsafe { (*ns).prefix } as *const libc::c_char) as usize;
607 let nlen = libc::strlen(name as *const libc::c_char) as usize;
608 let p =
609 crate::abi::allocator::xmlMallocImpl(plen + 1 + nlen + 1) as *mut xmlChar;
610 if !p.is_null() {
611 libc::memcpy(
612 p as *mut libc::c_void,
613 unsafe { (*ns).prefix } as *const libc::c_void,
614 plen,
615 );
616 *p.add(plen) = b':';
617 libc::memcpy(
618 p.add(plen + 1) as *mut libc::c_void,
619 name as *const libc::c_void,
620 nlen,
621 );
622 *p.add(plen + 1 + nlen) = 0;
623 }
624 p
625 } else {
626 unsafe { xml_strdup(name as *const xmlChar) }
627 }
628 } else {
629 unsafe { xml_strdup(name as *const xmlChar) }
630 };
631 self.name = qualified;
632 } else if !is_end {
633 let fixed: &[u8] = match etype {
636 x if x == XML_TEXT_NODE as c_int => b"#text\0",
637 x if x == XML_CDATA_SECTION_NODE as c_int => b"#cdata-section\0",
638 x if x == XML_COMMENT_NODE as c_int => b"#comment\0",
639 x if x == XML_DOCUMENT_NODE as c_int => b"#document\0",
640 x if x == XML_HTML_DOCUMENT_NODE as c_int => b"#document\0",
641 x if x == XML_DOCUMENT_FRAG_NODE as c_int => b"#document-fragment\0",
642 _ => b"",
643 };
644 if !fixed.is_empty() {
645 self.name = unsafe { xml_strdup(fixed.as_ptr() as *const xmlChar) };
646 }
647 }
648
649 let value: *mut xmlChar = if etype == XML_TEXT_NODE as c_int
651 || etype == XML_CDATA_SECTION_NODE as c_int
652 || etype == XML_COMMENT_NODE as c_int
653 {
654 unsafe { (*node).content }
656 } else if etype == XML_PI_NODE as c_int {
657 unsafe { (*node).content }
660 } else if etype == XML_ENTITY_REF_NODE as c_int {
661 unsafe { (*node).content }
664 } else {
665 ptr::null_mut()
666 };
667
668 if !value.is_null() {
669 self.value = unsafe { xml_strdup(value as *const xmlChar) };
671 }
672 }
673
674 unsafe fn count_attributes(&self, node: *mut _xmlNode) -> i32 {
680 let mut count: i32 = 0;
681 let mut ns = unsafe { (*node).nsDef };
684 while !ns.is_null() {
685 count += 1;
686 ns = unsafe { (*ns).next };
687 }
688 let mut prop = unsafe { (*node).properties };
690 while !prop.is_null() {
691 count += 1;
692 prop = unsafe { (*prop).next };
694 }
695 count
696 }
697
698 unsafe fn attr_at(&self, node: *mut _xmlNode, index: i32) -> AttrTarget {
701 if node.is_null() || index < 0 {
702 return AttrTarget::None;
703 }
704 let mut i = 0;
705 let mut ns = unsafe { (*node).nsDef };
706 while !ns.is_null() {
707 if i == index {
708 return AttrTarget::Ns(ns);
709 }
710 i += 1;
711 ns = unsafe { (*ns).next };
712 }
713 let mut prop = unsafe { (*node).properties };
714 while !prop.is_null() {
715 if i == index {
716 return AttrTarget::Prop(prop);
717 }
718 i += 1;
719 prop = unsafe { (*prop).next };
720 }
721 AttrTarget::None
722 }
723
724 unsafe fn attr_index_by_name(&self, node: *mut _xmlNode, name: *const xmlChar) -> i32 {
727 if node.is_null() || name.is_null() {
728 return -1;
729 }
730 let mut i = 0;
731 let mut ns = unsafe { (*node).nsDef };
732 while !ns.is_null() {
733 let n = unsafe { &*ns };
734 let nsname: Vec<u8> = if n.prefix.is_null() {
735 b"xmlns\0".to_vec()
736 } else {
737 let mut v = b"xmlns:\0".to_vec();
738 let plen = libc::strlen(n.prefix as *const libc::c_char) as usize;
739 v.extend_from_slice(core::slice::from_raw_parts(n.prefix, plen));
740 v.push(0);
741 v
742 };
743 let nlen = libc::strlen(name as *const libc::c_char) as usize;
744 let nbytes = core::slice::from_raw_parts(name as *const u8, nlen);
745 if nbytes == &nsname[..nsname.len() - 1] {
746 return i;
747 }
748 i += 1;
749 ns = unsafe { (*ns).next };
750 }
751 let mut prop = unsafe { (*node).properties };
752 while !prop.is_null() {
753 let pn = unsafe { (*prop).name };
754 if !pn.is_null()
755 && libc::strcmp(pn as *const libc::c_char, name as *const libc::c_char) == 0
756 {
757 return i;
758 }
759 i += 1;
760 prop = unsafe { (*prop).next };
761 }
762 -1
763 }
764
765 fn clear_cached_name(&mut self) {
767 if !self.name.is_null() {
768 unsafe { xmlFreeImpl(self.name as *mut c_void) };
770 self.name = ptr::null_mut();
771 }
772 }
773
774 fn clear_cached_value(&mut self) {
776 if !self.value.is_null() {
777 unsafe { xmlFreeImpl(self.value as *mut c_void) };
779 self.value = ptr::null_mut();
780 }
781 }
782
783 pub unsafe fn Read(&mut self) -> c_int {
791 if self.state == ReadState::ERROR || self.state == ReadState::CLOSED {
792 return -1;
793 }
794
795 if !self.parsed {
797 if self.parse_and_build_events() != 0 {
798 self.state = ReadState::ERROR;
799 return -1;
800 }
801 self.state = ReadState::READING;
802 }
803
804 if self.state == ReadState::EOF {
805 return 0;
806 }
807
808 if self.cur_attribute >= 0 {
810 self.cur_attribute = -1;
811 self.cur_attr_is_ns = false;
812 if !self.cur_node.is_null() {
814 unsafe { self.cache_name_and_value(self.cur_node, false) };
816 }
817 }
818
819 if self.events.is_empty() {
822 self.state = ReadState::EOF;
823 return 0;
824 }
825
826 let next_index = if self.cur_node.is_null() {
833 0
835 } else {
836 self.event_index + 1
837 };
838
839 if next_index < self.events.len() {
840 self.position_at(next_index);
841 1
842 } else {
843 self.state = ReadState::EOF;
844 self.cur_node = ptr::null_mut();
845 self.node_type = ReaderNodeType::NONE;
846 self.depth = 0;
847 self.clear_cached_name();
848 self.clear_cached_value();
849 self.attribute_count = -1;
850 self.cur_attribute = -1;
851 0
852 }
853 }
854
855 pub unsafe fn Next(&mut self) -> c_int {
859 if self.state != ReadState::READING || self.cur_node.is_null() {
860 return -1;
861 }
862
863 let current_depth = self.depth;
869 let mut i = self.event_index + 1;
870
871 while i < self.events.len() {
872 let event = &self.events[i];
873 if event.depth <= current_depth && !event.is_end {
874 self.position_at(i);
875 return 1;
876 }
877 i += 1;
878 }
879
880 0
881 }
882
883 pub unsafe fn MoveToElement(&mut self) -> c_int {
887 if self.cur_attribute < 0 {
888 return 0;
889 }
890 self.cur_attribute = -1;
891 self.cur_attr_is_ns = false;
892 if !self.cur_node.is_null() {
893 unsafe { self.cache_name_and_value(self.cur_node, false) };
895 self.node_type = ReaderNodeType::ELEMENT;
896 }
897 1
898 }
899
900 pub unsafe fn MoveToAttribute(&mut self, name: *const xmlChar) -> c_int {
904 if self.cur_node.is_null() {
905 return -1;
906 }
907
908 let etype = unsafe { (*self.cur_node).type_ };
910 if etype != XML_ELEMENT_NODE as c_int {
911 return -1;
912 }
913
914 let idx = unsafe { self.attr_index_by_name(self.cur_node, name) };
916 if idx < 0 {
917 return 0;
918 }
919 self.cur_attribute = idx;
920 let target = unsafe { self.attr_at(self.cur_node, idx) };
921 unsafe { self.cache_attribute_info(target) };
923 1
924 }
925
926 pub unsafe fn MoveToAttributeNo(&mut self, index: c_int) -> c_int {
930 if self.cur_node.is_null() || index < 0 {
931 return -1;
932 }
933
934 let etype = unsafe { (*self.cur_node).type_ };
936 if etype != XML_ELEMENT_NODE as c_int {
937 return -1;
938 }
939
940 let target = unsafe { self.attr_at(self.cur_node, index) };
942 match target {
943 AttrTarget::None => 0,
944 t => {
945 self.cur_attribute = index;
946 unsafe { self.cache_attribute_info(t) };
948 1
949 }
950 }
951 }
952
953 pub unsafe fn MoveToFirstAttribute(&mut self) -> c_int {
957 if self.cur_node.is_null() {
958 return -1;
959 }
960
961 let etype = unsafe { (*self.cur_node).type_ };
963 if etype != XML_ELEMENT_NODE as c_int {
964 return -1;
965 }
966
967 let first = unsafe { self.attr_at(self.cur_node, 0) };
969 match first {
970 AttrTarget::None => 0,
971 t => {
972 self.cur_attribute = 0;
973 unsafe { self.cache_attribute_info(t) };
975 1
976 }
977 }
978 }
979
980 pub unsafe fn MoveToNextAttribute(&mut self) -> c_int {
984 if self.cur_attribute < 0 || self.cur_node.is_null() {
985 return -1;
986 }
987
988 let etype = unsafe { (*self.cur_node).type_ };
990 if etype != XML_ELEMENT_NODE as c_int {
991 return -1;
992 }
993
994 let next_index = self.cur_attribute + 1;
996 let target = unsafe { self.attr_at(self.cur_node, next_index) };
997 match target {
998 AttrTarget::None => 0,
999 t => {
1000 self.cur_attribute = next_index;
1001 unsafe { self.cache_attribute_info(t) };
1002 1
1003 }
1004 }
1005 }
1006
1007 unsafe fn cache_attribute_info(&mut self, target: AttrTarget) {
1015 self.node_type = ReaderNodeType::ATTRIBUTE;
1016 self.cur_attr_is_ns = matches!(target, AttrTarget::Ns(_));
1017 self.clear_cached_name();
1018 self.clear_cached_value();
1019 match target {
1020 AttrTarget::Ns(ns) => {
1021 let n = unsafe { &*ns };
1025 if n.prefix.is_null() {
1026 self.name = unsafe { xml_strdup(b"xmlns\0".as_ptr() as *const xmlChar) };
1027 } else {
1028 let plen = libc::strlen(n.prefix as *const libc::c_char) as usize;
1029 let mut v = Vec::with_capacity(6 + plen);
1030 v.extend_from_slice(b"xmlns:");
1031 v.extend_from_slice(core::slice::from_raw_parts(n.prefix, plen));
1032 v.push(0);
1033 let p = crate::abi::allocator::xmlMallocImpl(v.len()) as *mut xmlChar;
1034 if !p.is_null() {
1035 libc::memcpy(
1036 p as *mut libc::c_void,
1037 v.as_ptr() as *const libc::c_void,
1038 v.len(),
1039 );
1040 self.name = p;
1041 }
1042 }
1043 if !n.href.is_null() {
1044 self.value = unsafe { xml_strdup(n.href as *const xmlChar) };
1045 }
1046 }
1047 AttrTarget::Prop(prop) => {
1048 let attr = unsafe { &*prop };
1050
1051 if !attr.name.is_null() {
1056 if !attr.ns.is_null() && !unsafe { (*attr.ns).prefix }.is_null() {
1057 let plen = libc::strlen(unsafe { (*attr.ns).prefix } as *const libc::c_char)
1058 as usize;
1059 let nlen = libc::strlen(attr.name as *const libc::c_char) as usize;
1060 let p = crate::abi::allocator::xmlMallocImpl(plen + 1 + nlen + 1)
1061 as *mut xmlChar;
1062 if !p.is_null() {
1063 libc::memcpy(
1064 p as *mut libc::c_void,
1065 unsafe { (*attr.ns).prefix } as *const libc::c_void,
1066 plen,
1067 );
1068 *p.add(plen) = b':';
1069 libc::memcpy(
1070 p.add(plen + 1) as *mut libc::c_void,
1071 attr.name as *const libc::c_void,
1072 nlen,
1073 );
1074 *p.add(plen + 1 + nlen) = 0;
1075 self.name = p;
1076 }
1077 } else {
1078 self.name = unsafe { xml_strdup(attr.name as *const xmlChar) };
1080 }
1081 }
1082
1083 if !attr.children.is_null() {
1085 let val = unsafe { (*attr.children).content };
1087 if !val.is_null() {
1088 self.value = unsafe { xml_strdup(val as *const xmlChar) };
1090 }
1091 }
1092 }
1093 AttrTarget::None => {}
1094 }
1095 }
1096
1097 pub unsafe fn Prev(&mut self) -> c_int {
1101 if self.state != ReadState::READING || self.cur_node.is_null() {
1102 return -1;
1103 }
1104
1105 let current_depth = self.depth;
1107 let mut i = if self.event_index > 0 {
1108 self.event_index - 1
1109 } else {
1110 return 0;
1111 };
1112
1113 loop {
1114 let event = &self.events[i];
1115 if event.depth == current_depth && !event.is_end {
1116 self.position_at(i);
1117 return 1;
1118 }
1119 if i == 0 {
1120 break;
1121 }
1122 i -= 1;
1123 }
1124
1125 0
1126 }
1127
1128 pub fn Depth(&self) -> c_int {
1134 self.depth
1135 }
1136
1137 pub fn NodeType(&self) -> ReaderNodeType {
1139 self.node_type
1140 }
1141
1142 pub unsafe fn Name(&self) -> *mut xmlChar {
1147 if self.name.is_null() {
1148 return ptr::null_mut();
1149 }
1150 unsafe { xml_strdup(self.name as *const xmlChar) }
1152 }
1153
1154 pub unsafe fn Value(&self) -> *mut xmlChar {
1159 if self.value.is_null() {
1160 return ptr::null_mut();
1161 }
1162 unsafe { xml_strdup(self.value as *const xmlChar) }
1164 }
1165
1166 pub fn ConstName(&self) -> *const xmlChar {
1171 self.name as *const xmlChar
1172 }
1173
1174 pub fn ConstValue(&self) -> *const xmlChar {
1179 self.value as *const xmlChar
1180 }
1181
1182 pub fn HasValue(&self) -> c_int {
1184 if self.value.is_null() {
1185 0
1186 } else {
1187 1
1188 }
1189 }
1190
1191 pub fn HasAttributes(&self) -> c_int {
1193 if self.cur_node.is_null() {
1194 return 0;
1195 }
1196 let etype = unsafe { (*self.cur_node).type_ };
1198 if etype != XML_ELEMENT_NODE as c_int {
1199 return 0;
1200 }
1201 let props = unsafe { (*self.cur_node).properties };
1204 let nsdefs = unsafe { (*self.cur_node).nsDef };
1205 if props.is_null() && nsdefs.is_null() {
1206 0
1207 } else {
1208 1
1209 }
1210 }
1211
1212 pub fn IsEmptyElement(&self) -> c_int {
1214 if self.cur_node.is_null() {
1215 return 0;
1216 }
1217 let etype = unsafe { (*self.cur_node).type_ };
1219 if etype != XML_ELEMENT_NODE as c_int {
1220 return 0;
1221 }
1222 let children = unsafe { (*self.cur_node).children };
1224 if children.is_null() {
1225 1
1226 } else {
1227 0
1228 }
1229 }
1230
1231 pub unsafe fn BaseUri(&self) -> *mut xmlChar {
1236 if self.doc.is_null() {
1238 return ptr::null_mut();
1239 }
1240 let url = unsafe { (*self.doc).URL };
1242 if url.is_null() {
1243 return ptr::null_mut();
1244 }
1245 unsafe { xml_strdup(url as *const xmlChar) }
1247 }
1248
1249 pub unsafe fn LocalName(&self) -> *mut xmlChar {
1254 if self.name.is_null() {
1255 return ptr::null_mut();
1256 }
1257
1258 let name_bytes = unsafe { xmlstr_to_bytes(self.name as *const xmlChar) };
1260
1261 if let Some(pos) = name_bytes.iter().position(|&b| b == b':') {
1263 let local = &name_bytes[pos + 1..];
1265 if local.is_empty() {
1266 return ptr::null_mut();
1267 }
1268 unsafe { bytes_to_xmlstr(local) }
1270 } else {
1271 unsafe { xml_strdup(self.name as *const xmlChar) }
1274 }
1275 }
1276
1277 pub unsafe fn NamespaceUri(&self) -> *mut xmlChar {
1281 if self.cur_node.is_null() {
1282 return ptr::null_mut();
1283 }
1284
1285 let ns = unsafe { (*self.cur_node).ns };
1287 if ns.is_null() {
1288 return ptr::null_mut();
1289 }
1290
1291 let href = unsafe { (*ns).href };
1293 if href.is_null() {
1294 return ptr::null_mut();
1295 }
1296
1297 unsafe { xml_strdup(href as *const xmlChar) }
1299 }
1300
1301 pub unsafe fn Prefix(&self) -> *mut xmlChar {
1305 if self.cur_node.is_null() {
1306 return ptr::null_mut();
1307 }
1308
1309 let ns = unsafe { (*self.cur_node).ns };
1311 if ns.is_null() {
1312 return ptr::null_mut();
1313 }
1314
1315 let prefix = unsafe { (*ns).prefix };
1317 if prefix.is_null() {
1318 return ptr::null_mut();
1319 }
1320
1321 unsafe { xml_strdup(prefix as *const xmlChar) }
1323 }
1324
1325 pub fn AttributeCount(&self) -> c_int {
1327 self.attribute_count
1328 }
1329
1330 pub fn ReadState(&self) -> ReadState {
1332 self.state
1333 }
1334
1335 pub unsafe fn GetAttribute(&self, name: *const xmlChar) -> *mut xmlChar {
1339 if self.cur_node.is_null() {
1340 return ptr::null_mut();
1341 }
1342
1343 let etype = unsafe { (*self.cur_node).type_ };
1345 if etype != XML_ELEMENT_NODE as c_int {
1346 return ptr::null_mut();
1347 }
1348
1349 let idx = unsafe { self.attr_index_by_name(self.cur_node, name) };
1351 if idx < 0 {
1352 return ptr::null_mut();
1353 }
1354 match unsafe { self.attr_at(self.cur_node, idx) } {
1355 AttrTarget::Ns(ns) => {
1356 let href = unsafe { (*ns).href };
1357 if href.is_null() {
1358 ptr::null_mut()
1359 } else {
1360 unsafe { xml_strdup(href as *const xmlChar) }
1361 }
1362 }
1363 AttrTarget::Prop(prop) => {
1364 let val = unsafe { (*prop).children };
1366 if !val.is_null() {
1367 let content = unsafe { (*val).content };
1368 if !content.is_null() {
1369 return unsafe { xml_strdup(content as *const xmlChar) };
1370 }
1371 }
1372 ptr::null_mut()
1373 }
1374 AttrTarget::None => ptr::null_mut(),
1375 }
1376 }
1377
1378 pub unsafe fn GetAttributeNo(&self, index: c_int) -> *mut xmlChar {
1382 if self.cur_node.is_null() || index < 0 {
1383 return ptr::null_mut();
1384 }
1385
1386 let etype = unsafe { (*self.cur_node).type_ };
1388 if etype != XML_ELEMENT_NODE as c_int {
1389 return ptr::null_mut();
1390 }
1391
1392 match unsafe { self.attr_at(self.cur_node, index) } {
1394 AttrTarget::Ns(ns) => {
1395 let href = unsafe { (*ns).href };
1396 if href.is_null() {
1397 ptr::null_mut()
1398 } else {
1399 unsafe { xml_strdup(href as *const xmlChar) }
1400 }
1401 }
1402 AttrTarget::Prop(prop) => {
1403 let val = unsafe { (*prop).children };
1404 if !val.is_null() {
1405 let content = unsafe { (*val).content };
1406 if !content.is_null() {
1407 return unsafe { xml_strdup(content as *const xmlChar) };
1408 }
1409 }
1410 ptr::null_mut()
1411 }
1412 AttrTarget::None => ptr::null_mut(),
1413 }
1414 }
1415
1416 pub unsafe fn GetAttributeNs(
1420 &self,
1421 localName: *const xmlChar,
1422 namespaceURI: *const xmlChar,
1423 ) -> *mut xmlChar {
1424 if self.cur_node.is_null() {
1425 return ptr::null_mut();
1426 }
1427
1428 let etype = unsafe { (*self.cur_node).type_ };
1430 if etype != XML_ELEMENT_NODE as c_int {
1431 return ptr::null_mut();
1432 }
1433
1434 let mut prop = unsafe { (*self.cur_node).properties };
1436 while !prop.is_null() {
1437 let prop_local = unsafe { (*prop).name };
1439 let prop_ns = unsafe { (*prop).ns };
1440
1441 if prop_local.is_null() {
1443 prop = unsafe { (*prop).next };
1445 continue;
1446 }
1447
1448 let name_match = unsafe {
1450 crate::xml::string::xml_strcmp(prop_local as *const xmlChar, localName) == 0
1451 };
1452
1453 if name_match {
1454 let ns_match = if namespaceURI.is_null() {
1456 prop_ns.is_null()
1457 } else if prop_ns.is_null() {
1458 false
1459 } else {
1460 unsafe {
1462 crate::xml::string::xml_strcmp(
1463 (*prop_ns).href as *const xmlChar,
1464 namespaceURI,
1465 ) == 0
1466 }
1467 };
1468
1469 if ns_match {
1470 let val = unsafe { (*prop).children };
1472 if !val.is_null() {
1473 let content = unsafe { (*val).content };
1475 if !content.is_null() {
1476 return unsafe { xml_strdup(content as *const xmlChar) };
1478 }
1479 }
1480 return ptr::null_mut();
1481 }
1482 }
1483
1484 prop = unsafe { (*prop).next };
1486 }
1487
1488 ptr::null_mut()
1489 }
1490
1491 pub unsafe fn LookupNamespace(&self, prefix: *const xmlChar) -> *mut xmlChar {
1495 if self.cur_node.is_null() {
1496 return ptr::null_mut();
1497 }
1498
1499 let mut cur = self.cur_node;
1502 while !cur.is_null() {
1503 let mut ns_def = unsafe { (*cur).nsDef };
1505 while !ns_def.is_null() {
1506 let ns_prefix = unsafe { (*ns_def).prefix };
1508
1509 let match_prefix = if prefix.is_null() || *prefix == 0 {
1510 ns_prefix.is_null()
1512 } else if ns_prefix.is_null() {
1513 false
1514 } else {
1515 unsafe {
1517 crate::xml::string::xml_strcmp(ns_prefix as *const xmlChar, prefix) == 0
1518 }
1519 };
1520
1521 if match_prefix {
1522 let href = unsafe { (*ns_def).href };
1524 if !href.is_null() {
1525 return unsafe { xml_strdup(href as *const xmlChar) };
1527 }
1528 return ptr::null_mut();
1529 }
1530
1531 ns_def = unsafe { (*ns_def).next };
1533 }
1534
1535 cur = unsafe { (*cur).parent };
1537 }
1538
1539 ptr::null_mut()
1540 }
1541
1542 pub fn GetParserProp(&self, prop: c_int) -> c_int {
1544 match prop {
1545 1 => {
1546 if (self.options & XML_PARSE_DTDLOAD) != 0 { 1 } else { 0 }
1547 }
1548 2 => {
1549 if (self.options & XML_PARSE_DTDATTR) != 0 { 1 } else { 0 }
1550 }
1551 3 => {
1552 if (self.options & XML_PARSE_DTDVALID) != 0 { 1 } else { 0 }
1553 }
1554 4 => {
1555 if (self.options & XML_PARSE_NOENT) != 0 { 1 } else { 0 }
1556 }
1557 _ => -1,
1558 }
1559 }
1560
1561 pub fn SetParserProp(&mut self, prop: c_int, value: c_int) -> c_int {
1563 match prop {
1564 1 => {
1565 if value != 0 {
1566 self.options |= XML_PARSE_DTDLOAD;
1567 } else {
1568 self.options &= !XML_PARSE_DTDLOAD;
1569 }
1570 0
1571 }
1572 2 => {
1573 if value != 0 {
1574 self.options |= XML_PARSE_DTDATTR;
1575 } else {
1576 self.options &= !XML_PARSE_DTDATTR;
1577 }
1578 0
1579 }
1580 3 => {
1581 if value != 0 {
1582 self.options |= XML_PARSE_DTDVALID;
1583 } else {
1584 self.options &= !XML_PARSE_DTDVALID;
1585 }
1586 0
1587 }
1588 4 => {
1589 if value != 0 {
1590 self.options |= XML_PARSE_NOENT;
1591 } else {
1592 self.options &= !XML_PARSE_NOENT;
1593 }
1594 0
1595 }
1596 _ => -1,
1597 }
1598 }
1599
1600 pub fn CurrentDoc(&self) -> *mut _xmlDoc {
1602 self.doc
1603 }
1604}
1605
1606impl Drop for XmlTextReader {
1607 fn drop(&mut self) {
1608 self.clear_cached_name();
1610 self.clear_cached_value();
1611
1612 if !self.last_err.message.is_null() {
1614 unsafe { libc::free(self.last_err.message as *mut libc::c_void) };
1616 self.last_err.message = ptr::null_mut();
1617 }
1618
1619 if !self.encoding.is_null() {
1621 unsafe { xmlFreeImpl(self.encoding as *mut c_void) };
1623 self.encoding = ptr::null_mut();
1624 }
1625 if !self.URL.is_null() {
1626 unsafe { xmlFreeImpl(self.URL as *mut c_void) };
1628 self.URL = ptr::null_mut();
1629 }
1630
1631 if !self.doc.is_null() && self.owns_doc {
1633 unsafe { tree::free_doc(self.doc) };
1636 self.doc = ptr::null_mut();
1637 }
1638
1639 if !self.ctxt.is_null() {
1641 unsafe { free_parser_ctxt(self.ctxt) };
1643 self.ctxt = ptr::null_mut();
1644 }
1645 }
1646}
1647
1648unsafe fn reader_from_input(
1658 input: *mut _xmlParserInputBuffer,
1659 URL: *const c_char,
1660 encoding: *const c_char,
1661 options: c_int,
1662) -> *mut XmlTextReader {
1663 if input.is_null() {
1664 return ptr::null_mut();
1665 }
1666
1667 let ctxt = create_parser_ctxt();
1669 if ctxt.is_null() {
1670 return ptr::null_mut();
1671 }
1672
1673 let mut data = Vec::new();
1675 let mut tmp = [0u8; 4096];
1676
1677 let read_cb = unsafe { (*input).readcallback };
1679 let ioctx = unsafe { (*input).context };
1680
1681 if let Some(read) = read_cb {
1682 loop {
1683 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
1685 if n <= 0 {
1686 break;
1687 }
1688 data.extend_from_slice(&tmp[..n as usize]);
1689 }
1690 }
1691
1692 let close_cb = unsafe { (*input).closecallback };
1695 if let Some(close) = close_cb {
1696 unsafe { close(ioctx) };
1698 }
1699
1700 let input_buf = InputBuffer::from_memory(&data, None);
1702
1703 setup_parser_input(ctxt, input_buf);
1705
1706 unsafe {
1708 (*ctxt).options = options;
1709 }
1710
1711 let url_bytes = if URL.is_null() {
1713 None
1714 } else {
1715 unsafe {
1717 let cstr = std::ffi::CStr::from_ptr(URL);
1718 Some(cstr.to_bytes().to_vec())
1719 }
1720 };
1721
1722 let enc_bytes = if encoding.is_null() {
1723 None
1724 } else {
1725 unsafe {
1727 let cstr = std::ffi::CStr::from_ptr(encoding);
1728 Some(cstr.to_bytes().to_vec())
1729 }
1730 };
1731
1732 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1734 reader.options = options;
1735
1736 Box::into_raw(Box::new(reader))
1738}
1739
1740#[no_mangle]
1757pub unsafe extern "C" fn xmlNewTextReader(
1758 input: *mut _xmlParserInputBuffer,
1759 URI: *const c_char,
1760) -> *mut XmlTextReader {
1761 unsafe { reader_from_input(input, URI, ptr::null(), 0) }
1763}
1764
1765#[no_mangle]
1778pub unsafe extern "C" fn xmlReaderForFile(
1779 filename: *const c_char,
1780 encoding: *const c_char,
1781 options: c_int,
1782) -> *mut XmlTextReader {
1783 if filename.is_null() {
1784 return ptr::null_mut();
1785 }
1786
1787 let ctxt = unsafe { create_parser_ctxt() };
1789 if ctxt.is_null() {
1790 return ptr::null_mut();
1791 }
1792
1793 let input = match unsafe { input_from_file(filename) } {
1795 Ok(input) => input,
1796 Err(_) => {
1797 unsafe { free_parser_ctxt(ctxt) };
1799 return ptr::null_mut();
1800 }
1801 };
1802
1803 unsafe { setup_parser_input(ctxt, input) };
1805 unsafe {
1806 (*ctxt).options = options;
1807 }
1808
1809 let enc_bytes = if encoding.is_null() {
1810 None
1811 } else {
1812 unsafe {
1814 let cstr = std::ffi::CStr::from_ptr(encoding);
1815 Some(cstr.to_bytes().to_vec())
1816 }
1817 };
1818
1819 let mut reader = XmlTextReader::new(ctxt, None, enc_bytes.as_deref());
1820 reader.options = options;
1821 Box::into_raw(Box::new(reader))
1822}
1823
1824#[no_mangle]
1838pub unsafe extern "C" fn xmlReaderForMemory(
1839 buffer: *const c_char,
1840 size: c_int,
1841 URL: *const c_char,
1842 encoding: *const c_char,
1843 options: c_int,
1844) -> *mut XmlTextReader {
1845 if buffer.is_null() || size <= 0 {
1846 return ptr::null_mut();
1847 }
1848
1849 let ctxt = unsafe { create_parser_ctxt() };
1851 if ctxt.is_null() {
1852 return ptr::null_mut();
1853 }
1854
1855 let input = unsafe { input_from_memory_named(buffer, size, URL) };
1858
1859 unsafe { setup_parser_input(ctxt, input) };
1861 unsafe {
1862 (*ctxt).options = options;
1863 }
1864
1865 let url_bytes = if URL.is_null() {
1866 None
1867 } else {
1868 unsafe {
1870 let cstr = std::ffi::CStr::from_ptr(URL);
1871 Some(cstr.to_bytes().to_vec())
1872 }
1873 };
1874
1875 let enc_bytes = if encoding.is_null() {
1876 None
1877 } else {
1878 unsafe {
1880 let cstr = std::ffi::CStr::from_ptr(encoding);
1881 Some(cstr.to_bytes().to_vec())
1882 }
1883 };
1884
1885 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1886 reader.options = options;
1887 Box::into_raw(Box::new(reader))
1888}
1889
1890#[no_mangle]
1904pub unsafe extern "C" fn xmlReaderForFd(
1905 fd: c_int,
1906 URL: *const c_char,
1907 encoding: *const c_char,
1908 options: c_int,
1909) -> *mut XmlTextReader {
1910 let ctxt = unsafe { create_parser_ctxt() };
1912 if ctxt.is_null() {
1913 return ptr::null_mut();
1914 }
1915
1916 let mut buf = Vec::new();
1918 let mut tmp = [0u8; 4096];
1919 loop {
1920 let n = unsafe { libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len()) };
1922 if n <= 0 {
1923 break;
1924 }
1925 buf.extend_from_slice(&tmp[..n as usize]);
1926 }
1927
1928 let input = unsafe { input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int) };
1930
1931 unsafe { setup_parser_input(ctxt, input) };
1933 unsafe {
1934 (*ctxt).options = options;
1935 }
1936
1937 let url_bytes = if URL.is_null() {
1938 None
1939 } else {
1940 unsafe {
1942 let cstr = std::ffi::CStr::from_ptr(URL);
1943 Some(cstr.to_bytes().to_vec())
1944 }
1945 };
1946
1947 let enc_bytes = if encoding.is_null() {
1948 None
1949 } else {
1950 unsafe {
1952 let cstr = std::ffi::CStr::from_ptr(encoding);
1953 Some(cstr.to_bytes().to_vec())
1954 }
1955 };
1956
1957 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1958 reader.options = options;
1959 Box::into_raw(Box::new(reader))
1960}
1961
1962#[no_mangle]
1978pub unsafe extern "C" fn xmlReaderForIO(
1979 ioread: Option<xmlInputReadCallback>,
1980 ioclose: Option<xmlInputCloseCallback>,
1981 ioctx: *mut c_void,
1982 URL: *const c_char,
1983 encoding: *const c_char,
1984 options: c_int,
1985) -> *mut XmlTextReader {
1986 let ctxt = unsafe { create_parser_ctxt() };
1988 if ctxt.is_null() {
1989 return ptr::null_mut();
1990 }
1991
1992 let input = unsafe { input_from_io(ioread, ioclose, ioctx) };
1994
1995 unsafe { setup_parser_input(ctxt, input) };
1997 unsafe {
1998 (*ctxt).options = options;
1999 }
2000
2001 let url_bytes = if URL.is_null() {
2002 None
2003 } else {
2004 unsafe {
2006 let cstr = std::ffi::CStr::from_ptr(URL);
2007 Some(cstr.to_bytes().to_vec())
2008 }
2009 };
2010
2011 let enc_bytes = if encoding.is_null() {
2012 None
2013 } else {
2014 unsafe {
2016 let cstr = std::ffi::CStr::from_ptr(encoding);
2017 Some(cstr.to_bytes().to_vec())
2018 }
2019 };
2020
2021 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
2022 reader.options = options;
2023 Box::into_raw(Box::new(reader))
2024}
2025
2026#[no_mangle]
2045pub unsafe extern "C" fn xmlTextReaderRead(reader: *mut XmlTextReader) -> c_int {
2046 if reader.is_null() {
2047 return -1;
2048 }
2049 unsafe { (*reader).Read() }
2051}
2052
2053#[no_mangle]
2067pub unsafe extern "C" fn xmlTextReaderNext(reader: *mut XmlTextReader) -> c_int {
2068 if reader.is_null() {
2069 return -1;
2070 }
2071 unsafe { (*reader).Next() }
2073}
2074
2075#[no_mangle]
2087pub unsafe extern "C" fn xmlTextReaderNextSibling(reader: *mut XmlTextReader) -> c_int {
2088 if reader.is_null() {
2089 return -1;
2090 }
2091 unsafe { (*reader).Next() }
2093}
2094
2095#[no_mangle]
2109pub unsafe extern "C" fn xmlTextReaderPrev(reader: *mut XmlTextReader) -> c_int {
2110 if reader.is_null() {
2111 return -1;
2112 }
2113 unsafe { (*reader).Prev() }
2115}
2116
2117#[no_mangle]
2131pub unsafe extern "C" fn xmlTextReaderMoveToElement(reader: *mut XmlTextReader) -> c_int {
2132 if reader.is_null() {
2133 return -1;
2134 }
2135 unsafe { (*reader).MoveToElement() }
2137}
2138
2139#[no_mangle]
2153pub unsafe extern "C" fn xmlTextReaderMoveToAttribute(
2154 reader: *mut XmlTextReader,
2155 name: *const xmlChar,
2156) -> c_int {
2157 if reader.is_null() || name.is_null() {
2158 return -1;
2159 }
2160 unsafe { (*reader).MoveToAttribute(name) }
2162}
2163
2164#[no_mangle]
2178pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNo(
2179 reader: *mut XmlTextReader,
2180 index: c_int,
2181) -> c_int {
2182 if reader.is_null() {
2183 return -1;
2184 }
2185 unsafe { (*reader).MoveToAttributeNo(index) }
2187}
2188
2189#[no_mangle]
2203pub unsafe extern "C" fn xmlTextReaderMoveToFirstAttribute(reader: *mut XmlTextReader) -> c_int {
2204 if reader.is_null() {
2205 return -1;
2206 }
2207 unsafe { (*reader).MoveToFirstAttribute() }
2209}
2210
2211#[no_mangle]
2225pub unsafe extern "C" fn xmlTextReaderMoveToNextAttribute(reader: *mut XmlTextReader) -> c_int {
2226 if reader.is_null() {
2227 return -1;
2228 }
2229 unsafe { (*reader).MoveToNextAttribute() }
2231}
2232
2233#[no_mangle]
2251pub unsafe extern "C" fn xmlTextReaderAttributeCount(reader: *mut XmlTextReader) -> c_int {
2252 if reader.is_null() {
2253 return -1;
2254 }
2255 unsafe { (*reader).AttributeCount() }
2257}
2258
2259#[no_mangle]
2273pub unsafe extern "C" fn xmlTextReaderDepth(reader: *mut XmlTextReader) -> c_int {
2274 if reader.is_null() {
2275 return -1;
2276 }
2277 unsafe { (*reader).Depth() }
2279}
2280
2281#[no_mangle]
2295pub unsafe extern "C" fn xmlTextReaderNodeType(reader: *mut XmlTextReader) -> c_int {
2296 if reader.is_null() {
2297 return -1;
2298 }
2299 unsafe { (*reader).NodeType() as c_int }
2301}
2302
2303#[no_mangle]
2318pub unsafe extern "C" fn xmlTextReaderName(reader: *mut XmlTextReader) -> *mut xmlChar {
2319 if reader.is_null() {
2320 return ptr::null_mut();
2321 }
2322 unsafe { (*reader).Name() }
2324}
2325
2326#[no_mangle]
2341pub unsafe extern "C" fn xmlTextReaderValue(reader: *mut XmlTextReader) -> *mut xmlChar {
2342 if reader.is_null() {
2343 return ptr::null_mut();
2344 }
2345 unsafe { (*reader).Value() }
2347}
2348
2349#[no_mangle]
2364pub unsafe extern "C" fn xmlTextReaderConstName(reader: *mut XmlTextReader) -> *const xmlChar {
2365 if reader.is_null() {
2366 return ptr::null();
2367 }
2368 unsafe { (*reader).ConstName() }
2370}
2371
2372#[no_mangle]
2387pub unsafe extern "C" fn xmlTextReaderConstValue(reader: *mut XmlTextReader) -> *const xmlChar {
2388 if reader.is_null() {
2389 return ptr::null();
2390 }
2391 unsafe { (*reader).ConstValue() }
2393}
2394
2395#[no_mangle]
2410pub unsafe extern "C" fn xmlTextReaderBaseUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2411 if reader.is_null() {
2412 return ptr::null_mut();
2413 }
2414 unsafe { (*reader).BaseUri() }
2416}
2417
2418#[no_mangle]
2432pub unsafe extern "C" fn xmlTextReaderLocalName(reader: *mut XmlTextReader) -> *mut xmlChar {
2433 if reader.is_null() {
2434 return ptr::null_mut();
2435 }
2436 unsafe { (*reader).LocalName() }
2438}
2439
2440#[no_mangle]
2454pub unsafe extern "C" fn xmlTextReaderNamespaceUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2455 if reader.is_null() {
2456 return ptr::null_mut();
2457 }
2458 unsafe { (*reader).NamespaceUri() }
2460}
2461
2462#[no_mangle]
2476pub unsafe extern "C" fn xmlTextReaderPrefix(reader: *mut XmlTextReader) -> *mut xmlChar {
2477 if reader.is_null() {
2478 return ptr::null_mut();
2479 }
2480 unsafe { (*reader).Prefix() }
2482}
2483
2484#[no_mangle]
2498pub unsafe extern "C" fn xmlTextReaderHasValue(reader: *mut XmlTextReader) -> c_int {
2499 if reader.is_null() {
2500 return 0;
2501 }
2502 unsafe { (*reader).HasValue() }
2504}
2505
2506#[no_mangle]
2520pub unsafe extern "C" fn xmlTextReaderHasAttributes(reader: *mut XmlTextReader) -> c_int {
2521 if reader.is_null() {
2522 return 0;
2523 }
2524 unsafe { (*reader).HasAttributes() }
2526}
2527
2528#[no_mangle]
2542pub unsafe extern "C" fn xmlTextReaderIsEmptyElement(reader: *mut XmlTextReader) -> c_int {
2543 if reader.is_null() {
2544 return 0;
2545 }
2546 unsafe { (*reader).IsEmptyElement() }
2548}
2549
2550#[no_mangle]
2564pub unsafe extern "C" fn xmlTextReaderReadState(reader: *mut XmlTextReader) -> c_int {
2565 if reader.is_null() {
2566 return ReadState::ERROR as c_int;
2567 }
2568 unsafe { (*reader).ReadState() as c_int }
2570}
2571
2572#[no_mangle]
2590pub unsafe extern "C" fn xmlTextReaderGetAttribute(
2591 reader: *mut XmlTextReader,
2592 name: *const xmlChar,
2593) -> *mut xmlChar {
2594 if reader.is_null() || name.is_null() {
2595 return ptr::null_mut();
2596 }
2597 unsafe { (*reader).GetAttribute(name) }
2599}
2600
2601#[no_mangle]
2615pub unsafe extern "C" fn xmlTextReaderGetAttributeNo(
2616 reader: *mut XmlTextReader,
2617 index: c_int,
2618) -> *mut xmlChar {
2619 if reader.is_null() {
2620 return ptr::null_mut();
2621 }
2622 unsafe { (*reader).GetAttributeNo(index) }
2624}
2625
2626#[no_mangle]
2642pub unsafe extern "C" fn xmlTextReaderGetAttributeNs(
2643 reader: *mut XmlTextReader,
2644 localName: *const xmlChar,
2645 namespaceURI: *const xmlChar,
2646) -> *mut xmlChar {
2647 if reader.is_null() || localName.is_null() {
2648 return ptr::null_mut();
2649 }
2650 unsafe { (*reader).GetAttributeNs(localName, namespaceURI) }
2652}
2653
2654#[no_mangle]
2668pub unsafe extern "C" fn xmlTextReaderLookupNamespace(
2669 reader: *mut XmlTextReader,
2670 prefix: *const xmlChar,
2671) -> *mut xmlChar {
2672 if reader.is_null() {
2673 return ptr::null_mut();
2674 }
2675 unsafe { (*reader).LookupNamespace(prefix) }
2677}
2678
2679#[no_mangle]
2697pub unsafe extern "C" fn xmlTextReaderGetParserProp(
2698 reader: *mut XmlTextReader,
2699 prop: c_int,
2700) -> c_int {
2701 if reader.is_null() {
2702 return -1;
2703 }
2704 unsafe { (*reader).GetParserProp(prop) }
2706}
2707
2708#[no_mangle]
2722pub unsafe extern "C" fn xmlTextReaderSetParserProp(
2723 reader: *mut XmlTextReader,
2724 prop: c_int,
2725 value: c_int,
2726) -> c_int {
2727 if reader.is_null() {
2728 return -1;
2729 }
2730 unsafe { (*reader).SetParserProp(prop, value) }
2732}
2733
2734#[no_mangle]
2751pub unsafe extern "C" fn xmlFreeTextReader(reader: *mut XmlTextReader) {
2752 if reader.is_null() {
2753 return;
2754 }
2755 unsafe {
2758 let _ = Box::from_raw(reader);
2759 }
2760}
2761
2762#[no_mangle]
2778pub unsafe extern "C" fn xmlTextReaderSetup(
2779 reader: *mut XmlTextReader,
2780 input: *mut _xmlParserInputBuffer,
2781 URL: *const c_char,
2782 encoding: *const c_char,
2783 options: c_int,
2784) -> c_int {
2785 if reader.is_null() {
2786 return -1;
2787 }
2788
2789 let r = unsafe { &mut *reader };
2791
2792 r.clear_cached_name();
2794 r.clear_cached_value();
2795
2796 if !r.doc.is_null() {
2798 unsafe { tree::free_doc(r.doc) };
2800 r.doc = ptr::null_mut();
2801 }
2802
2803 if !r.ctxt.is_null() {
2805 unsafe { free_parser_ctxt(r.ctxt) };
2807 r.ctxt = ptr::null_mut();
2808 }
2809
2810 r.events.clear();
2811 r.event_index = 0;
2812 r.state = ReadState::INITIALIZED;
2813 r.cur_node = ptr::null_mut();
2814 r.node_type = ReaderNodeType::NONE;
2815 r.depth = 0;
2816 r.attribute_count = -1;
2817 r.cur_attribute = -1;
2818 r.options = options;
2819 r.parsed = false;
2820 r.errors.clear();
2821
2822 if !r.URL.is_null() {
2824 unsafe { xmlFreeImpl(r.URL as *mut c_void) };
2826 r.URL = ptr::null_mut();
2827 }
2828 if !URL.is_null() {
2829 let url_str = unsafe { std::ffi::CStr::from_ptr(URL) };
2831 r.URL = unsafe { bytes_to_xmlstr(url_str.to_bytes()) };
2833 }
2834
2835 if !r.encoding.is_null() {
2837 unsafe { xmlFreeImpl(r.encoding as *mut c_void) };
2839 r.encoding = ptr::null_mut();
2840 }
2841 if !encoding.is_null() {
2842 let enc_str = unsafe { std::ffi::CStr::from_ptr(encoding) };
2844 r.encoding = unsafe { bytes_to_xmlstr(enc_str.to_bytes()) };
2846 }
2847
2848 if !input.is_null() {
2850 let ctxt = unsafe { create_parser_ctxt() };
2852 if ctxt.is_null() {
2853 return -1;
2854 }
2855
2856 let mut data = Vec::new();
2858 let mut tmp = [0u8; 4096];
2859
2860 let read_cb = unsafe { (*input).readcallback };
2862 let ioctx = unsafe { (*input).context };
2863
2864 if let Some(read) = read_cb {
2865 loop {
2866 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2868 if n <= 0 {
2869 break;
2870 }
2871 data.extend_from_slice(&tmp[..n as usize]);
2872 }
2873 }
2874
2875 let close_cb = unsafe { (*input).closecallback };
2877 if let Some(close) = close_cb {
2878 unsafe { close(ioctx) };
2880 }
2881
2882 let input_buf = InputBuffer::from_memory(&data, None);
2883
2884 unsafe { setup_parser_input(ctxt, input_buf) };
2886 unsafe {
2887 (*ctxt).options = options;
2888 }
2889
2890 r.ctxt = ctxt;
2891 }
2892
2893 0
2894}
2895
2896#[no_mangle]
2910pub unsafe extern "C" fn xmlTextReaderCurrentDoc(reader: *mut XmlTextReader) -> *mut _xmlDoc {
2911 if reader.is_null() {
2912 return ptr::null_mut();
2913 }
2914 unsafe { (*reader).CurrentDoc() }
2916}
2917
2918#[no_mangle]
2937pub unsafe extern "C" fn xmlTextReaderClose(reader: *mut XmlTextReader) -> c_int {
2938 if reader.is_null() {
2939 return -1;
2940 }
2941 unsafe {
2944 let r = &mut *reader;
2945 r.cur_node = ptr::null_mut();
2946 r.node_type = ReaderNodeType::NONE;
2947 r.clear_cached_name();
2948 r.clear_cached_value();
2949 r.state = ReadState::CLOSED;
2950 }
2951 0
2952}
2953
2954#[no_mangle]
2969pub unsafe extern "C" fn xmlTextReaderCurrentNode(reader: *mut XmlTextReader) -> *mut _xmlNode {
2970 if reader.is_null() {
2971 return ptr::null_mut();
2972 }
2973 unsafe { (*reader).cur_node }
2975}
2976
2977#[no_mangle]
2997pub unsafe extern "C" fn xmlTextReaderExpand(reader: *mut XmlTextReader) -> *mut _xmlNode {
2998 if reader.is_null() {
2999 return ptr::null_mut();
3000 }
3001 unsafe { (*reader).cur_node }
3003}
3004
3005#[no_mangle]
3023pub unsafe extern "C" fn xmlTextReaderGetParserLineNumber(reader: *mut XmlTextReader) -> c_int {
3024 if reader.is_null() {
3025 return 0;
3026 }
3027 unsafe {
3029 let node = (*reader).cur_node;
3030 if node.is_null() {
3031 0
3032 } else {
3033 (*node).line as c_int
3034 }
3035 }
3036}
3037
3038#[no_mangle]
3054pub unsafe extern "C" fn xmlTextReaderGetParserColumnNumber(reader: *mut XmlTextReader) -> c_int {
3055 if reader.is_null() {
3056 return -1;
3057 }
3058 -1
3059}
3060
3061#[no_mangle]
3079pub unsafe extern "C" fn xmlTextReaderIsValid(reader: *mut XmlTextReader) -> c_int {
3080 if reader.is_null() {
3081 return -1;
3082 }
3083 0
3084}
3085
3086#[no_mangle]
3103pub unsafe extern "C" fn xmlTextReaderNormalization(reader: *mut XmlTextReader) -> c_int {
3104 if reader.is_null() {
3105 return -1;
3106 }
3107 1
3108}
3109
3110#[no_mangle]
3129pub unsafe extern "C" fn xmlTextReaderReadAttributeValue(reader: *mut XmlTextReader) -> c_int {
3130 if reader.is_null() {
3131 return -1;
3132 }
3133 unsafe {
3135 let r = &*reader;
3136 if r.node_type == ReaderNodeType::ATTRIBUTE && !r.cur_node.is_null() {
3137 1
3138 } else {
3139 0
3140 }
3141 }
3142}
3143
3144#[no_mangle]
3162pub unsafe extern "C" fn xmlTextReaderReadString(reader: *mut XmlTextReader) -> *mut xmlChar {
3163 if reader.is_null() {
3164 return ptr::null_mut();
3165 }
3166 unsafe {
3168 let node = (*reader).cur_node;
3169 if node.is_null() {
3170 return ptr::null_mut();
3171 }
3172 tree::node_get_content(node)
3173 }
3174}
3175
3176#[no_mangle]
3193pub unsafe extern "C" fn xmlTextReaderReadInnerXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3194 if reader.is_null() {
3195 return ptr::null_mut();
3196 }
3197 unsafe {
3199 let node = (*reader).cur_node;
3200 if node.is_null() {
3201 return ptr::null_mut();
3202 }
3203 let buf = crate::xml::io::buf_create(-1);
3204 if buf.is_null() {
3205 return ptr::null_mut();
3206 }
3207 let mut child = (*node).children;
3208 while !child.is_null() {
3209 tree::serialize_node(child, buf, 0, 0);
3210 child = (*child).next;
3211 }
3212 let len = crate::xml::io::buf_length(buf) as usize;
3213 let content = crate::xml::io::buf_content(buf);
3214 if content.is_null() || len == 0 {
3215 crate::xml::io::buf_free(buf);
3216 return ptr::null_mut();
3217 }
3218 let out = xml_strdup(content);
3219 crate::xml::io::buf_free(buf);
3220 out
3221 }
3222}
3223
3224#[no_mangle]
3240pub unsafe extern "C" fn xmlTextReaderReadOuterXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3241 if reader.is_null() {
3242 return ptr::null_mut();
3243 }
3244 unsafe {
3246 let node = (*reader).cur_node;
3247 if node.is_null() {
3248 return ptr::null_mut();
3249 }
3250 let buf = crate::xml::io::buf_create(-1);
3251 if buf.is_null() {
3252 return ptr::null_mut();
3253 }
3254 tree::serialize_node(node, buf, 0, 0);
3255 let len = crate::xml::io::buf_length(buf) as usize;
3256 let content = crate::xml::io::buf_content(buf);
3257 if content.is_null() || len == 0 {
3258 crate::xml::io::buf_free(buf);
3259 return ptr::null_mut();
3260 }
3261 let out = xml_strdup(content);
3262 crate::xml::io::buf_free(buf);
3263 out
3264 }
3265}
3266
3267#[no_mangle]
3282pub unsafe extern "C" fn xmlTextReaderStandalone(reader: *mut XmlTextReader) -> c_int {
3283 if reader.is_null() {
3284 return -1;
3285 }
3286 unsafe {
3288 let doc = (*reader).doc;
3289 if doc.is_null() {
3290 return -1;
3291 }
3292 (*doc).standalone
3293 }
3294}
3295
3296#[no_mangle]
3313pub unsafe extern "C" fn xmlTextReaderXmlLang(reader: *mut XmlTextReader) -> *mut xmlChar {
3314 if reader.is_null() {
3315 return ptr::null_mut();
3316 }
3317 unsafe {
3319 let mut node = (*reader).cur_node;
3320 while !node.is_null() {
3321 let mut prop = (*node).properties;
3323 while !prop.is_null() {
3324 if !(*prop).name.is_null() {
3325 let name = crate::xml::string::xmlstr_to_bytes((*prop).name);
3326 if name == b"lang" && !(*prop).ns.is_null() {
3327 let ns_href = crate::xml::string::xmlstr_to_bytes((*(*prop).ns).href);
3328 if ns_href == b"http://www.w3.org/XML/1998/namespace" {
3329 let v = (*prop).children;
3330 if !v.is_null() && !(*v).content.is_null() {
3331 return xml_strdup((*v).content);
3332 }
3333 }
3334 }
3335 }
3336 prop = (*prop).next;
3337 }
3338 node = (*node).parent;
3339 }
3340 ptr::null_mut()
3341 }
3342}
3343
3344#[cfg(test)]
3349mod tests {
3350 use super::*;
3351 use crate::abi::allocator::xmlFreeImpl;
3352 use core::ffi::c_void;
3353 use std::os::raw::c_char;
3354
3355 unsafe fn create_reader(xml: &str) -> *mut XmlTextReader {
3357 let bytes = xml.as_bytes();
3358 xmlReaderForMemory(
3359 bytes.as_ptr() as *const c_char,
3360 bytes.len() as c_int,
3361 ptr::null(),
3362 ptr::null(),
3363 0,
3364 )
3365 }
3366
3367 unsafe fn free_reader(reader: *mut XmlTextReader) {
3369 if !reader.is_null() {
3370 xmlFreeTextReader(reader);
3371 }
3372 }
3373
3374 unsafe fn collect_nodes(reader: *mut XmlTextReader) -> Vec<(ReaderNodeType, String, i32)> {
3376 let mut result = Vec::new();
3377 loop {
3378 let ret = xmlTextReaderRead(reader);
3379 if ret <= 0 {
3380 break;
3381 }
3382 let r = &*reader;
3384 let ntype = r.NodeType();
3385 let name = if r.name.is_null() {
3386 String::new()
3387 } else {
3388 xmlstr_to_string(r.name as *const xmlChar)
3389 };
3390 let depth = r.Depth();
3391 result.push((ntype, name, depth));
3392 }
3393 result
3394 }
3395
3396 #[test]
3399 fn test_create_reader_from_memory() {
3400 unsafe {
3401 let reader = create_reader("<root/>");
3402 assert!(!reader.is_null());
3403 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3404 free_reader(reader);
3405 }
3406 }
3407
3408 #[test]
3409 fn test_read_simple_document() {
3410 unsafe {
3411 let reader = create_reader("<root><child>text</child></root>");
3412 assert!(!reader.is_null());
3413
3414 let nodes = collect_nodes(reader);
3415 assert_eq!(nodes.len(), 5);
3423 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
3424 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
3425 assert_eq!(nodes[2], (ReaderNodeType::TEXT, "#text".to_string(), 2));
3427 assert_eq!(
3428 nodes[3],
3429 (ReaderNodeType::END_ELEMENT, "child".to_string(), 1)
3430 );
3431 assert_eq!(
3432 nodes[4],
3433 (ReaderNodeType::END_ELEMENT, "root".to_string(), 0)
3434 );
3435
3436 assert_eq!((*reader).ReadState(), ReadState::EOF);
3437 free_reader(reader);
3438 }
3439 }
3440
3441 #[test]
3442 fn test_read_state_transitions() {
3443 unsafe {
3444 let reader = create_reader("<root/>");
3445 assert!(!reader.is_null());
3446 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3447
3448 assert_eq!(xmlTextReaderRead(reader), 1);
3450 assert_eq!((*reader).ReadState(), ReadState::READING);
3451 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3452 assert_eq!((*reader).Depth(), 0);
3453
3454 assert_eq!(xmlTextReaderRead(reader), 0);
3457 assert_eq!((*reader).ReadState(), ReadState::EOF);
3458
3459 free_reader(reader);
3460 }
3461 }
3462
3463 #[test]
3464 fn test_null_reader_returns_error() {
3465 unsafe {
3466 assert_eq!(xmlTextReaderRead(ptr::null_mut()), -1);
3467 assert_eq!(xmlTextReaderDepth(ptr::null_mut()), -1);
3468 assert_eq!(xmlTextReaderNodeType(ptr::null_mut()), -1);
3469 assert!(xmlTextReaderName(ptr::null_mut()).is_null());
3470 assert!(xmlTextReaderValue(ptr::null_mut()).is_null());
3471 assert_eq!(xmlTextReaderHasValue(ptr::null_mut()), 0);
3472 assert_eq!(xmlTextReaderIsEmptyElement(ptr::null_mut()), 0);
3473 assert_eq!(
3474 xmlTextReaderReadState(ptr::null_mut()),
3475 ReadState::ERROR as c_int
3476 );
3477 }
3478 }
3479
3480 #[test]
3481 fn test_xmlFreeTextReader_null() {
3482 unsafe {
3483 xmlFreeTextReader(ptr::null_mut());
3485 }
3486 }
3487
3488 #[test]
3489 fn test_reader_name_and_value() {
3490 unsafe {
3491 let reader = create_reader("<root>hello</root>");
3492 assert!(!reader.is_null());
3493
3494 assert_eq!(xmlTextReaderRead(reader), 1);
3496 let name = xmlTextReaderName(reader);
3497 assert!(!name.is_null());
3498 assert_eq!(xmlstr_to_string(name), "root");
3499 xmlFreeImpl(name as *mut c_void);
3500
3501 assert_eq!(xmlTextReaderHasValue(reader), 0);
3502
3503 assert_eq!(xmlTextReaderRead(reader), 1);
3505 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3506 assert_eq!((*reader).HasValue(), 1);
3507
3508 let val = xmlTextReaderValue(reader);
3509 assert!(!val.is_null());
3510 assert_eq!(xmlstr_to_string(val), "hello");
3511 xmlFreeImpl(val as *mut c_void);
3512
3513 free_reader(reader);
3514 }
3515 }
3516
3517 #[test]
3518 fn test_empty_element() {
3519 unsafe {
3520 let reader = create_reader("<empty/>");
3521 assert!(!reader.is_null());
3522
3523 assert_eq!(xmlTextReaderRead(reader), 1);
3524 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3525 assert_eq!((*reader).IsEmptyElement(), 1);
3526 assert_eq!((*reader).HasAttributes(), 0);
3527 assert_eq!((*reader).AttributeCount(), 0);
3528
3529 assert_eq!(xmlTextReaderRead(reader), 0);
3532 assert_eq!((*reader).ReadState(), ReadState::EOF);
3533
3534 free_reader(reader);
3535 }
3536 }
3537
3538 #[test]
3539 fn test_element_with_attributes() {
3540 unsafe {
3541 let reader = create_reader(r#"<root a="1" b="2"/>"#);
3542 assert!(!reader.is_null());
3543
3544 assert_eq!(xmlTextReaderRead(reader), 1);
3545 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3546 assert_eq!((*reader).HasAttributes(), 1);
3547
3548 let attrs = xmlTextReaderAttributeCount(reader);
3551 assert_eq!(attrs, 2);
3552
3553 free_reader(reader);
3554 }
3555 }
3556
3557 #[test]
3558 fn test_attribute_navigation() {
3559 unsafe {
3560 let reader = create_reader(r#"<root a="1" b="2"></root>"#);
3561 assert!(!reader.is_null());
3562
3563 assert_eq!(xmlTextReaderRead(reader), 1);
3565 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3566
3567 assert_eq!(xmlTextReaderMoveToFirstAttribute(reader), 1);
3569 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3570
3571 let name = xmlTextReaderConstName(reader);
3572 assert!(!name.is_null());
3573 assert_eq!(xmlstr_to_bytes(name), b"a");
3574
3575 let val = xmlTextReaderConstValue(reader);
3576 assert!(!val.is_null());
3577 assert_eq!(xmlstr_to_bytes(val), b"1");
3578
3579 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 1);
3581 let name = xmlTextReaderConstName(reader);
3582 assert!(!name.is_null());
3583 assert_eq!(xmlstr_to_bytes(name), b"b");
3584 let val = xmlTextReaderConstValue(reader);
3585 assert!(!val.is_null());
3586 assert_eq!(xmlstr_to_bytes(val), b"2");
3587
3588 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 0);
3590
3591 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3593 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3594
3595 assert_eq!(
3597 xmlTextReaderMoveToAttribute(reader, b"a\0" as *const u8 as *const xmlChar),
3598 1
3599 );
3600 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3601
3602 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3604 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 1), 1);
3605 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3606
3607 free_reader(reader);
3608 }
3609 }
3610
3611 #[test]
3612 fn test_get_attribute() {
3613 unsafe {
3614 let reader = create_reader(r#"<root a="hello" b="world"/>"#);
3615 assert!(!reader.is_null());
3616
3617 assert_eq!(xmlTextReaderRead(reader), 1);
3618
3619 let val = xmlTextReaderGetAttribute(reader, b"a\0" as *const u8 as *const xmlChar);
3621 assert!(!val.is_null());
3622 assert_eq!(xmlstr_to_bytes(val), b"hello");
3623 xmlFreeImpl(val as *mut c_void);
3624
3625 let val = xmlTextReaderGetAttribute(reader, b"b\0" as *const u8 as *const xmlChar);
3626 assert!(!val.is_null());
3627 assert_eq!(xmlstr_to_bytes(val), b"world");
3628 xmlFreeImpl(val as *mut c_void);
3629
3630 let val = xmlTextReaderGetAttribute(reader, b"c\0" as *const u8 as *const xmlChar);
3632 assert!(val.is_null());
3633
3634 let val = xmlTextReaderGetAttributeNo(reader, 0);
3636 assert!(!val.is_null());
3637 assert_eq!(xmlstr_to_bytes(val), b"hello");
3638 xmlFreeImpl(val as *mut c_void);
3639
3640 let val = xmlTextReaderGetAttributeNo(reader, 1);
3641 assert!(!val.is_null());
3642 assert_eq!(xmlstr_to_bytes(val), b"world");
3643 xmlFreeImpl(val as *mut c_void);
3644
3645 let val = xmlTextReaderGetAttributeNo(reader, 2);
3646 assert!(val.is_null());
3647
3648 free_reader(reader);
3649 }
3650 }
3651
3652 #[test]
3653 fn test_depth_tracking() {
3654 unsafe {
3655 let reader = create_reader("<a><b><c/></b></a>");
3656 assert!(!reader.is_null());
3657
3658 let nodes = collect_nodes(reader);
3659 assert_eq!(nodes.len(), 5);
3664 assert_eq!(nodes[0].2, 0); assert_eq!(nodes[1].2, 1); assert_eq!(nodes[2].2, 2); assert_eq!(nodes[3].2, 1); assert_eq!(nodes[4].2, 0); free_reader(reader);
3671 }
3672 }
3673
3674 #[test]
3675 fn test_multiple_siblings() {
3676 unsafe {
3677 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3678 assert!(!reader.is_null());
3679
3680 let nodes = collect_nodes(reader);
3681 assert_eq!(nodes.len(), 11);
3686
3687 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "a".to_string(), 1));
3689 assert_eq!(nodes[4], (ReaderNodeType::ELEMENT, "b".to_string(), 1));
3690 assert_eq!(nodes[7], (ReaderNodeType::ELEMENT, "c".to_string(), 1));
3691
3692 free_reader(reader);
3693 }
3694 }
3695
3696 #[test]
3697 fn test_next_skip_to_sibling() {
3698 unsafe {
3699 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3700 assert!(!reader.is_null());
3701
3702 assert_eq!(xmlTextReaderRead(reader), 1);
3704 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3705
3706 assert_eq!(xmlTextReaderRead(reader), 1);
3708 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3709 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "a");
3710
3711 assert_eq!(xmlTextReaderRead(reader), 1);
3713 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3714
3715 assert_eq!(xmlTextReaderNext(reader), 1);
3717 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3718 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "b");
3719
3720 assert_eq!(xmlTextReaderNext(reader), 1);
3722 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3723 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "c");
3724
3725 assert_eq!(xmlTextReaderNext(reader), 0);
3727
3728 free_reader(reader);
3729 }
3730 }
3731
3732 #[test]
3733 fn test_comment_and_pi_nodes() {
3734 unsafe {
3735 let xml = b"<?pi target?><root><!-- comment -->text</root>\0";
3736 let reader = xmlReaderForMemory(
3737 xml.as_ptr() as *const c_char,
3738 (xml.len() - 1) as c_int,
3739 ptr::null(),
3740 ptr::null(),
3741 0,
3742 );
3743 assert!(!reader.is_null());
3744
3745 let nodes = collect_nodes(reader);
3746 assert!(!nodes.is_empty(), "no nodes collected: {:?}", nodes);
3749
3750 assert_eq!(
3752 nodes[0].0,
3753 ReaderNodeType::PROCESSING_INSTRUCTION,
3754 "expected PI at nodes[0], got {:?} name={}",
3755 nodes[0].0,
3756 nodes[0].1
3757 );
3758 assert_eq!(
3759 nodes[0].0,
3760 ReaderNodeType::PROCESSING_INSTRUCTION,
3761 "expected PI at nodes[0], got {:?} name={}",
3762 nodes[0].0,
3763 nodes[0].1
3764 );
3765
3766 let root_idx = nodes
3768 .iter()
3769 .position(|(t, n, _)| *t == ReaderNodeType::ELEMENT && n == "root");
3770 assert!(
3771 root_idx.is_some(),
3772 "no ELEMENT root found in nodes: {:?}",
3773 nodes
3774 .iter()
3775 .map(|(t, n, _)| format!("{:?}:{}", t, n))
3776 .collect::<Vec<_>>()
3777 );
3778
3779 let comment_idx = nodes
3781 .iter()
3782 .position(|(t, _, _)| *t == ReaderNodeType::COMMENT);
3783 assert!(comment_idx.is_some(), "no COMMENT found");
3784
3785 let text_idx = nodes
3787 .iter()
3788 .position(|(t, _, _)| *t == ReaderNodeType::TEXT);
3789 assert!(text_idx.is_some(), "no TEXT found");
3790
3791 free_reader(reader);
3792 }
3793 }
3794
3795 #[test]
3796 fn test_local_name() {
3797 unsafe {
3798 let reader = create_reader("<root/>");
3800 assert!(!reader.is_null());
3801
3802 assert_eq!(xmlTextReaderRead(reader), 1);
3803 let local = xmlTextReaderLocalName(reader);
3804 assert!(!local.is_null());
3805 assert_eq!(xmlstr_to_bytes(local), b"root");
3806 xmlFreeImpl(local as *mut c_void);
3807
3808 free_reader(reader);
3809 }
3810 }
3811
3812 #[test]
3813 fn test_base_uri() {
3814 unsafe {
3815 let reader = create_reader("<root/>");
3816 assert!(!reader.is_null());
3817
3818 assert_eq!(xmlTextReaderRead(reader), 1);
3819 let uri = xmlTextReaderBaseUri(reader);
3821 assert!(uri.is_null());
3822
3823 free_reader(reader);
3824 }
3825 }
3826
3827 #[test]
3828 fn test_lookup_namespace() {
3829 unsafe {
3830 let reader = create_reader(r#"<root xmlns:ns="http://example.com"><ns:child/></root>"#);
3831 assert!(!reader.is_null());
3832
3833 assert_eq!(xmlTextReaderRead(reader), 1);
3835 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3836
3837 assert_eq!(xmlTextReaderRead(reader), 1);
3839
3840 let uri = xmlTextReaderLookupNamespace(reader, b"ns\0" as *const u8 as *const xmlChar);
3842 assert!(!uri.is_null());
3843 assert_eq!(xmlstr_to_bytes(uri), b"http://example.com");
3844 xmlFreeImpl(uri as *mut c_void);
3845
3846 let uri = xmlTextReaderLookupNamespace(reader, ptr::null());
3848 assert!(uri.is_null());
3849
3850 let uri = xmlTextReaderLookupNamespace(
3852 reader,
3853 b"nonexistent\0" as *const u8 as *const xmlChar,
3854 );
3855 assert!(uri.is_null());
3856
3857 free_reader(reader);
3858 }
3859 }
3860
3861 #[test]
3862 fn test_parser_properties() {
3863 unsafe {
3864 let reader = create_reader("<root/>");
3865 assert!(!reader.is_null());
3866
3867 assert_eq!(xmlTextReaderGetParserProp(reader, 1), 0); assert_eq!(xmlTextReaderGetParserProp(reader, 2), 0); assert_eq!(xmlTextReaderGetParserProp(reader, 3), 0); assert_eq!(xmlTextReaderGetParserProp(reader, 4), 0); assert_eq!(xmlTextReaderSetParserProp(reader, 1, 1), 0);
3875 assert_eq!(xmlTextReaderGetParserProp(reader, 1), 1);
3876
3877 assert_eq!(xmlTextReaderSetParserProp(reader, 4, 1), 0);
3878 assert_eq!(xmlTextReaderGetParserProp(reader, 4), 1);
3879
3880 assert_eq!(xmlTextReaderGetParserProp(reader, 99), -1);
3882 assert_eq!(xmlTextReaderSetParserProp(reader, 99, 1), -1);
3883
3884 free_reader(reader);
3885 }
3886 }
3887
3888 #[test]
3889 fn test_current_doc() {
3890 unsafe {
3891 let reader = create_reader("<root/>");
3892 assert!(!reader.is_null());
3893
3894 assert!((*reader).CurrentDoc().is_null());
3896
3897 assert_eq!(xmlTextReaderRead(reader), 1);
3899 let doc = xmlTextReaderCurrentDoc(reader);
3900 assert!(!doc.is_null());
3901
3902 free_reader(reader);
3903 }
3904 }
3905
3906 #[test]
3907 fn test_free_reader_after_read() {
3908 unsafe {
3909 let reader = create_reader("<root><child/></root>");
3910 assert!(!reader.is_null());
3911
3912 while xmlTextReaderRead(reader) > 0 {}
3914 assert_eq!((*reader).ReadState(), ReadState::EOF);
3915
3916 free_reader(reader);
3918 }
3919 }
3920
3921 #[test]
3922 fn test_reader_for_memory_null_buffer() {
3923 unsafe {
3924 let reader = xmlReaderForMemory(ptr::null(), 10, ptr::null(), ptr::null(), 0);
3925 assert!(reader.is_null());
3926 }
3927 }
3928
3929 #[test]
3930 fn test_reader_for_memory_empty_size() {
3931 unsafe {
3932 let data = b"<root/>";
3933 let reader = xmlReaderForMemory(
3934 data.as_ptr() as *const c_char,
3935 0,
3936 ptr::null(),
3937 ptr::null(),
3938 0,
3939 );
3940 assert!(reader.is_null());
3941 }
3942 }
3943
3944 #[test]
3945 fn test_reader_for_file_not_found() {
3946 unsafe {
3947 let filename = b"/nonexistent/file.xml\0" as *const u8 as *const c_char;
3948 let reader = xmlReaderForFile(filename, ptr::null(), 0);
3949 assert!(reader.is_null());
3950 }
3951 }
3952
3953 #[test]
3954 fn test_const_name_and_value() {
3955 unsafe {
3956 let reader = create_reader("<root>text</root>");
3957 assert!(!reader.is_null());
3958
3959 assert_eq!(xmlTextReaderRead(reader), 1);
3961 let cname = xmlTextReaderConstName(reader);
3962 assert!(!cname.is_null());
3963 assert_eq!(xmlstr_to_bytes(cname), b"root");
3964
3965 assert_eq!(xmlTextReaderRead(reader), 1);
3967 let cval = xmlTextReaderConstValue(reader);
3968 assert!(!cval.is_null());
3969 assert_eq!(xmlstr_to_bytes(cval), b"text");
3970
3971 free_reader(reader);
3972 }
3973 }
3974
3975 #[test]
3976 fn test_complex_nested_document() {
3977 unsafe {
3978 let xml = r#"<?xml version="1.0"?>
3979<library>
3980 <book id="1">
3981 <title>XML Fundamentals</title>
3982 <author>John Doe</author>
3983 </book>
3984 <book id="2">
3985 <title>XSLT Recipes</title>
3986 <author>Jane Smith</author>
3987 </book>
3988</library>"#;
3989
3990 let reader = create_reader(xml);
3991 assert!(!reader.is_null());
3992
3993 let mut element_count = 0;
3994 let mut end_element_count = 0;
3995 let mut text_count = 0;
3996 let mut pi_count = 0;
3997
3998 loop {
3999 let ret = xmlTextReaderRead(reader);
4000 if ret <= 0 {
4001 break;
4002 }
4003 match (*reader).NodeType() {
4004 ReaderNodeType::ELEMENT => element_count += 1,
4005 ReaderNodeType::END_ELEMENT => end_element_count += 1,
4006 ReaderNodeType::TEXT => text_count += 1,
4007 ReaderNodeType::PROCESSING_INSTRUCTION => pi_count += 1,
4008 _ => {}
4009 }
4010 }
4011
4012 assert_eq!(element_count, 7);
4014 assert_eq!(end_element_count, 7);
4016 assert_eq!(text_count, 4);
4018 assert_eq!(pi_count, 0);
4023
4024 free_reader(reader);
4025 }
4026 }
4027
4028 #[test]
4029 fn test_setup_reinitialize() {
4030 unsafe {
4031 let reader = create_reader("<root/>");
4032 assert!(!reader.is_null());
4033
4034 assert_eq!(xmlTextReaderRead(reader), 1);
4036 assert_eq!((*reader).ReadState(), ReadState::READING);
4037
4038 assert_eq!(
4042 xmlTextReaderSetup(reader, ptr::null_mut(), ptr::null(), ptr::null(), 0),
4043 0
4044 );
4045 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
4046
4047 free_reader(reader);
4048 }
4049 }
4050
4051 #[test]
4052 fn test_has_attributes_on_non_element() {
4053 unsafe {
4054 let reader = create_reader("<root>text</root>");
4055 assert!(!reader.is_null());
4056
4057 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0); assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0);
4062
4063 free_reader(reader);
4064 }
4065 }
4066
4067 #[test]
4068 fn test_prev_sibling() {
4069 unsafe {
4070 let reader = create_reader("<root><a/><b/><c/></root>");
4071 assert!(!reader.is_null());
4072
4073 while xmlTextReaderRead(reader) > 0 {
4075 }
4077
4078 assert_eq!(xmlTextReaderPrev(reader), -1);
4080
4081 free_reader(reader);
4082 }
4083 }
4084
4085 #[test]
4086 fn test_move_to_attribute_no_not_on_element() {
4087 unsafe {
4088 let reader = create_reader("<root>text</root>");
4089 assert!(!reader.is_null());
4090
4091 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4093
4094 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 0), 0);
4096
4097 free_reader(reader);
4098 }
4099 }
4100
4101 #[test]
4102 fn test_get_attribute_ns() {
4103 unsafe {
4104 let reader = create_reader(r#"<root a="1" b="2"/>"#);
4105 assert!(!reader.is_null());
4106
4107 assert_eq!(xmlTextReaderRead(reader), 1);
4108
4109 let val = xmlTextReaderGetAttributeNs(
4111 reader,
4112 b"a\0" as *const u8 as *const xmlChar,
4113 ptr::null(),
4114 );
4115 assert!(!val.is_null());
4116 assert_eq!(xmlstr_to_bytes(val), b"1");
4117 xmlFreeImpl(val as *mut c_void);
4118
4119 free_reader(reader);
4120 }
4121 }
4122
4123 #[test]
4124 fn test_mixed_content() {
4125 unsafe {
4126 let reader = create_reader("<root>before<child/>after</root>");
4127 assert!(!reader.is_null());
4128
4129 let nodes = collect_nodes(reader);
4130 assert_eq!(nodes.len(), 5);
4135 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
4136 assert_eq!(nodes[1].0, ReaderNodeType::TEXT);
4137 assert_eq!(nodes[2], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
4138 assert_eq!(nodes[3].0, ReaderNodeType::TEXT);
4139
4140 free_reader(reader);
4141 }
4142 }
4143
4144 #[test]
4145 fn test_error_handling_invalid_xml() {
4146 unsafe {
4147 let data = b"<root><\0" as *const u8 as *const c_char;
4149 let reader = xmlReaderForMemory(data, 7, ptr::null(), ptr::null(), 0);
4150 assert!(!reader.is_null());
4151
4152 let ret = xmlTextReaderRead(reader);
4154 assert!(ret == -1 || ret == 0);
4155
4156 free_reader(reader);
4157 }
4158 }
4159
4160 #[test]
4161 fn test_reader_with_options() {
4162 unsafe {
4163 let data = b"<root/>\0" as *const u8 as *const c_char;
4164 let reader = xmlReaderForMemory(
4165 data,
4166 7,
4167 ptr::null(),
4168 ptr::null(),
4169 XML_PARSE_NOENT | XML_PARSE_DTDLOAD,
4170 );
4171 assert!(!reader.is_null());
4172
4173 assert_eq!((*reader).options & XML_PARSE_NOENT, XML_PARSE_NOENT);
4175 assert_eq!((*reader).options & XML_PARSE_DTDLOAD, XML_PARSE_DTDLOAD);
4176
4177 assert_eq!(xmlTextReaderRead(reader), 1);
4178 free_reader(reader);
4179 }
4180 }
4181
4182 #[test]
4183 fn test_reader_for_fd() {
4184 unsafe {
4185 let tmp_path = "/tmp/libxml_rs_test_reader_fd.xml";
4187 let tmp_cstr = std::ffi::CString::new(tmp_path).unwrap();
4188 let content = b"<root><data/></root>";
4189 let fd = libc::open(
4190 tmp_cstr.as_ptr(),
4191 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
4192 0o644,
4193 );
4194 assert!(fd >= 0);
4195 libc::write(fd, content.as_ptr() as *const c_void, content.len());
4196 libc::close(fd);
4197
4198 let fd = libc::open(tmp_cstr.as_ptr(), libc::O_RDONLY, 0);
4200 assert!(fd >= 0);
4201
4202 let reader = xmlReaderForFd(fd, ptr::null(), ptr::null(), 0);
4203 assert!(!reader.is_null());
4204
4205 let nodes = collect_nodes(reader);
4206 assert_eq!(nodes.len(), 3);
4209
4210 free_reader(reader);
4211 libc::close(fd);
4212 std::fs::remove_file(tmp_path).ok();
4213 }
4214 }
4215
4216 #[test]
4217 fn test_reader_for_io() {
4218 unsafe {
4219 extern "C" fn io_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
4220 if context.is_null() || buffer.is_null() || len <= 0 {
4221 return -1;
4222 }
4223 let ctx = unsafe { &mut *(context as *mut IoCtx) };
4225 if ctx.pos >= ctx.data.len() {
4226 return 0;
4227 }
4228 let remaining = ctx.data.len() - ctx.pos;
4229 let to_copy = if (remaining as c_int) < len {
4230 remaining
4231 } else {
4232 len as usize
4233 };
4234 unsafe {
4236 std::ptr::copy_nonoverlapping(
4237 ctx.data.as_ptr().add(ctx.pos),
4238 buffer as *mut u8,
4239 to_copy,
4240 );
4241 }
4242 ctx.pos += to_copy;
4243 to_copy as c_int
4244 }
4245
4246 extern "C" fn io_close(_context: *mut c_void) -> c_int {
4247 0
4248 }
4249
4250 struct IoCtx {
4251 data: &'static [u8],
4252 pos: usize,
4253 }
4254 let mut ctx = IoCtx {
4255 data: b"<root/>",
4256 pos: 0,
4257 };
4258
4259 let reader = xmlReaderForIO(
4260 Some(io_read),
4261 Some(io_close),
4262 &mut ctx as *mut IoCtx as *mut c_void,
4263 ptr::null(),
4264 ptr::null(),
4265 0,
4266 );
4267 assert!(!reader.is_null());
4268
4269 assert_eq!(xmlTextReaderRead(reader), 1);
4271 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4272 let cname = xmlTextReaderConstName(reader);
4273 assert!(!cname.is_null());
4274 assert_eq!(xmlstr_to_bytes(cname), b"root");
4275
4276 assert_eq!(xmlTextReaderRead(reader), 0);
4279
4280 free_reader(reader);
4281 }
4282 }
4283}
4284
4285pub const XML_PARSER_SEVERITY_VALIDITY_WARNING: c_int = 1;
4291pub const XML_PARSER_SEVERITY_VALIDITY_ERROR: c_int = 2;
4292pub const XML_PARSER_SEVERITY_WARNING: c_int = 3;
4293pub const XML_PARSER_SEVERITY_ERROR: c_int = 4;
4294
4295#[repr(C)]
4298pub struct XmlTextReaderLocator {
4299 pub reader: *mut XmlTextReader,
4300}
4301
4302pub type xmlTextReaderErrorFunc = unsafe extern "C" fn(
4304 arg: *mut c_void,
4305 msg: *const c_char,
4306 severity: c_int,
4307 locator: *mut XmlTextReaderLocator,
4308);
4309
4310#[no_mangle]
4317pub unsafe extern "C" fn xmlReaderForDoc(
4318 cur: *const xmlChar,
4319 URL: *const c_char,
4320 encoding: *const c_char,
4321 options: c_int,
4322) -> *mut XmlTextReader {
4323 if cur.is_null() {
4324 return ptr::null_mut();
4325 }
4326 let len = unsafe { libc::strlen(cur as *const libc::c_char) } as c_int;
4327 unsafe { xmlReaderForMemory(cur as *const c_char, len, URL, encoding, options) }
4328}
4329
4330#[no_mangle]
4332pub unsafe extern "C" fn xmlNewTextReaderFilename(
4333 URI: *const c_char,
4334 encoding: *const c_char,
4335 options: c_int,
4336) -> *mut XmlTextReader {
4337 unsafe { xmlReaderForFile(URI, encoding, options) }
4338}
4339
4340unsafe fn reader_renew(reader: *mut XmlTextReader, new_reader: *mut XmlTextReader) {
4352 debug_assert!(!reader.is_null() && !new_reader.is_null() && reader != new_reader);
4353 unsafe {
4354 core::ptr::drop_in_place(reader);
4358 core::ptr::copy_nonoverlapping(new_reader, reader, 1);
4359 let layout = std::alloc::Layout::new::<XmlTextReader>();
4360 std::alloc::dealloc(new_reader as *mut u8, layout);
4361 }
4362}
4363
4364#[no_mangle]
4366pub unsafe extern "C" fn xmlReaderNewDoc(
4367 reader: *mut XmlTextReader,
4368 cur: *const xmlChar,
4369 URL: *const c_char,
4370 encoding: *const c_char,
4371 options: c_int,
4372) -> c_int {
4373 if reader.is_null() || cur.is_null() {
4376 return -1;
4377 }
4378 let r = unsafe { xmlReaderForDoc(cur, URL, encoding, options) };
4379 if r.is_null() {
4380 return -1;
4381 }
4382 unsafe { reader_renew(reader, r) };
4383 0
4384}
4385
4386#[no_mangle]
4388pub unsafe extern "C" fn xmlReaderNewFile(
4389 reader: *mut XmlTextReader,
4390 filename: *const c_char,
4391 encoding: *const c_char,
4392 options: c_int,
4393) -> c_int {
4394 if reader.is_null() {
4395 return -1;
4396 }
4397 let r = unsafe { xmlReaderForFile(filename, encoding, options) };
4398 if r.is_null() {
4399 return -1;
4400 }
4401 unsafe { reader_renew(reader, r) };
4402 0
4403}
4404
4405#[no_mangle]
4407pub unsafe extern "C" fn xmlReaderNewMemory(
4408 reader: *mut XmlTextReader,
4409 buffer: *const c_char,
4410 size: c_int,
4411 URL: *const c_char,
4412 encoding: *const c_char,
4413 options: c_int,
4414) -> c_int {
4415 if reader.is_null() || buffer.is_null() {
4416 return -1;
4417 }
4418 let r = unsafe { xmlReaderForMemory(buffer, size, URL, encoding, options) };
4419 if r.is_null() {
4420 return -1;
4421 }
4422 unsafe { reader_renew(reader, r) };
4423 0
4424}
4425
4426#[no_mangle]
4428pub unsafe extern "C" fn xmlReaderNewFd(
4429 reader: *mut XmlTextReader,
4430 fd: c_int,
4431 URL: *const c_char,
4432 encoding: *const c_char,
4433 options: c_int,
4434) -> c_int {
4435 if reader.is_null() {
4436 return -1;
4437 }
4438 let r = unsafe { xmlReaderForFd(fd, URL, encoding, options) };
4439 if r.is_null() {
4440 return -1;
4441 }
4442 unsafe { reader_renew(reader, r) };
4443 0
4444}
4445
4446#[no_mangle]
4448pub unsafe extern "C" fn xmlReaderNewIO(
4449 reader: *mut XmlTextReader,
4450 ioread: Option<xmlInputReadCallback>,
4451 ioclose: Option<xmlInputCloseCallback>,
4452 ioctx: *mut c_void,
4453 URL: *const c_char,
4454 encoding: *const c_char,
4455 options: c_int,
4456) -> c_int {
4457 if reader.is_null() || ioread.is_none() {
4459 return -1;
4460 }
4461 let r = unsafe { xmlReaderForIO(ioread, ioclose, ioctx, URL, encoding, options) };
4462 if r.is_null() {
4463 return -1;
4464 }
4465 unsafe { reader_renew(reader, r) };
4466 0
4467}
4468
4469#[no_mangle]
4476pub unsafe extern "C" fn xmlReaderWalker(doc: *mut _xmlDoc) -> *mut XmlTextReader {
4477 if doc.is_null() {
4478 return ptr::null_mut();
4479 }
4480 let mut reader = XmlTextReader::new(ptr::null_mut(), None, None);
4481 reader.doc = doc;
4482 reader.parsed = true;
4483 reader.owns_doc = false; reader.state = ReadState::READING;
4485 reader.build_events();
4486 Box::into_raw(Box::new(reader))
4487}
4488
4489#[no_mangle]
4491pub unsafe extern "C" fn xmlReaderNewWalker(
4492 reader: *mut XmlTextReader,
4493 doc: *mut _xmlDoc,
4494) -> c_int {
4495 if reader.is_null() || doc.is_null() {
4497 return -1;
4498 }
4499 let r = unsafe { xmlReaderWalker(doc) };
4500 if r.is_null() {
4501 return -1;
4502 }
4503 unsafe { reader_renew(reader, r) };
4504 0
4505}
4506
4507#[no_mangle]
4512pub unsafe extern "C" fn xmlTextReaderByteConsumed(reader: *mut XmlTextReader) -> c_long {
4513 if reader.is_null() {
4514 return -1;
4515 }
4516 0
4517}
4518
4519#[no_mangle]
4522pub unsafe extern "C" fn xmlTextReaderConstBaseUri(reader: *mut XmlTextReader) -> *const xmlChar {
4523 if reader.is_null() {
4524 return ptr::null();
4525 }
4526 unsafe { (*reader).URL }
4527}
4528
4529#[no_mangle]
4531pub unsafe extern "C" fn xmlTextReaderConstEncoding(reader: *mut XmlTextReader) -> *const xmlChar {
4532 if reader.is_null() {
4533 return ptr::null();
4534 }
4535 let r = unsafe { &*reader };
4536 if !r.encoding.is_null() {
4537 return r.encoding;
4538 }
4539 if !r.doc.is_null() {
4540 return unsafe { (*r.doc).encoding };
4541 }
4542 ptr::null()
4543}
4544
4545#[no_mangle]
4551pub unsafe extern "C" fn xmlTextReaderConstLocalName(reader: *mut XmlTextReader) -> *const xmlChar {
4552 if reader.is_null() {
4553 return ptr::null();
4554 }
4555 let r = unsafe { &*reader };
4556 if r.cur_node.is_null() {
4557 return ptr::null();
4558 }
4559 if r.cur_attribute >= 0 {
4562 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4563 return match target {
4564 AttrTarget::Ns(ns) => {
4565 if ns.is_null() {
4566 ptr::null()
4567 } else if unsafe { (*ns).prefix }.is_null() {
4568 b"xmlns\0".as_ptr() as *const xmlChar
4569 } else {
4570 unsafe { (*ns).prefix }
4571 }
4572 }
4573 AttrTarget::Prop(p) => {
4574 if p.is_null() || unsafe { (*p).name }.is_null() {
4575 ptr::null()
4576 } else {
4577 unsafe { (*p).name }
4578 }
4579 }
4580 AttrTarget::None => ptr::null(),
4581 };
4582 }
4583 let etype = unsafe { (*r.cur_node).type_ };
4585 if etype == XML_ELEMENT_NODE as c_int || etype == XML_ATTRIBUTE_NODE as c_int {
4586 unsafe { (*r.cur_node).name }
4587 } else {
4588 ptr::null()
4589 }
4590}
4591
4592#[no_mangle]
4597pub unsafe extern "C" fn xmlTextReaderConstNamespaceUri(
4598 reader: *mut XmlTextReader,
4599) -> *const xmlChar {
4600 if reader.is_null() {
4601 return ptr::null();
4602 }
4603 let r = unsafe { &*reader };
4604 if r.cur_node.is_null() {
4605 return ptr::null();
4606 }
4607 if r.cur_attribute >= 0 {
4609 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4610 return match target {
4611 AttrTarget::Ns(_ns) => {
4612 b"http://www.w3.org/2000/xmlns/\0".as_ptr() as *const xmlChar
4616 }
4617 AttrTarget::Prop(p) => {
4618 if p.is_null() || unsafe { (*p).ns }.is_null() {
4619 ptr::null()
4620 } else {
4621 unsafe { (*(*p).ns).href }
4622 }
4623 }
4624 AttrTarget::None => ptr::null(),
4625 };
4626 }
4627 let ns = unsafe { (*r.cur_node).ns };
4628 if ns.is_null() || unsafe { (*ns).href }.is_null() {
4629 ptr::null()
4630 } else {
4631 unsafe { (*ns).href }
4632 }
4633}
4634
4635#[no_mangle]
4641pub unsafe extern "C" fn xmlTextReaderConstPrefix(reader: *mut XmlTextReader) -> *const xmlChar {
4642 if reader.is_null() {
4643 return ptr::null();
4644 }
4645 let r = unsafe { &*reader };
4646 if r.cur_node.is_null() {
4647 return ptr::null();
4648 }
4649 if r.cur_attribute >= 0 {
4651 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4652 return match target {
4653 AttrTarget::Ns(ns) => {
4654 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4655 ptr::null()
4656 } else {
4657 b"xmlns\0".as_ptr() as *const xmlChar
4658 }
4659 }
4660 AttrTarget::Prop(p) => {
4661 if p.is_null() || unsafe { (*p).ns }.is_null() {
4662 ptr::null()
4663 } else {
4664 unsafe { (*(*p).ns).prefix }
4665 }
4666 }
4667 AttrTarget::None => ptr::null(),
4668 };
4669 }
4670 let ns = unsafe { (*r.cur_node).ns };
4671 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4672 ptr::null()
4673 } else {
4674 unsafe { (*ns).prefix }
4675 }
4676}
4677
4678#[no_mangle]
4682pub unsafe extern "C" fn xmlTextReaderConstString(
4683 _reader: *mut XmlTextReader,
4684 str: *const xmlChar,
4685) -> *const xmlChar {
4686 str
4687}
4688
4689#[no_mangle]
4691pub unsafe extern "C" fn xmlTextReaderConstXmlLang(reader: *mut XmlTextReader) -> *const xmlChar {
4692 if reader.is_null() {
4693 return ptr::null();
4694 }
4695 let r = unsafe { &*reader };
4696 let mut node = r.cur_node;
4697 while !node.is_null() {
4698 let mut prop = unsafe { (*node).properties };
4699 while !prop.is_null() {
4700 let p = unsafe { &*prop };
4701 if !p.name.is_null()
4702 && unsafe { *p.name } == b'x'
4703 && unsafe { *p.name.add(1) } == b'm'
4704 && unsafe { *p.name.add(2) } == b'l'
4705 && unsafe { *p.name.add(3) } == b':'
4706 && unsafe { *p.name.add(4) } == b'l'
4707 && unsafe { *p.name.add(5) } == b'a'
4708 && unsafe { *p.name.add(6) } == b'n'
4709 && unsafe { *p.name.add(7) } == b'g'
4710 && unsafe { *p.name.add(8) } == 0
4711 {
4712 if !p.children.is_null() {
4713 let txt = p.children;
4714 if unsafe { (*txt).type_ }
4715 == crate::abi::types::xmlElementType::XML_TEXT_NODE as c_int
4716 {
4717 return unsafe { (*txt).content };
4718 }
4719 }
4720 return ptr::null();
4721 }
4722 prop = p.next;
4723 }
4724 node = unsafe { (*node).parent };
4725 }
4726 ptr::null()
4727}
4728
4729#[no_mangle]
4731pub unsafe extern "C" fn xmlTextReaderConstXmlVersion(
4732 reader: *mut XmlTextReader,
4733) -> *const xmlChar {
4734 if reader.is_null() {
4735 return ptr::null();
4736 }
4737 let r = unsafe { &*reader };
4738 if r.doc.is_null() {
4739 return ptr::null();
4740 }
4741 unsafe { (*r.doc).version }
4742}
4743
4744#[no_mangle]
4751pub unsafe extern "C" fn xmlTextReaderQuoteChar(reader: *mut XmlTextReader) -> c_int {
4752 if reader.is_null() {
4753 return -1;
4754 }
4755 b'"' as c_int
4756}
4757
4758#[no_mangle]
4763pub unsafe extern "C" fn xmlTextReaderIsDefault(reader: *mut XmlTextReader) -> c_int {
4764 if reader.is_null() {
4765 return -1;
4766 }
4767 0
4768}
4769
4770#[no_mangle]
4773pub unsafe extern "C" fn xmlTextReaderIsNamespaceDecl(reader: *mut XmlTextReader) -> c_int {
4774 if reader.is_null() {
4775 return -1;
4776 }
4777 let r = unsafe { &*reader };
4778 if r.cur_node.is_null() {
4779 return -1;
4780 }
4781 r.cur_attr_is_ns as c_int
4782}
4783
4784#[no_mangle]
4797pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNs(
4798 reader: *mut XmlTextReader,
4799 localName: *const xmlChar,
4800 namespaceURI: *const xmlChar,
4801) -> c_int {
4802 if reader.is_null() || localName.is_null() || namespaceURI.is_null() {
4803 return -1;
4804 }
4805 let r = unsafe { &mut *reader };
4806 let node = r.cur_node;
4807 if node.is_null() {
4808 return -1;
4809 }
4810 if unsafe { (*node).type_ } != XML_ELEMENT_NODE as c_int {
4811 return 0;
4812 }
4813
4814 const XMLNS_URI: &[u8] = b"http://www.w3.org/2000/xmlns/\0";
4815 if libc::strcmp(
4816 namespaceURI as *const libc::c_char,
4817 XMLNS_URI.as_ptr() as *const libc::c_char,
4818 ) == 0
4819 {
4820 let is_default = libc::strcmp(
4823 localName as *const libc::c_char,
4824 b"xmlns\0".as_ptr() as *const libc::c_char,
4825 ) == 0;
4826 let mut ns = unsafe { (*node).nsDef };
4827 let mut index = 0;
4828 while !ns.is_null() {
4829 let n = unsafe { &*ns };
4830 let prefix_match = if is_default {
4831 n.prefix.is_null()
4832 } else {
4833 !n.prefix.is_null()
4834 && libc::strcmp(
4835 n.prefix as *const libc::c_char,
4836 localName as *const libc::c_char,
4837 ) == 0
4838 };
4839 if prefix_match {
4840 r.cur_attribute = index;
4841 r.node_type = ReaderNodeType::ATTRIBUTE;
4842 r.cache_attribute_info(AttrTarget::Ns(ns));
4843 return 1;
4844 }
4845 index += 1;
4846 ns = unsafe { (*ns).next };
4847 }
4848 return 0;
4849 }
4850
4851 let mut prop = unsafe { (*node).properties };
4853 let mut index = 0;
4854 let mut ns_count = 0;
4855 let mut ns = unsafe { (*node).nsDef };
4856 while !ns.is_null() {
4857 ns_count += 1;
4858 ns = unsafe { (*ns).next };
4859 }
4860 while !prop.is_null() {
4861 let p = unsafe { &*prop };
4862 if !p.name.is_null()
4863 && !p.ns.is_null()
4864 && !(*p.ns).href.is_null()
4865 && libc::strcmp(
4866 p.name as *const libc::c_char,
4867 localName as *const libc::c_char,
4868 ) == 0
4869 && libc::strcmp(
4870 (*p.ns).href as *const libc::c_char,
4871 namespaceURI as *const libc::c_char,
4872 ) == 0
4873 {
4874 r.cur_attribute = ns_count + index;
4875 r.node_type = ReaderNodeType::ATTRIBUTE;
4876 r.cache_attribute_info(AttrTarget::Prop(prop));
4877 return 1;
4878 }
4879 index += 1;
4880 prop = unsafe { (*prop).next };
4881 }
4882 0
4883}
4884
4885#[no_mangle]
4889pub unsafe extern "C" fn xmlTextReaderPreserve(reader: *mut XmlTextReader) -> *mut _xmlNode {
4890 if reader.is_null() {
4891 return ptr::null_mut();
4892 }
4893 unsafe { (*reader).cur_node }
4894}
4895
4896#[no_mangle]
4901pub unsafe extern "C" fn xmlTextReaderPreservePattern(
4902 reader: *mut XmlTextReader,
4903 _pattern: *const xmlChar,
4904 _namespaces: *mut *const xmlChar,
4905) -> c_int {
4906 if reader.is_null() {
4907 return -1;
4908 }
4909 0
4910}
4911
4912#[no_mangle]
4918pub unsafe extern "C" fn xmlTextReaderSetErrorHandler(
4919 reader: *mut XmlTextReader,
4920 f: Option<xmlTextReaderErrorFunc>,
4921 arg: *mut c_void,
4922) {
4923 if reader.is_null() {
4924 return;
4925 }
4926 unsafe {
4927 (*reader).error_handler = f;
4928 (*reader).error_arg = arg;
4929 }
4930}
4931
4932#[no_mangle]
4938pub unsafe extern "C" fn xmlTextReaderGetErrorHandler(
4939 reader: *mut XmlTextReader,
4940 f: *mut Option<xmlTextReaderErrorFunc>,
4941 arg: *mut *mut c_void,
4942) {
4943 if reader.is_null() {
4944 return;
4945 }
4946 unsafe {
4947 if !f.is_null() {
4948 *f = (*reader).error_handler;
4949 }
4950 if !arg.is_null() {
4951 *arg = (*reader).error_arg;
4952 }
4953 }
4954}
4955
4956#[no_mangle]
4958pub unsafe extern "C" fn xmlTextReaderSetStructuredErrorHandler(
4959 reader: *mut XmlTextReader,
4960 f: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4961 arg: *mut c_void,
4962) {
4963 if reader.is_null() {
4964 return;
4965 }
4966 unsafe {
4967 (*reader).structured_handler = f;
4968 (*reader).structured_arg = arg;
4969 }
4970}
4971
4972#[no_mangle]
4977pub unsafe extern "C" fn xmlTextReaderSetResourceLoader(
4978 reader: *mut XmlTextReader,
4979 loader: Option<crate::abi::callbacks::xmlResourceLoader>,
4980 data: *mut c_void,
4981) {
4982 if reader.is_null() {
4983 return;
4984 }
4985 unsafe {
4986 if !(*reader).ctxt.is_null() {
4987 crate::abi::exports_parserint::xmlCtxtSetResourceLoader((*reader).ctxt, loader, data);
4988 }
4989 }
4990}
4991
4992#[no_mangle]
4997pub unsafe extern "C" fn xmlTextReaderGetLastError(
4998 reader: *mut XmlTextReader,
4999) -> *const crate::abi::structs::_xmlError {
5000 if reader.is_null() {
5001 return ptr::null();
5002 }
5003 let r = unsafe { &mut *reader };
5004 if let Some(msg) = r.errors.last() {
5008 unsafe {
5009 let bytes = msg.as_bytes();
5012 let m = libc::malloc(bytes.len() + 1) as *mut xmlChar;
5013 if !m.is_null() {
5014 libc::memcpy(
5015 m as *mut libc::c_void,
5016 bytes.as_ptr() as *const libc::c_void,
5017 bytes.len(),
5018 );
5019 *m.add(bytes.len()) = 0;
5020 if !r.last_err.message.is_null() {
5021 libc::free(r.last_err.message as *mut libc::c_void);
5022 }
5023 (*reader).last_err.message = m as *mut c_char;
5024 (*reader).last_err.domain = crate::abi::types::XML_FROM_PARSER as c_int;
5025 (*reader).last_err.level = crate::abi::types::xmlErrorLevel::XML_ERR_ERROR as c_int;
5026 (*reader).last_err.code = crate::abi::types::XML_ERR_INTERNAL_ERROR as c_int;
5027 }
5028 }
5029 }
5030 &(*reader).last_err as *const crate::abi::structs::_xmlError
5031}
5032
5033#[no_mangle]
5039pub unsafe extern "C" fn xmlTextReaderLocatorBaseURI(
5040 locator: *mut XmlTextReaderLocator,
5041) -> *mut xmlChar {
5042 if locator.is_null() {
5043 return ptr::null_mut();
5044 }
5045 unsafe {
5046 let r = (*locator).reader;
5047 if r.is_null() {
5048 return ptr::null_mut();
5049 }
5050 xml_strdup((*r).URL)
5051 }
5052}
5053
5054#[no_mangle]
5056pub unsafe extern "C" fn xmlTextReaderLocatorLineNumber(
5057 locator: *mut XmlTextReaderLocator,
5058) -> c_int {
5059 if locator.is_null() {
5060 return -1;
5061 }
5062 unsafe {
5063 let r = (*locator).reader;
5064 if r.is_null() {
5065 return -1;
5066 }
5067 let node = (*r).cur_node;
5068 if node.is_null() {
5069 return -1;
5070 }
5071 (*node).line as c_int
5072 }
5073}
5074
5075#[no_mangle]
5080pub unsafe extern "C" fn xmlTextReaderGetRemainder(
5081 _reader: *mut XmlTextReader,
5082) -> *mut crate::abi::structs::_xmlParserInputBuffer {
5083 ptr::null_mut()
5084}
5085
5086#[no_mangle]
5088pub unsafe extern "C" fn xmlTextReaderSetMaxAmplification(
5089 reader: *mut XmlTextReader,
5090 maxAmpl: c_uint,
5091) {
5092 if reader.is_null() {
5093 return;
5094 }
5095 unsafe { (*reader).max_amplification = maxAmpl as c_int };
5096}
5097
5098#[no_mangle]
5105pub unsafe extern "C" fn xmlTextReaderSchemaValidate(
5106 reader: *mut XmlTextReader,
5107 xsd: *const c_char,
5108) -> c_int {
5109 if reader.is_null() || xsd.is_null() {
5110 return -1;
5111 }
5112 if unsafe { (*reader).doc }.is_null() {
5114 if unsafe { (*reader).parsed } == false {
5115 unsafe { (*reader).Read() };
5116 }
5117 }
5118 let ctxt = crate::xml::schemas::xmlSchemaNewParserCtxt(xsd);
5119 if ctxt.is_null() {
5120 return -1;
5121 }
5122 let schema = crate::xml::schemas::xmlSchemaParse(ctxt);
5123 if schema.is_null() {
5124 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5125 return -1;
5126 }
5127 let vctxt = crate::xml::schemas::xmlSchemaNewValidCtxt(schema);
5128 if vctxt.is_null() {
5129 crate::xml::schemas::xmlSchemaFree(schema);
5130 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5131 return -1;
5132 }
5133 let ret = crate::xml::schemas::xmlSchemaValidateDoc(vctxt, unsafe { (*reader).doc });
5134 crate::xml::schemas::xmlSchemaFreeValidCtxt(vctxt);
5135 crate::xml::schemas::xmlSchemaFree(schema);
5136 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5137 ret
5138}
5139
5140#[no_mangle]
5142pub unsafe extern "C" fn xmlTextReaderSchemaValidateCtxt(
5143 reader: *mut XmlTextReader,
5144 ctxt: *mut c_void,
5145 _options: c_int,
5146) -> c_int {
5147 if reader.is_null() || ctxt.is_null() {
5148 return -1;
5149 }
5150 if unsafe { (*reader).doc }.is_null() {
5151 if unsafe { (*reader).parsed } == false {
5152 unsafe { (*reader).Read() };
5153 }
5154 }
5155 crate::xml::schemas::xmlSchemaValidateDoc(ctxt, unsafe { (*reader).doc })
5156}
5157
5158#[no_mangle]
5160pub unsafe extern "C" fn xmlTextReaderSetSchema(
5161 reader: *mut XmlTextReader,
5162 schema: *mut c_void,
5163) -> c_int {
5164 if reader.is_null() {
5165 return -1;
5166 }
5167 unsafe {
5168 (*reader).schema = schema;
5169 }
5170 0
5171}
5172
5173#[no_mangle]
5175pub unsafe extern "C" fn xmlTextReaderRelaxNGValidate(
5176 reader: *mut XmlTextReader,
5177 rng: *const c_char,
5178) -> c_int {
5179 if reader.is_null() || rng.is_null() {
5180 return -1;
5181 }
5182 if unsafe { (*reader).doc }.is_null() {
5183 if unsafe { (*reader).parsed } == false {
5184 unsafe { (*reader).Read() };
5185 }
5186 }
5187 let ctxt = crate::xml::relaxng::xmlRelaxNGNewParserCtxt(rng);
5188 if ctxt.is_null() {
5189 return -1;
5190 }
5191 let schema = crate::xml::relaxng::xmlRelaxNGParse(ctxt);
5192 if schema.is_null() {
5193 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5194 return -1;
5195 }
5196 let vctxt = crate::xml::relaxng::xmlRelaxNGNewValidCtxt(schema);
5197 if vctxt.is_null() {
5198 crate::xml::relaxng::xmlRelaxNGFree(schema);
5199 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5200 return -1;
5201 }
5202 let ret = crate::xml::relaxng::xmlRelaxNGValidateDoc(vctxt, unsafe { (*reader).doc });
5203 crate::xml::relaxng::xmlRelaxNGFreeValidCtxt(vctxt);
5204 crate::xml::relaxng::xmlRelaxNGFree(schema);
5205 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5206 ret
5207}
5208
5209#[no_mangle]
5211pub unsafe extern "C" fn xmlTextReaderRelaxNGValidateCtxt(
5212 reader: *mut XmlTextReader,
5213 ctxt: *mut c_void,
5214 _options: c_int,
5215) -> c_int {
5216 if reader.is_null() || ctxt.is_null() {
5217 return -1;
5218 }
5219 if unsafe { (*reader).doc }.is_null() {
5220 if unsafe { (*reader).parsed } == false {
5221 unsafe { (*reader).Read() };
5222 }
5223 }
5224 crate::xml::relaxng::xmlRelaxNGValidateDoc(ctxt, unsafe { (*reader).doc })
5225}
5226
5227#[no_mangle]
5229pub unsafe extern "C" fn xmlTextReaderRelaxNGSetSchema(
5230 reader: *mut XmlTextReader,
5231 schema: *mut c_void,
5232) -> c_int {
5233 if reader.is_null() {
5234 return -1;
5235 }
5236 unsafe {
5237 (*reader).rng = schema;
5238 }
5239 0
5240}