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::xmlFree;
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 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 = crate::abi::allocator::xmlMalloc(plen + 1 + nlen + 1) as *mut xmlChar;
609 if !p.is_null() {
610 libc::memcpy(
611 p as *mut libc::c_void,
612 unsafe { (*ns).prefix } as *const libc::c_void,
613 plen,
614 );
615 *p.add(plen) = b':';
616 libc::memcpy(
617 p.add(plen + 1) as *mut libc::c_void,
618 name as *const libc::c_void,
619 nlen,
620 );
621 *p.add(plen + 1 + nlen) = 0;
622 }
623 p
624 } else {
625 unsafe { xml_strdup(name as *const xmlChar) }
626 }
627 } else {
628 unsafe { xml_strdup(name as *const xmlChar) }
629 };
630 self.name = qualified;
631 } else if !is_end {
632 let fixed: &[u8] = match etype {
635 x if x == XML_TEXT_NODE as c_int => b"#text\0",
636 x if x == XML_CDATA_SECTION_NODE as c_int => b"#cdata-section\0",
637 x if x == XML_COMMENT_NODE as c_int => b"#comment\0",
638 x if x == XML_DOCUMENT_NODE as c_int => b"#document\0",
639 x if x == XML_HTML_DOCUMENT_NODE as c_int => b"#document\0",
640 x if x == XML_DOCUMENT_FRAG_NODE as c_int => b"#document-fragment\0",
641 _ => b"",
642 };
643 if !fixed.is_empty() {
644 self.name = unsafe { xml_strdup(fixed.as_ptr() as *const xmlChar) };
645 }
646 }
647
648 let value: *mut xmlChar = if etype == XML_TEXT_NODE as c_int
650 || etype == XML_CDATA_SECTION_NODE as c_int
651 || etype == XML_COMMENT_NODE as c_int
652 {
653 unsafe { (*node).content }
655 } else if etype == XML_PI_NODE as c_int {
656 unsafe { (*node).content }
659 } else if etype == XML_ENTITY_REF_NODE as c_int {
660 unsafe { (*node).content }
663 } else {
664 ptr::null_mut()
665 };
666
667 if !value.is_null() {
668 self.value = unsafe { xml_strdup(value as *const xmlChar) };
670 }
671 }
672
673 unsafe fn count_attributes(&self, node: *mut _xmlNode) -> i32 {
679 let mut count: i32 = 0;
680 let mut ns = unsafe { (*node).nsDef };
683 while !ns.is_null() {
684 count += 1;
685 ns = unsafe { (*ns).next };
686 }
687 let mut prop = unsafe { (*node).properties };
689 while !prop.is_null() {
690 count += 1;
691 prop = unsafe { (*prop).next };
693 }
694 count
695 }
696
697 unsafe fn attr_at(&self, node: *mut _xmlNode, index: i32) -> AttrTarget {
700 if node.is_null() || index < 0 {
701 return AttrTarget::None;
702 }
703 let mut i = 0;
704 let mut ns = unsafe { (*node).nsDef };
705 while !ns.is_null() {
706 if i == index {
707 return AttrTarget::Ns(ns);
708 }
709 i += 1;
710 ns = unsafe { (*ns).next };
711 }
712 let mut prop = unsafe { (*node).properties };
713 while !prop.is_null() {
714 if i == index {
715 return AttrTarget::Prop(prop);
716 }
717 i += 1;
718 prop = unsafe { (*prop).next };
719 }
720 AttrTarget::None
721 }
722
723 unsafe fn attr_index_by_name(&self, node: *mut _xmlNode, name: *const xmlChar) -> i32 {
726 if node.is_null() || name.is_null() {
727 return -1;
728 }
729 let mut i = 0;
730 let mut ns = unsafe { (*node).nsDef };
731 while !ns.is_null() {
732 let n = unsafe { &*ns };
733 let nsname: Vec<u8> = if n.prefix.is_null() {
734 b"xmlns\0".to_vec()
735 } else {
736 let mut v = b"xmlns:\0".to_vec();
737 let plen = libc::strlen(n.prefix as *const libc::c_char) as usize;
738 v.extend_from_slice(core::slice::from_raw_parts(n.prefix, plen));
739 v.push(0);
740 v
741 };
742 let nlen = libc::strlen(name as *const libc::c_char) as usize;
743 let nbytes = core::slice::from_raw_parts(name as *const u8, nlen);
744 if nbytes == &nsname[..nsname.len() - 1] {
745 return i;
746 }
747 i += 1;
748 ns = unsafe { (*ns).next };
749 }
750 let mut prop = unsafe { (*node).properties };
751 while !prop.is_null() {
752 let pn = unsafe { (*prop).name };
753 if !pn.is_null()
754 && libc::strcmp(pn as *const libc::c_char, name as *const libc::c_char) == 0
755 {
756 return i;
757 }
758 i += 1;
759 prop = unsafe { (*prop).next };
760 }
761 -1
762 }
763
764 fn clear_cached_name(&mut self) {
766 if !self.name.is_null() {
767 unsafe { xmlFree(self.name as *mut c_void) };
769 self.name = ptr::null_mut();
770 }
771 }
772
773 fn clear_cached_value(&mut self) {
775 if !self.value.is_null() {
776 unsafe { xmlFree(self.value as *mut c_void) };
778 self.value = ptr::null_mut();
779 }
780 }
781
782 pub unsafe fn Read(&mut self) -> c_int {
790 if self.state == ReadState::ERROR || self.state == ReadState::CLOSED {
791 return -1;
792 }
793
794 if !self.parsed {
796 if self.parse_and_build_events() != 0 {
797 self.state = ReadState::ERROR;
798 return -1;
799 }
800 self.state = ReadState::READING;
801 }
802
803 if self.state == ReadState::EOF {
804 return 0;
805 }
806
807 if self.cur_attribute >= 0 {
809 self.cur_attribute = -1;
810 self.cur_attr_is_ns = false;
811 if !self.cur_node.is_null() {
813 unsafe { self.cache_name_and_value(self.cur_node, false) };
815 }
816 }
817
818 if self.events.is_empty() {
821 self.state = ReadState::EOF;
822 return 0;
823 }
824
825 let next_index = if self.cur_node.is_null() {
832 0
834 } else {
835 self.event_index + 1
836 };
837
838 if next_index < self.events.len() {
839 self.position_at(next_index);
840 1
841 } else {
842 self.state = ReadState::EOF;
843 self.cur_node = ptr::null_mut();
844 self.node_type = ReaderNodeType::NONE;
845 self.depth = 0;
846 self.clear_cached_name();
847 self.clear_cached_value();
848 self.attribute_count = -1;
849 self.cur_attribute = -1;
850 0
851 }
852 }
853
854 pub unsafe fn Next(&mut self) -> c_int {
858 if self.state != ReadState::READING || self.cur_node.is_null() {
859 return -1;
860 }
861
862 let current_depth = self.depth;
868 let mut i = self.event_index + 1;
869
870 while i < self.events.len() {
871 let event = &self.events[i];
872 if event.depth <= current_depth && !event.is_end {
873 self.position_at(i);
874 return 1;
875 }
876 i += 1;
877 }
878
879 0
880 }
881
882 pub unsafe fn MoveToElement(&mut self) -> c_int {
886 if self.cur_attribute < 0 {
887 return 0;
888 }
889 self.cur_attribute = -1;
890 self.cur_attr_is_ns = false;
891 if !self.cur_node.is_null() {
892 unsafe { self.cache_name_and_value(self.cur_node, false) };
894 self.node_type = ReaderNodeType::ELEMENT;
895 }
896 1
897 }
898
899 pub unsafe fn MoveToAttribute(&mut self, name: *const xmlChar) -> c_int {
903 if self.cur_node.is_null() {
904 return -1;
905 }
906
907 let etype = unsafe { (*self.cur_node).type_ };
909 if etype != XML_ELEMENT_NODE as c_int {
910 return -1;
911 }
912
913 let idx = unsafe { self.attr_index_by_name(self.cur_node, name) };
915 if idx < 0 {
916 return 0;
917 }
918 self.cur_attribute = idx;
919 let target = unsafe { self.attr_at(self.cur_node, idx) };
920 unsafe { self.cache_attribute_info(target) };
922 1
923 }
924
925 pub unsafe fn MoveToAttributeNo(&mut self, index: c_int) -> c_int {
929 if self.cur_node.is_null() || index < 0 {
930 return -1;
931 }
932
933 let etype = unsafe { (*self.cur_node).type_ };
935 if etype != XML_ELEMENT_NODE as c_int {
936 return -1;
937 }
938
939 let target = unsafe { self.attr_at(self.cur_node, index) };
941 match target {
942 AttrTarget::None => 0,
943 t => {
944 self.cur_attribute = index;
945 unsafe { self.cache_attribute_info(t) };
947 1
948 }
949 }
950 }
951
952 pub unsafe fn MoveToFirstAttribute(&mut self) -> c_int {
956 if self.cur_node.is_null() {
957 return -1;
958 }
959
960 let etype = unsafe { (*self.cur_node).type_ };
962 if etype != XML_ELEMENT_NODE as c_int {
963 return -1;
964 }
965
966 let first = unsafe { self.attr_at(self.cur_node, 0) };
968 match first {
969 AttrTarget::None => 0,
970 t => {
971 self.cur_attribute = 0;
972 unsafe { self.cache_attribute_info(t) };
974 1
975 }
976 }
977 }
978
979 pub unsafe fn MoveToNextAttribute(&mut self) -> c_int {
983 if self.cur_attribute < 0 || self.cur_node.is_null() {
984 return -1;
985 }
986
987 let etype = unsafe { (*self.cur_node).type_ };
989 if etype != XML_ELEMENT_NODE as c_int {
990 return -1;
991 }
992
993 let next_index = self.cur_attribute + 1;
995 let target = unsafe { self.attr_at(self.cur_node, next_index) };
996 match target {
997 AttrTarget::None => 0,
998 t => {
999 self.cur_attribute = next_index;
1000 unsafe { self.cache_attribute_info(t) };
1001 1
1002 }
1003 }
1004 }
1005
1006 unsafe fn cache_attribute_info(&mut self, target: AttrTarget) {
1014 self.node_type = ReaderNodeType::ATTRIBUTE;
1015 self.cur_attr_is_ns = matches!(target, AttrTarget::Ns(_));
1016 self.clear_cached_name();
1017 self.clear_cached_value();
1018 match target {
1019 AttrTarget::Ns(ns) => {
1020 let n = unsafe { &*ns };
1024 if n.prefix.is_null() {
1025 self.name = unsafe { xml_strdup(b"xmlns\0".as_ptr() as *const xmlChar) };
1026 } else {
1027 let plen = libc::strlen(n.prefix as *const libc::c_char) as usize;
1028 let mut v = Vec::with_capacity(6 + plen);
1029 v.extend_from_slice(b"xmlns:");
1030 v.extend_from_slice(core::slice::from_raw_parts(n.prefix, plen));
1031 v.push(0);
1032 let p = crate::abi::allocator::xmlMalloc(v.len()) as *mut xmlChar;
1033 if !p.is_null() {
1034 libc::memcpy(
1035 p as *mut libc::c_void,
1036 v.as_ptr() as *const libc::c_void,
1037 v.len(),
1038 );
1039 self.name = p;
1040 }
1041 }
1042 if !n.href.is_null() {
1043 self.value = unsafe { xml_strdup(n.href as *const xmlChar) };
1044 }
1045 }
1046 AttrTarget::Prop(prop) => {
1047 let attr = unsafe { &*prop };
1049
1050 if !attr.name.is_null() {
1055 if !attr.ns.is_null() && !unsafe { (*attr.ns).prefix }.is_null() {
1056 let plen = libc::strlen(unsafe { (*attr.ns).prefix } as *const libc::c_char)
1057 as usize;
1058 let nlen = libc::strlen(attr.name as *const libc::c_char) as usize;
1059 let p =
1060 crate::abi::allocator::xmlMalloc(plen + 1 + nlen + 1) as *mut xmlChar;
1061 if !p.is_null() {
1062 libc::memcpy(
1063 p as *mut libc::c_void,
1064 unsafe { (*attr.ns).prefix } as *const libc::c_void,
1065 plen,
1066 );
1067 *p.add(plen) = b':';
1068 libc::memcpy(
1069 p.add(plen + 1) as *mut libc::c_void,
1070 attr.name as *const libc::c_void,
1071 nlen,
1072 );
1073 *p.add(plen + 1 + nlen) = 0;
1074 self.name = p;
1075 }
1076 } else {
1077 self.name = unsafe { xml_strdup(attr.name as *const xmlChar) };
1079 }
1080 }
1081
1082 if !attr.children.is_null() {
1084 let val = unsafe { (*attr.children).content };
1086 if !val.is_null() {
1087 self.value = unsafe { xml_strdup(val as *const xmlChar) };
1089 }
1090 }
1091 }
1092 AttrTarget::None => {}
1093 }
1094 }
1095
1096 pub unsafe fn Prev(&mut self) -> c_int {
1100 if self.state != ReadState::READING || self.cur_node.is_null() {
1101 return -1;
1102 }
1103
1104 let current_depth = self.depth;
1106 let mut i = if self.event_index > 0 {
1107 self.event_index - 1
1108 } else {
1109 return 0;
1110 };
1111
1112 loop {
1113 let event = &self.events[i];
1114 if event.depth == current_depth && !event.is_end {
1115 self.position_at(i);
1116 return 1;
1117 }
1118 if i == 0 {
1119 break;
1120 }
1121 i -= 1;
1122 }
1123
1124 0
1125 }
1126
1127 pub fn Depth(&self) -> c_int {
1133 self.depth
1134 }
1135
1136 pub fn NodeType(&self) -> ReaderNodeType {
1138 self.node_type
1139 }
1140
1141 pub unsafe fn Name(&self) -> *mut xmlChar {
1146 if self.name.is_null() {
1147 return ptr::null_mut();
1148 }
1149 unsafe { xml_strdup(self.name as *const xmlChar) }
1151 }
1152
1153 pub unsafe fn Value(&self) -> *mut xmlChar {
1158 if self.value.is_null() {
1159 return ptr::null_mut();
1160 }
1161 unsafe { xml_strdup(self.value as *const xmlChar) }
1163 }
1164
1165 pub fn ConstName(&self) -> *const xmlChar {
1170 self.name as *const xmlChar
1171 }
1172
1173 pub fn ConstValue(&self) -> *const xmlChar {
1178 self.value as *const xmlChar
1179 }
1180
1181 pub fn HasValue(&self) -> c_int {
1183 if self.value.is_null() {
1184 0
1185 } else {
1186 1
1187 }
1188 }
1189
1190 pub fn HasAttributes(&self) -> c_int {
1192 if self.cur_node.is_null() {
1193 return 0;
1194 }
1195 let etype = unsafe { (*self.cur_node).type_ };
1197 if etype != XML_ELEMENT_NODE as c_int {
1198 return 0;
1199 }
1200 let props = unsafe { (*self.cur_node).properties };
1203 let nsdefs = unsafe { (*self.cur_node).nsDef };
1204 if props.is_null() && nsdefs.is_null() {
1205 0
1206 } else {
1207 1
1208 }
1209 }
1210
1211 pub fn IsEmptyElement(&self) -> c_int {
1213 if self.cur_node.is_null() {
1214 return 0;
1215 }
1216 let etype = unsafe { (*self.cur_node).type_ };
1218 if etype != XML_ELEMENT_NODE as c_int {
1219 return 0;
1220 }
1221 let children = unsafe { (*self.cur_node).children };
1223 if children.is_null() {
1224 1
1225 } else {
1226 0
1227 }
1228 }
1229
1230 pub unsafe fn BaseUri(&self) -> *mut xmlChar {
1235 if self.doc.is_null() {
1237 return ptr::null_mut();
1238 }
1239 let url = unsafe { (*self.doc).URL };
1241 if url.is_null() {
1242 return ptr::null_mut();
1243 }
1244 unsafe { xml_strdup(url as *const xmlChar) }
1246 }
1247
1248 pub unsafe fn LocalName(&self) -> *mut xmlChar {
1253 if self.name.is_null() {
1254 return ptr::null_mut();
1255 }
1256
1257 let name_bytes = unsafe { xmlstr_to_bytes(self.name as *const xmlChar) };
1259
1260 if let Some(pos) = name_bytes.iter().position(|&b| b == b':') {
1262 let local = &name_bytes[pos + 1..];
1264 if local.is_empty() {
1265 return ptr::null_mut();
1266 }
1267 unsafe { bytes_to_xmlstr(local) }
1269 } else {
1270 unsafe { xml_strdup(self.name as *const xmlChar) }
1273 }
1274 }
1275
1276 pub unsafe fn NamespaceUri(&self) -> *mut xmlChar {
1280 if self.cur_node.is_null() {
1281 return ptr::null_mut();
1282 }
1283
1284 let ns = unsafe { (*self.cur_node).ns };
1286 if ns.is_null() {
1287 return ptr::null_mut();
1288 }
1289
1290 let href = unsafe { (*ns).href };
1292 if href.is_null() {
1293 return ptr::null_mut();
1294 }
1295
1296 unsafe { xml_strdup(href as *const xmlChar) }
1298 }
1299
1300 pub unsafe fn Prefix(&self) -> *mut xmlChar {
1304 if self.cur_node.is_null() {
1305 return ptr::null_mut();
1306 }
1307
1308 let ns = unsafe { (*self.cur_node).ns };
1310 if ns.is_null() {
1311 return ptr::null_mut();
1312 }
1313
1314 let prefix = unsafe { (*ns).prefix };
1316 if prefix.is_null() {
1317 return ptr::null_mut();
1318 }
1319
1320 unsafe { xml_strdup(prefix as *const xmlChar) }
1322 }
1323
1324 pub fn AttributeCount(&self) -> c_int {
1326 self.attribute_count
1327 }
1328
1329 pub fn ReadState(&self) -> ReadState {
1331 self.state
1332 }
1333
1334 pub unsafe fn GetAttribute(&self, name: *const xmlChar) -> *mut xmlChar {
1338 if self.cur_node.is_null() {
1339 return ptr::null_mut();
1340 }
1341
1342 let etype = unsafe { (*self.cur_node).type_ };
1344 if etype != XML_ELEMENT_NODE as c_int {
1345 return ptr::null_mut();
1346 }
1347
1348 let idx = unsafe { self.attr_index_by_name(self.cur_node, name) };
1350 if idx < 0 {
1351 return ptr::null_mut();
1352 }
1353 match unsafe { self.attr_at(self.cur_node, idx) } {
1354 AttrTarget::Ns(ns) => {
1355 let href = unsafe { (*ns).href };
1356 if href.is_null() {
1357 ptr::null_mut()
1358 } else {
1359 unsafe { xml_strdup(href as *const xmlChar) }
1360 }
1361 }
1362 AttrTarget::Prop(prop) => {
1363 let val = unsafe { (*prop).children };
1365 if !val.is_null() {
1366 let content = unsafe { (*val).content };
1367 if !content.is_null() {
1368 return unsafe { xml_strdup(content as *const xmlChar) };
1369 }
1370 }
1371 ptr::null_mut()
1372 }
1373 AttrTarget::None => ptr::null_mut(),
1374 }
1375 }
1376
1377 pub unsafe fn GetAttributeNo(&self, index: c_int) -> *mut xmlChar {
1381 if self.cur_node.is_null() || index < 0 {
1382 return ptr::null_mut();
1383 }
1384
1385 let etype = unsafe { (*self.cur_node).type_ };
1387 if etype != XML_ELEMENT_NODE as c_int {
1388 return ptr::null_mut();
1389 }
1390
1391 match unsafe { self.attr_at(self.cur_node, index) } {
1393 AttrTarget::Ns(ns) => {
1394 let href = unsafe { (*ns).href };
1395 if href.is_null() {
1396 ptr::null_mut()
1397 } else {
1398 unsafe { xml_strdup(href as *const xmlChar) }
1399 }
1400 }
1401 AttrTarget::Prop(prop) => {
1402 let val = unsafe { (*prop).children };
1403 if !val.is_null() {
1404 let content = unsafe { (*val).content };
1405 if !content.is_null() {
1406 return unsafe { xml_strdup(content as *const xmlChar) };
1407 }
1408 }
1409 ptr::null_mut()
1410 }
1411 AttrTarget::None => ptr::null_mut(),
1412 }
1413 }
1414
1415 pub unsafe fn GetAttributeNs(
1419 &self,
1420 localName: *const xmlChar,
1421 namespaceURI: *const xmlChar,
1422 ) -> *mut xmlChar {
1423 if self.cur_node.is_null() {
1424 return ptr::null_mut();
1425 }
1426
1427 let etype = unsafe { (*self.cur_node).type_ };
1429 if etype != XML_ELEMENT_NODE as c_int {
1430 return ptr::null_mut();
1431 }
1432
1433 let mut prop = unsafe { (*self.cur_node).properties };
1435 while !prop.is_null() {
1436 let prop_local = unsafe { (*prop).name };
1438 let prop_ns = unsafe { (*prop).ns };
1439
1440 if prop_local.is_null() {
1442 prop = unsafe { (*prop).next };
1444 continue;
1445 }
1446
1447 let name_match = unsafe {
1449 crate::xml::string::xml_strcmp(prop_local as *const xmlChar, localName) == 0
1450 };
1451
1452 if name_match {
1453 let ns_match = if namespaceURI.is_null() {
1455 prop_ns.is_null()
1456 } else if prop_ns.is_null() {
1457 false
1458 } else {
1459 unsafe {
1461 crate::xml::string::xml_strcmp(
1462 (*prop_ns).href as *const xmlChar,
1463 namespaceURI,
1464 ) == 0
1465 }
1466 };
1467
1468 if ns_match {
1469 let val = unsafe { (*prop).children };
1471 if !val.is_null() {
1472 let content = unsafe { (*val).content };
1474 if !content.is_null() {
1475 return unsafe { xml_strdup(content as *const xmlChar) };
1477 }
1478 }
1479 return ptr::null_mut();
1480 }
1481 }
1482
1483 prop = unsafe { (*prop).next };
1485 }
1486
1487 ptr::null_mut()
1488 }
1489
1490 pub unsafe fn LookupNamespace(&self, prefix: *const xmlChar) -> *mut xmlChar {
1494 if self.cur_node.is_null() {
1495 return ptr::null_mut();
1496 }
1497
1498 let mut cur = self.cur_node;
1501 while !cur.is_null() {
1502 let mut ns_def = unsafe { (*cur).nsDef };
1504 while !ns_def.is_null() {
1505 let ns_prefix = unsafe { (*ns_def).prefix };
1507
1508 let match_prefix = if prefix.is_null() || *prefix == 0 {
1509 ns_prefix.is_null()
1511 } else if ns_prefix.is_null() {
1512 false
1513 } else {
1514 unsafe {
1516 crate::xml::string::xml_strcmp(ns_prefix as *const xmlChar, prefix) == 0
1517 }
1518 };
1519
1520 if match_prefix {
1521 let href = unsafe { (*ns_def).href };
1523 if !href.is_null() {
1524 return unsafe { xml_strdup(href as *const xmlChar) };
1526 }
1527 return ptr::null_mut();
1528 }
1529
1530 ns_def = unsafe { (*ns_def).next };
1532 }
1533
1534 cur = unsafe { (*cur).parent };
1536 }
1537
1538 ptr::null_mut()
1539 }
1540
1541 pub fn GetParserProp(&self, prop: c_int) -> c_int {
1543 match prop {
1544 1 => {
1545 if (self.options & XML_PARSE_DTDLOAD) != 0 { 1 } else { 0 }
1546 }
1547 2 => {
1548 if (self.options & XML_PARSE_DTDATTR) != 0 { 1 } else { 0 }
1549 }
1550 3 => {
1551 if (self.options & XML_PARSE_DTDVALID) != 0 { 1 } else { 0 }
1552 }
1553 4 => {
1554 if (self.options & XML_PARSE_NOENT) != 0 { 1 } else { 0 }
1555 }
1556 _ => -1,
1557 }
1558 }
1559
1560 pub fn SetParserProp(&mut self, prop: c_int, value: c_int) -> c_int {
1562 match prop {
1563 1 => {
1564 if value != 0 {
1565 self.options |= XML_PARSE_DTDLOAD;
1566 } else {
1567 self.options &= !XML_PARSE_DTDLOAD;
1568 }
1569 0
1570 }
1571 2 => {
1572 if value != 0 {
1573 self.options |= XML_PARSE_DTDATTR;
1574 } else {
1575 self.options &= !XML_PARSE_DTDATTR;
1576 }
1577 0
1578 }
1579 3 => {
1580 if value != 0 {
1581 self.options |= XML_PARSE_DTDVALID;
1582 } else {
1583 self.options &= !XML_PARSE_DTDVALID;
1584 }
1585 0
1586 }
1587 4 => {
1588 if value != 0 {
1589 self.options |= XML_PARSE_NOENT;
1590 } else {
1591 self.options &= !XML_PARSE_NOENT;
1592 }
1593 0
1594 }
1595 _ => -1,
1596 }
1597 }
1598
1599 pub fn CurrentDoc(&self) -> *mut _xmlDoc {
1601 self.doc
1602 }
1603}
1604
1605impl Drop for XmlTextReader {
1606 fn drop(&mut self) {
1607 self.clear_cached_name();
1609 self.clear_cached_value();
1610
1611 if !self.last_err.message.is_null() {
1613 unsafe { libc::free(self.last_err.message as *mut libc::c_void) };
1615 self.last_err.message = ptr::null_mut();
1616 }
1617
1618 if !self.encoding.is_null() {
1620 unsafe { xmlFree(self.encoding as *mut c_void) };
1622 self.encoding = ptr::null_mut();
1623 }
1624 if !self.URL.is_null() {
1625 unsafe { xmlFree(self.URL as *mut c_void) };
1627 self.URL = ptr::null_mut();
1628 }
1629
1630 if !self.doc.is_null() && self.owns_doc {
1632 unsafe { tree::free_doc(self.doc) };
1635 self.doc = ptr::null_mut();
1636 }
1637
1638 if !self.ctxt.is_null() {
1640 unsafe { free_parser_ctxt(self.ctxt) };
1642 self.ctxt = ptr::null_mut();
1643 }
1644 }
1645}
1646
1647unsafe fn reader_from_input(
1657 input: *mut _xmlParserInputBuffer,
1658 URL: *const c_char,
1659 encoding: *const c_char,
1660 options: c_int,
1661) -> *mut XmlTextReader {
1662 if input.is_null() {
1663 return ptr::null_mut();
1664 }
1665
1666 let ctxt = create_parser_ctxt();
1668 if ctxt.is_null() {
1669 return ptr::null_mut();
1670 }
1671
1672 let mut data = Vec::new();
1674 let mut tmp = [0u8; 4096];
1675
1676 let read_cb = unsafe { (*input).readcallback };
1678 let ioctx = unsafe { (*input).context };
1679
1680 if let Some(read) = read_cb {
1681 loop {
1682 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
1684 if n <= 0 {
1685 break;
1686 }
1687 data.extend_from_slice(&tmp[..n as usize]);
1688 }
1689 }
1690
1691 let close_cb = unsafe { (*input).closecallback };
1694 if let Some(close) = close_cb {
1695 unsafe { close(ioctx) };
1697 }
1698
1699 let input_buf = InputBuffer::from_memory(&data, None);
1701
1702 setup_parser_input(ctxt, input_buf);
1704
1705 unsafe {
1707 (*ctxt).options = options;
1708 }
1709
1710 let url_bytes = if URL.is_null() {
1712 None
1713 } else {
1714 unsafe {
1716 let cstr = std::ffi::CStr::from_ptr(URL);
1717 Some(cstr.to_bytes().to_vec())
1718 }
1719 };
1720
1721 let enc_bytes = if encoding.is_null() {
1722 None
1723 } else {
1724 unsafe {
1726 let cstr = std::ffi::CStr::from_ptr(encoding);
1727 Some(cstr.to_bytes().to_vec())
1728 }
1729 };
1730
1731 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1733 reader.options = options;
1734
1735 Box::into_raw(Box::new(reader))
1737}
1738
1739#[no_mangle]
1756pub unsafe extern "C" fn xmlNewTextReader(
1757 input: *mut _xmlParserInputBuffer,
1758 URI: *const c_char,
1759) -> *mut XmlTextReader {
1760 unsafe { reader_from_input(input, URI, ptr::null(), 0) }
1762}
1763
1764#[no_mangle]
1777pub unsafe extern "C" fn xmlReaderForFile(
1778 filename: *const c_char,
1779 encoding: *const c_char,
1780 options: c_int,
1781) -> *mut XmlTextReader {
1782 if filename.is_null() {
1783 return ptr::null_mut();
1784 }
1785
1786 let ctxt = unsafe { create_parser_ctxt() };
1788 if ctxt.is_null() {
1789 return ptr::null_mut();
1790 }
1791
1792 let input = match unsafe { input_from_file(filename) } {
1794 Ok(input) => input,
1795 Err(_) => {
1796 unsafe { free_parser_ctxt(ctxt) };
1798 return ptr::null_mut();
1799 }
1800 };
1801
1802 unsafe { setup_parser_input(ctxt, input) };
1804 unsafe {
1805 (*ctxt).options = options;
1806 }
1807
1808 let enc_bytes = if encoding.is_null() {
1809 None
1810 } else {
1811 unsafe {
1813 let cstr = std::ffi::CStr::from_ptr(encoding);
1814 Some(cstr.to_bytes().to_vec())
1815 }
1816 };
1817
1818 let mut reader = XmlTextReader::new(ctxt, None, enc_bytes.as_deref());
1819 reader.options = options;
1820 Box::into_raw(Box::new(reader))
1821}
1822
1823#[no_mangle]
1837pub unsafe extern "C" fn xmlReaderForMemory(
1838 buffer: *const c_char,
1839 size: c_int,
1840 URL: *const c_char,
1841 encoding: *const c_char,
1842 options: c_int,
1843) -> *mut XmlTextReader {
1844 if buffer.is_null() || size <= 0 {
1845 return ptr::null_mut();
1846 }
1847
1848 let ctxt = unsafe { create_parser_ctxt() };
1850 if ctxt.is_null() {
1851 return ptr::null_mut();
1852 }
1853
1854 let input = unsafe { input_from_memory(buffer, size) };
1856
1857 unsafe { setup_parser_input(ctxt, input) };
1859 unsafe {
1860 (*ctxt).options = options;
1861 }
1862
1863 let url_bytes = if URL.is_null() {
1864 None
1865 } else {
1866 unsafe {
1868 let cstr = std::ffi::CStr::from_ptr(URL);
1869 Some(cstr.to_bytes().to_vec())
1870 }
1871 };
1872
1873 let enc_bytes = if encoding.is_null() {
1874 None
1875 } else {
1876 unsafe {
1878 let cstr = std::ffi::CStr::from_ptr(encoding);
1879 Some(cstr.to_bytes().to_vec())
1880 }
1881 };
1882
1883 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1884 reader.options = options;
1885 Box::into_raw(Box::new(reader))
1886}
1887
1888#[no_mangle]
1902pub unsafe extern "C" fn xmlReaderForFd(
1903 fd: c_int,
1904 URL: *const c_char,
1905 encoding: *const c_char,
1906 options: c_int,
1907) -> *mut XmlTextReader {
1908 let ctxt = unsafe { create_parser_ctxt() };
1910 if ctxt.is_null() {
1911 return ptr::null_mut();
1912 }
1913
1914 let mut buf = Vec::new();
1916 let mut tmp = [0u8; 4096];
1917 loop {
1918 let n = unsafe { libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len()) };
1920 if n <= 0 {
1921 break;
1922 }
1923 buf.extend_from_slice(&tmp[..n as usize]);
1924 }
1925
1926 let input = unsafe { input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int) };
1928
1929 unsafe { setup_parser_input(ctxt, input) };
1931 unsafe {
1932 (*ctxt).options = options;
1933 }
1934
1935 let url_bytes = if URL.is_null() {
1936 None
1937 } else {
1938 unsafe {
1940 let cstr = std::ffi::CStr::from_ptr(URL);
1941 Some(cstr.to_bytes().to_vec())
1942 }
1943 };
1944
1945 let enc_bytes = if encoding.is_null() {
1946 None
1947 } else {
1948 unsafe {
1950 let cstr = std::ffi::CStr::from_ptr(encoding);
1951 Some(cstr.to_bytes().to_vec())
1952 }
1953 };
1954
1955 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1956 reader.options = options;
1957 Box::into_raw(Box::new(reader))
1958}
1959
1960#[no_mangle]
1976pub unsafe extern "C" fn xmlReaderForIO(
1977 ioread: Option<xmlInputReadCallback>,
1978 ioclose: Option<xmlInputCloseCallback>,
1979 ioctx: *mut c_void,
1980 URL: *const c_char,
1981 encoding: *const c_char,
1982 options: c_int,
1983) -> *mut XmlTextReader {
1984 let ctxt = unsafe { create_parser_ctxt() };
1986 if ctxt.is_null() {
1987 return ptr::null_mut();
1988 }
1989
1990 let input = unsafe { input_from_io(ioread, ioclose, ioctx) };
1992
1993 unsafe { setup_parser_input(ctxt, input) };
1995 unsafe {
1996 (*ctxt).options = options;
1997 }
1998
1999 let url_bytes = if URL.is_null() {
2000 None
2001 } else {
2002 unsafe {
2004 let cstr = std::ffi::CStr::from_ptr(URL);
2005 Some(cstr.to_bytes().to_vec())
2006 }
2007 };
2008
2009 let enc_bytes = if encoding.is_null() {
2010 None
2011 } else {
2012 unsafe {
2014 let cstr = std::ffi::CStr::from_ptr(encoding);
2015 Some(cstr.to_bytes().to_vec())
2016 }
2017 };
2018
2019 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
2020 reader.options = options;
2021 Box::into_raw(Box::new(reader))
2022}
2023
2024#[no_mangle]
2043pub unsafe extern "C" fn xmlTextReaderRead(reader: *mut XmlTextReader) -> c_int {
2044 if reader.is_null() {
2045 return -1;
2046 }
2047 unsafe { (*reader).Read() }
2049}
2050
2051#[no_mangle]
2065pub unsafe extern "C" fn xmlTextReaderNext(reader: *mut XmlTextReader) -> c_int {
2066 if reader.is_null() {
2067 return -1;
2068 }
2069 unsafe { (*reader).Next() }
2071}
2072
2073#[no_mangle]
2085pub unsafe extern "C" fn xmlTextReaderNextSibling(reader: *mut XmlTextReader) -> c_int {
2086 if reader.is_null() {
2087 return -1;
2088 }
2089 unsafe { (*reader).Next() }
2091}
2092
2093#[no_mangle]
2107pub unsafe extern "C" fn xmlTextReaderPrev(reader: *mut XmlTextReader) -> c_int {
2108 if reader.is_null() {
2109 return -1;
2110 }
2111 unsafe { (*reader).Prev() }
2113}
2114
2115#[no_mangle]
2129pub unsafe extern "C" fn xmlTextReaderMoveToElement(reader: *mut XmlTextReader) -> c_int {
2130 if reader.is_null() {
2131 return -1;
2132 }
2133 unsafe { (*reader).MoveToElement() }
2135}
2136
2137#[no_mangle]
2151pub unsafe extern "C" fn xmlTextReaderMoveToAttribute(
2152 reader: *mut XmlTextReader,
2153 name: *const xmlChar,
2154) -> c_int {
2155 if reader.is_null() || name.is_null() {
2156 return -1;
2157 }
2158 unsafe { (*reader).MoveToAttribute(name) }
2160}
2161
2162#[no_mangle]
2176pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNo(
2177 reader: *mut XmlTextReader,
2178 index: c_int,
2179) -> c_int {
2180 if reader.is_null() {
2181 return -1;
2182 }
2183 unsafe { (*reader).MoveToAttributeNo(index) }
2185}
2186
2187#[no_mangle]
2201pub unsafe extern "C" fn xmlTextReaderMoveToFirstAttribute(reader: *mut XmlTextReader) -> c_int {
2202 if reader.is_null() {
2203 return -1;
2204 }
2205 unsafe { (*reader).MoveToFirstAttribute() }
2207}
2208
2209#[no_mangle]
2223pub unsafe extern "C" fn xmlTextReaderMoveToNextAttribute(reader: *mut XmlTextReader) -> c_int {
2224 if reader.is_null() {
2225 return -1;
2226 }
2227 unsafe { (*reader).MoveToNextAttribute() }
2229}
2230
2231#[no_mangle]
2249pub unsafe extern "C" fn xmlTextReaderAttributeCount(reader: *mut XmlTextReader) -> c_int {
2250 if reader.is_null() {
2251 return -1;
2252 }
2253 unsafe { (*reader).AttributeCount() }
2255}
2256
2257#[no_mangle]
2271pub unsafe extern "C" fn xmlTextReaderDepth(reader: *mut XmlTextReader) -> c_int {
2272 if reader.is_null() {
2273 return -1;
2274 }
2275 unsafe { (*reader).Depth() }
2277}
2278
2279#[no_mangle]
2293pub unsafe extern "C" fn xmlTextReaderNodeType(reader: *mut XmlTextReader) -> c_int {
2294 if reader.is_null() {
2295 return -1;
2296 }
2297 unsafe { (*reader).NodeType() as c_int }
2299}
2300
2301#[no_mangle]
2316pub unsafe extern "C" fn xmlTextReaderName(reader: *mut XmlTextReader) -> *mut xmlChar {
2317 if reader.is_null() {
2318 return ptr::null_mut();
2319 }
2320 unsafe { (*reader).Name() }
2322}
2323
2324#[no_mangle]
2339pub unsafe extern "C" fn xmlTextReaderValue(reader: *mut XmlTextReader) -> *mut xmlChar {
2340 if reader.is_null() {
2341 return ptr::null_mut();
2342 }
2343 unsafe { (*reader).Value() }
2345}
2346
2347#[no_mangle]
2362pub unsafe extern "C" fn xmlTextReaderConstName(reader: *mut XmlTextReader) -> *const xmlChar {
2363 if reader.is_null() {
2364 return ptr::null();
2365 }
2366 unsafe { (*reader).ConstName() }
2368}
2369
2370#[no_mangle]
2385pub unsafe extern "C" fn xmlTextReaderConstValue(reader: *mut XmlTextReader) -> *const xmlChar {
2386 if reader.is_null() {
2387 return ptr::null();
2388 }
2389 unsafe { (*reader).ConstValue() }
2391}
2392
2393#[no_mangle]
2408pub unsafe extern "C" fn xmlTextReaderBaseUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2409 if reader.is_null() {
2410 return ptr::null_mut();
2411 }
2412 unsafe { (*reader).BaseUri() }
2414}
2415
2416#[no_mangle]
2430pub unsafe extern "C" fn xmlTextReaderLocalName(reader: *mut XmlTextReader) -> *mut xmlChar {
2431 if reader.is_null() {
2432 return ptr::null_mut();
2433 }
2434 unsafe { (*reader).LocalName() }
2436}
2437
2438#[no_mangle]
2452pub unsafe extern "C" fn xmlTextReaderNamespaceUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2453 if reader.is_null() {
2454 return ptr::null_mut();
2455 }
2456 unsafe { (*reader).NamespaceUri() }
2458}
2459
2460#[no_mangle]
2474pub unsafe extern "C" fn xmlTextReaderPrefix(reader: *mut XmlTextReader) -> *mut xmlChar {
2475 if reader.is_null() {
2476 return ptr::null_mut();
2477 }
2478 unsafe { (*reader).Prefix() }
2480}
2481
2482#[no_mangle]
2496pub unsafe extern "C" fn xmlTextReaderHasValue(reader: *mut XmlTextReader) -> c_int {
2497 if reader.is_null() {
2498 return 0;
2499 }
2500 unsafe { (*reader).HasValue() }
2502}
2503
2504#[no_mangle]
2518pub unsafe extern "C" fn xmlTextReaderHasAttributes(reader: *mut XmlTextReader) -> c_int {
2519 if reader.is_null() {
2520 return 0;
2521 }
2522 unsafe { (*reader).HasAttributes() }
2524}
2525
2526#[no_mangle]
2540pub unsafe extern "C" fn xmlTextReaderIsEmptyElement(reader: *mut XmlTextReader) -> c_int {
2541 if reader.is_null() {
2542 return 0;
2543 }
2544 unsafe { (*reader).IsEmptyElement() }
2546}
2547
2548#[no_mangle]
2562pub unsafe extern "C" fn xmlTextReaderReadState(reader: *mut XmlTextReader) -> c_int {
2563 if reader.is_null() {
2564 return ReadState::ERROR as c_int;
2565 }
2566 unsafe { (*reader).ReadState() as c_int }
2568}
2569
2570#[no_mangle]
2588pub unsafe extern "C" fn xmlTextReaderGetAttribute(
2589 reader: *mut XmlTextReader,
2590 name: *const xmlChar,
2591) -> *mut xmlChar {
2592 if reader.is_null() || name.is_null() {
2593 return ptr::null_mut();
2594 }
2595 unsafe { (*reader).GetAttribute(name) }
2597}
2598
2599#[no_mangle]
2613pub unsafe extern "C" fn xmlTextReaderGetAttributeNo(
2614 reader: *mut XmlTextReader,
2615 index: c_int,
2616) -> *mut xmlChar {
2617 if reader.is_null() {
2618 return ptr::null_mut();
2619 }
2620 unsafe { (*reader).GetAttributeNo(index) }
2622}
2623
2624#[no_mangle]
2640pub unsafe extern "C" fn xmlTextReaderGetAttributeNs(
2641 reader: *mut XmlTextReader,
2642 localName: *const xmlChar,
2643 namespaceURI: *const xmlChar,
2644) -> *mut xmlChar {
2645 if reader.is_null() || localName.is_null() {
2646 return ptr::null_mut();
2647 }
2648 unsafe { (*reader).GetAttributeNs(localName, namespaceURI) }
2650}
2651
2652#[no_mangle]
2666pub unsafe extern "C" fn xmlTextReaderLookupNamespace(
2667 reader: *mut XmlTextReader,
2668 prefix: *const xmlChar,
2669) -> *mut xmlChar {
2670 if reader.is_null() {
2671 return ptr::null_mut();
2672 }
2673 unsafe { (*reader).LookupNamespace(prefix) }
2675}
2676
2677#[no_mangle]
2695pub unsafe extern "C" fn xmlTextReaderGetParserProp(
2696 reader: *mut XmlTextReader,
2697 prop: c_int,
2698) -> c_int {
2699 if reader.is_null() {
2700 return -1;
2701 }
2702 unsafe { (*reader).GetParserProp(prop) }
2704}
2705
2706#[no_mangle]
2720pub unsafe extern "C" fn xmlTextReaderSetParserProp(
2721 reader: *mut XmlTextReader,
2722 prop: c_int,
2723 value: c_int,
2724) -> c_int {
2725 if reader.is_null() {
2726 return -1;
2727 }
2728 unsafe { (*reader).SetParserProp(prop, value) }
2730}
2731
2732#[no_mangle]
2749pub unsafe extern "C" fn xmlFreeTextReader(reader: *mut XmlTextReader) {
2750 if reader.is_null() {
2751 return;
2752 }
2753 unsafe {
2756 let _ = Box::from_raw(reader);
2757 }
2758}
2759
2760#[no_mangle]
2776pub unsafe extern "C" fn xmlTextReaderSetup(
2777 reader: *mut XmlTextReader,
2778 input: *mut _xmlParserInputBuffer,
2779 URL: *const c_char,
2780 encoding: *const c_char,
2781 options: c_int,
2782) -> c_int {
2783 if reader.is_null() {
2784 return -1;
2785 }
2786
2787 let r = unsafe { &mut *reader };
2789
2790 r.clear_cached_name();
2792 r.clear_cached_value();
2793
2794 if !r.doc.is_null() {
2796 unsafe { tree::free_doc(r.doc) };
2798 r.doc = ptr::null_mut();
2799 }
2800
2801 if !r.ctxt.is_null() {
2803 unsafe { free_parser_ctxt(r.ctxt) };
2805 r.ctxt = ptr::null_mut();
2806 }
2807
2808 r.events.clear();
2809 r.event_index = 0;
2810 r.state = ReadState::INITIALIZED;
2811 r.cur_node = ptr::null_mut();
2812 r.node_type = ReaderNodeType::NONE;
2813 r.depth = 0;
2814 r.attribute_count = -1;
2815 r.cur_attribute = -1;
2816 r.options = options;
2817 r.parsed = false;
2818 r.errors.clear();
2819
2820 if !r.URL.is_null() {
2822 unsafe { xmlFree(r.URL as *mut c_void) };
2824 r.URL = ptr::null_mut();
2825 }
2826 if !URL.is_null() {
2827 let url_str = unsafe { std::ffi::CStr::from_ptr(URL) };
2829 r.URL = unsafe { bytes_to_xmlstr(url_str.to_bytes()) };
2831 }
2832
2833 if !r.encoding.is_null() {
2835 unsafe { xmlFree(r.encoding as *mut c_void) };
2837 r.encoding = ptr::null_mut();
2838 }
2839 if !encoding.is_null() {
2840 let enc_str = unsafe { std::ffi::CStr::from_ptr(encoding) };
2842 r.encoding = unsafe { bytes_to_xmlstr(enc_str.to_bytes()) };
2844 }
2845
2846 if !input.is_null() {
2848 let ctxt = unsafe { create_parser_ctxt() };
2850 if ctxt.is_null() {
2851 return -1;
2852 }
2853
2854 let mut data = Vec::new();
2856 let mut tmp = [0u8; 4096];
2857
2858 let read_cb = unsafe { (*input).readcallback };
2860 let ioctx = unsafe { (*input).context };
2861
2862 if let Some(read) = read_cb {
2863 loop {
2864 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2866 if n <= 0 {
2867 break;
2868 }
2869 data.extend_from_slice(&tmp[..n as usize]);
2870 }
2871 }
2872
2873 let close_cb = unsafe { (*input).closecallback };
2875 if let Some(close) = close_cb {
2876 unsafe { close(ioctx) };
2878 }
2879
2880 let input_buf = InputBuffer::from_memory(&data, None);
2881
2882 unsafe { setup_parser_input(ctxt, input_buf) };
2884 unsafe {
2885 (*ctxt).options = options;
2886 }
2887
2888 r.ctxt = ctxt;
2889 }
2890
2891 0
2892}
2893
2894#[no_mangle]
2908pub unsafe extern "C" fn xmlTextReaderCurrentDoc(reader: *mut XmlTextReader) -> *mut _xmlDoc {
2909 if reader.is_null() {
2910 return ptr::null_mut();
2911 }
2912 unsafe { (*reader).CurrentDoc() }
2914}
2915
2916#[no_mangle]
2935pub unsafe extern "C" fn xmlTextReaderClose(reader: *mut XmlTextReader) -> c_int {
2936 if reader.is_null() {
2937 return -1;
2938 }
2939 unsafe {
2942 let r = &mut *reader;
2943 r.cur_node = ptr::null_mut();
2944 r.node_type = ReaderNodeType::NONE;
2945 r.clear_cached_name();
2946 r.clear_cached_value();
2947 r.state = ReadState::CLOSED;
2948 }
2949 0
2950}
2951
2952#[no_mangle]
2967pub unsafe extern "C" fn xmlTextReaderCurrentNode(reader: *mut XmlTextReader) -> *mut _xmlNode {
2968 if reader.is_null() {
2969 return ptr::null_mut();
2970 }
2971 unsafe { (*reader).cur_node }
2973}
2974
2975#[no_mangle]
2995pub unsafe extern "C" fn xmlTextReaderExpand(reader: *mut XmlTextReader) -> *mut _xmlNode {
2996 if reader.is_null() {
2997 return ptr::null_mut();
2998 }
2999 unsafe { (*reader).cur_node }
3001}
3002
3003#[no_mangle]
3021pub unsafe extern "C" fn xmlTextReaderGetParserLineNumber(reader: *mut XmlTextReader) -> c_int {
3022 if reader.is_null() {
3023 return 0;
3024 }
3025 unsafe {
3027 let node = (*reader).cur_node;
3028 if node.is_null() {
3029 0
3030 } else {
3031 (*node).line as c_int
3032 }
3033 }
3034}
3035
3036#[no_mangle]
3052pub unsafe extern "C" fn xmlTextReaderGetParserColumnNumber(reader: *mut XmlTextReader) -> c_int {
3053 if reader.is_null() {
3054 return -1;
3055 }
3056 -1
3057}
3058
3059#[no_mangle]
3077pub unsafe extern "C" fn xmlTextReaderIsValid(reader: *mut XmlTextReader) -> c_int {
3078 if reader.is_null() {
3079 return -1;
3080 }
3081 0
3082}
3083
3084#[no_mangle]
3101pub unsafe extern "C" fn xmlTextReaderNormalization(reader: *mut XmlTextReader) -> c_int {
3102 if reader.is_null() {
3103 return -1;
3104 }
3105 1
3106}
3107
3108#[no_mangle]
3127pub unsafe extern "C" fn xmlTextReaderReadAttributeValue(reader: *mut XmlTextReader) -> c_int {
3128 if reader.is_null() {
3129 return -1;
3130 }
3131 unsafe {
3133 let r = &*reader;
3134 if r.node_type == ReaderNodeType::ATTRIBUTE && !r.cur_node.is_null() {
3135 1
3136 } else {
3137 0
3138 }
3139 }
3140}
3141
3142#[no_mangle]
3160pub unsafe extern "C" fn xmlTextReaderReadString(reader: *mut XmlTextReader) -> *mut xmlChar {
3161 if reader.is_null() {
3162 return ptr::null_mut();
3163 }
3164 unsafe {
3166 let node = (*reader).cur_node;
3167 if node.is_null() {
3168 return ptr::null_mut();
3169 }
3170 tree::node_get_content(node)
3171 }
3172}
3173
3174#[no_mangle]
3191pub unsafe extern "C" fn xmlTextReaderReadInnerXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3192 if reader.is_null() {
3193 return ptr::null_mut();
3194 }
3195 unsafe {
3197 let node = (*reader).cur_node;
3198 if node.is_null() {
3199 return ptr::null_mut();
3200 }
3201 let buf = crate::xml::io::buf_create(-1);
3202 if buf.is_null() {
3203 return ptr::null_mut();
3204 }
3205 let mut child = (*node).children;
3206 while !child.is_null() {
3207 tree::serialize_node(child, buf, 0, 0);
3208 child = (*child).next;
3209 }
3210 let len = crate::xml::io::buf_length(buf) as usize;
3211 let content = crate::xml::io::buf_content(buf);
3212 if content.is_null() || len == 0 {
3213 crate::xml::io::buf_free(buf);
3214 return ptr::null_mut();
3215 }
3216 let out = xml_strdup(content);
3217 crate::xml::io::buf_free(buf);
3218 out
3219 }
3220}
3221
3222#[no_mangle]
3238pub unsafe extern "C" fn xmlTextReaderReadOuterXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3239 if reader.is_null() {
3240 return ptr::null_mut();
3241 }
3242 unsafe {
3244 let node = (*reader).cur_node;
3245 if node.is_null() {
3246 return ptr::null_mut();
3247 }
3248 let buf = crate::xml::io::buf_create(-1);
3249 if buf.is_null() {
3250 return ptr::null_mut();
3251 }
3252 tree::serialize_node(node, buf, 0, 0);
3253 let len = crate::xml::io::buf_length(buf) as usize;
3254 let content = crate::xml::io::buf_content(buf);
3255 if content.is_null() || len == 0 {
3256 crate::xml::io::buf_free(buf);
3257 return ptr::null_mut();
3258 }
3259 let out = xml_strdup(content);
3260 crate::xml::io::buf_free(buf);
3261 out
3262 }
3263}
3264
3265#[no_mangle]
3280pub unsafe extern "C" fn xmlTextReaderStandalone(reader: *mut XmlTextReader) -> c_int {
3281 if reader.is_null() {
3282 return -1;
3283 }
3284 unsafe {
3286 let doc = (*reader).doc;
3287 if doc.is_null() {
3288 return -1;
3289 }
3290 (*doc).standalone
3291 }
3292}
3293
3294#[no_mangle]
3311pub unsafe extern "C" fn xmlTextReaderXmlLang(reader: *mut XmlTextReader) -> *mut xmlChar {
3312 if reader.is_null() {
3313 return ptr::null_mut();
3314 }
3315 unsafe {
3317 let mut node = (*reader).cur_node;
3318 while !node.is_null() {
3319 let mut prop = (*node).properties;
3321 while !prop.is_null() {
3322 if !(*prop).name.is_null() {
3323 let name = crate::xml::string::xmlstr_to_bytes((*prop).name);
3324 if name == b"lang" && !(*prop).ns.is_null() {
3325 let ns_href = crate::xml::string::xmlstr_to_bytes((*(*prop).ns).href);
3326 if ns_href == b"http://www.w3.org/XML/1998/namespace" {
3327 let v = (*prop).children;
3328 if !v.is_null() && !(*v).content.is_null() {
3329 return xml_strdup((*v).content);
3330 }
3331 }
3332 }
3333 }
3334 prop = (*prop).next;
3335 }
3336 node = (*node).parent;
3337 }
3338 ptr::null_mut()
3339 }
3340}
3341
3342#[cfg(test)]
3347mod tests {
3348 use super::*;
3349 use crate::abi::allocator::xmlFree;
3350 use core::ffi::c_void;
3351 use std::os::raw::c_char;
3352
3353 unsafe fn create_reader(xml: &str) -> *mut XmlTextReader {
3355 let bytes = xml.as_bytes();
3356 xmlReaderForMemory(
3357 bytes.as_ptr() as *const c_char,
3358 bytes.len() as c_int,
3359 ptr::null(),
3360 ptr::null(),
3361 0,
3362 )
3363 }
3364
3365 unsafe fn free_reader(reader: *mut XmlTextReader) {
3367 if !reader.is_null() {
3368 xmlFreeTextReader(reader);
3369 }
3370 }
3371
3372 unsafe fn collect_nodes(reader: *mut XmlTextReader) -> Vec<(ReaderNodeType, String, i32)> {
3374 let mut result = Vec::new();
3375 loop {
3376 let ret = xmlTextReaderRead(reader);
3377 if ret <= 0 {
3378 break;
3379 }
3380 let r = &*reader;
3382 let ntype = r.NodeType();
3383 let name = if r.name.is_null() {
3384 String::new()
3385 } else {
3386 xmlstr_to_string(r.name as *const xmlChar)
3387 };
3388 let depth = r.Depth();
3389 result.push((ntype, name, depth));
3390 }
3391 result
3392 }
3393
3394 #[test]
3397 fn test_create_reader_from_memory() {
3398 unsafe {
3399 let reader = create_reader("<root/>");
3400 assert!(!reader.is_null());
3401 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3402 free_reader(reader);
3403 }
3404 }
3405
3406 #[test]
3407 fn test_read_simple_document() {
3408 unsafe {
3409 let reader = create_reader("<root><child>text</child></root>");
3410 assert!(!reader.is_null());
3411
3412 let nodes = collect_nodes(reader);
3413 assert_eq!(nodes.len(), 5);
3421 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
3422 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
3423 assert_eq!(nodes[2], (ReaderNodeType::TEXT, "#text".to_string(), 2));
3425 assert_eq!(
3426 nodes[3],
3427 (ReaderNodeType::END_ELEMENT, "child".to_string(), 1)
3428 );
3429 assert_eq!(
3430 nodes[4],
3431 (ReaderNodeType::END_ELEMENT, "root".to_string(), 0)
3432 );
3433
3434 assert_eq!((*reader).ReadState(), ReadState::EOF);
3435 free_reader(reader);
3436 }
3437 }
3438
3439 #[test]
3440 fn test_read_state_transitions() {
3441 unsafe {
3442 let reader = create_reader("<root/>");
3443 assert!(!reader.is_null());
3444 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3445
3446 assert_eq!(xmlTextReaderRead(reader), 1);
3448 assert_eq!((*reader).ReadState(), ReadState::READING);
3449 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3450 assert_eq!((*reader).Depth(), 0);
3451
3452 assert_eq!(xmlTextReaderRead(reader), 0);
3455 assert_eq!((*reader).ReadState(), ReadState::EOF);
3456
3457 free_reader(reader);
3458 }
3459 }
3460
3461 #[test]
3462 fn test_null_reader_returns_error() {
3463 unsafe {
3464 assert_eq!(xmlTextReaderRead(ptr::null_mut()), -1);
3465 assert_eq!(xmlTextReaderDepth(ptr::null_mut()), -1);
3466 assert_eq!(xmlTextReaderNodeType(ptr::null_mut()), -1);
3467 assert!(xmlTextReaderName(ptr::null_mut()).is_null());
3468 assert!(xmlTextReaderValue(ptr::null_mut()).is_null());
3469 assert_eq!(xmlTextReaderHasValue(ptr::null_mut()), 0);
3470 assert_eq!(xmlTextReaderIsEmptyElement(ptr::null_mut()), 0);
3471 assert_eq!(
3472 xmlTextReaderReadState(ptr::null_mut()),
3473 ReadState::ERROR as c_int
3474 );
3475 }
3476 }
3477
3478 #[test]
3479 fn test_xmlFreeTextReader_null() {
3480 unsafe {
3481 xmlFreeTextReader(ptr::null_mut());
3483 }
3484 }
3485
3486 #[test]
3487 fn test_reader_name_and_value() {
3488 unsafe {
3489 let reader = create_reader("<root>hello</root>");
3490 assert!(!reader.is_null());
3491
3492 assert_eq!(xmlTextReaderRead(reader), 1);
3494 let name = xmlTextReaderName(reader);
3495 assert!(!name.is_null());
3496 assert_eq!(xmlstr_to_string(name), "root");
3497 xmlFree(name as *mut c_void);
3498
3499 assert_eq!(xmlTextReaderHasValue(reader), 0);
3500
3501 assert_eq!(xmlTextReaderRead(reader), 1);
3503 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3504 assert_eq!((*reader).HasValue(), 1);
3505
3506 let val = xmlTextReaderValue(reader);
3507 assert!(!val.is_null());
3508 assert_eq!(xmlstr_to_string(val), "hello");
3509 xmlFree(val as *mut c_void);
3510
3511 free_reader(reader);
3512 }
3513 }
3514
3515 #[test]
3516 fn test_empty_element() {
3517 unsafe {
3518 let reader = create_reader("<empty/>");
3519 assert!(!reader.is_null());
3520
3521 assert_eq!(xmlTextReaderRead(reader), 1);
3522 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3523 assert_eq!((*reader).IsEmptyElement(), 1);
3524 assert_eq!((*reader).HasAttributes(), 0);
3525 assert_eq!((*reader).AttributeCount(), 0);
3526
3527 assert_eq!(xmlTextReaderRead(reader), 0);
3530 assert_eq!((*reader).ReadState(), ReadState::EOF);
3531
3532 free_reader(reader);
3533 }
3534 }
3535
3536 #[test]
3537 fn test_element_with_attributes() {
3538 unsafe {
3539 let reader = create_reader(r#"<root a="1" b="2"/>"#);
3540 assert!(!reader.is_null());
3541
3542 assert_eq!(xmlTextReaderRead(reader), 1);
3543 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3544 assert_eq!((*reader).HasAttributes(), 1);
3545
3546 let attrs = xmlTextReaderAttributeCount(reader);
3549 assert_eq!(attrs, 2);
3550
3551 free_reader(reader);
3552 }
3553 }
3554
3555 #[test]
3556 fn test_attribute_navigation() {
3557 unsafe {
3558 let reader = create_reader(r#"<root a="1" b="2"></root>"#);
3559 assert!(!reader.is_null());
3560
3561 assert_eq!(xmlTextReaderRead(reader), 1);
3563 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3564
3565 assert_eq!(xmlTextReaderMoveToFirstAttribute(reader), 1);
3567 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3568
3569 let name = xmlTextReaderConstName(reader);
3570 assert!(!name.is_null());
3571 assert_eq!(xmlstr_to_bytes(name), b"a");
3572
3573 let val = xmlTextReaderConstValue(reader);
3574 assert!(!val.is_null());
3575 assert_eq!(xmlstr_to_bytes(val), b"1");
3576
3577 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 1);
3579 let name = xmlTextReaderConstName(reader);
3580 assert!(!name.is_null());
3581 assert_eq!(xmlstr_to_bytes(name), b"b");
3582 let val = xmlTextReaderConstValue(reader);
3583 assert!(!val.is_null());
3584 assert_eq!(xmlstr_to_bytes(val), b"2");
3585
3586 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 0);
3588
3589 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3591 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3592
3593 assert_eq!(
3595 xmlTextReaderMoveToAttribute(reader, b"a\0" as *const u8 as *const xmlChar),
3596 1
3597 );
3598 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3599
3600 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3602 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 1), 1);
3603 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3604
3605 free_reader(reader);
3606 }
3607 }
3608
3609 #[test]
3610 fn test_get_attribute() {
3611 unsafe {
3612 let reader = create_reader(r#"<root a="hello" b="world"/>"#);
3613 assert!(!reader.is_null());
3614
3615 assert_eq!(xmlTextReaderRead(reader), 1);
3616
3617 let val = xmlTextReaderGetAttribute(reader, b"a\0" as *const u8 as *const xmlChar);
3619 assert!(!val.is_null());
3620 assert_eq!(xmlstr_to_bytes(val), b"hello");
3621 xmlFree(val as *mut c_void);
3622
3623 let val = xmlTextReaderGetAttribute(reader, b"b\0" as *const u8 as *const xmlChar);
3624 assert!(!val.is_null());
3625 assert_eq!(xmlstr_to_bytes(val), b"world");
3626 xmlFree(val as *mut c_void);
3627
3628 let val = xmlTextReaderGetAttribute(reader, b"c\0" as *const u8 as *const xmlChar);
3630 assert!(val.is_null());
3631
3632 let val = xmlTextReaderGetAttributeNo(reader, 0);
3634 assert!(!val.is_null());
3635 assert_eq!(xmlstr_to_bytes(val), b"hello");
3636 xmlFree(val as *mut c_void);
3637
3638 let val = xmlTextReaderGetAttributeNo(reader, 1);
3639 assert!(!val.is_null());
3640 assert_eq!(xmlstr_to_bytes(val), b"world");
3641 xmlFree(val as *mut c_void);
3642
3643 let val = xmlTextReaderGetAttributeNo(reader, 2);
3644 assert!(val.is_null());
3645
3646 free_reader(reader);
3647 }
3648 }
3649
3650 #[test]
3651 fn test_depth_tracking() {
3652 unsafe {
3653 let reader = create_reader("<a><b><c/></b></a>");
3654 assert!(!reader.is_null());
3655
3656 let nodes = collect_nodes(reader);
3657 assert_eq!(nodes.len(), 5);
3662 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);
3669 }
3670 }
3671
3672 #[test]
3673 fn test_multiple_siblings() {
3674 unsafe {
3675 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3676 assert!(!reader.is_null());
3677
3678 let nodes = collect_nodes(reader);
3679 assert_eq!(nodes.len(), 11);
3684
3685 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "a".to_string(), 1));
3687 assert_eq!(nodes[4], (ReaderNodeType::ELEMENT, "b".to_string(), 1));
3688 assert_eq!(nodes[7], (ReaderNodeType::ELEMENT, "c".to_string(), 1));
3689
3690 free_reader(reader);
3691 }
3692 }
3693
3694 #[test]
3695 fn test_next_skip_to_sibling() {
3696 unsafe {
3697 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3698 assert!(!reader.is_null());
3699
3700 assert_eq!(xmlTextReaderRead(reader), 1);
3702 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3703
3704 assert_eq!(xmlTextReaderRead(reader), 1);
3706 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3707 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "a");
3708
3709 assert_eq!(xmlTextReaderRead(reader), 1);
3711 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3712
3713 assert_eq!(xmlTextReaderNext(reader), 1);
3715 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3716 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "b");
3717
3718 assert_eq!(xmlTextReaderNext(reader), 1);
3720 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3721 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "c");
3722
3723 assert_eq!(xmlTextReaderNext(reader), 0);
3725
3726 free_reader(reader);
3727 }
3728 }
3729
3730 #[test]
3731 fn test_comment_and_pi_nodes() {
3732 unsafe {
3733 let xml = b"<?pi target?><root><!-- comment -->text</root>\0";
3734 let reader = xmlReaderForMemory(
3735 xml.as_ptr() as *const c_char,
3736 (xml.len() - 1) as c_int,
3737 ptr::null(),
3738 ptr::null(),
3739 0,
3740 );
3741 assert!(!reader.is_null());
3742
3743 let nodes = collect_nodes(reader);
3744 assert!(!nodes.is_empty(), "no nodes collected: {:?}", nodes);
3747
3748 assert_eq!(
3750 nodes[0].0,
3751 ReaderNodeType::PROCESSING_INSTRUCTION,
3752 "expected PI at nodes[0], got {:?} name={}",
3753 nodes[0].0,
3754 nodes[0].1
3755 );
3756 assert_eq!(
3757 nodes[0].0,
3758 ReaderNodeType::PROCESSING_INSTRUCTION,
3759 "expected PI at nodes[0], got {:?} name={}",
3760 nodes[0].0,
3761 nodes[0].1
3762 );
3763
3764 let root_idx = nodes
3766 .iter()
3767 .position(|(t, n, _)| *t == ReaderNodeType::ELEMENT && n == "root");
3768 assert!(
3769 root_idx.is_some(),
3770 "no ELEMENT root found in nodes: {:?}",
3771 nodes
3772 .iter()
3773 .map(|(t, n, _)| format!("{:?}:{}", t, n))
3774 .collect::<Vec<_>>()
3775 );
3776
3777 let comment_idx = nodes
3779 .iter()
3780 .position(|(t, _, _)| *t == ReaderNodeType::COMMENT);
3781 assert!(comment_idx.is_some(), "no COMMENT found");
3782
3783 let text_idx = nodes
3785 .iter()
3786 .position(|(t, _, _)| *t == ReaderNodeType::TEXT);
3787 assert!(text_idx.is_some(), "no TEXT found");
3788
3789 free_reader(reader);
3790 }
3791 }
3792
3793 #[test]
3794 fn test_local_name() {
3795 unsafe {
3796 let reader = create_reader("<root/>");
3798 assert!(!reader.is_null());
3799
3800 assert_eq!(xmlTextReaderRead(reader), 1);
3801 let local = xmlTextReaderLocalName(reader);
3802 assert!(!local.is_null());
3803 assert_eq!(xmlstr_to_bytes(local), b"root");
3804 xmlFree(local as *mut c_void);
3805
3806 free_reader(reader);
3807 }
3808 }
3809
3810 #[test]
3811 fn test_base_uri() {
3812 unsafe {
3813 let reader = create_reader("<root/>");
3814 assert!(!reader.is_null());
3815
3816 assert_eq!(xmlTextReaderRead(reader), 1);
3817 let uri = xmlTextReaderBaseUri(reader);
3819 assert!(uri.is_null());
3820
3821 free_reader(reader);
3822 }
3823 }
3824
3825 #[test]
3826 fn test_lookup_namespace() {
3827 unsafe {
3828 let reader = create_reader(r#"<root xmlns:ns="http://example.com"><ns:child/></root>"#);
3829 assert!(!reader.is_null());
3830
3831 assert_eq!(xmlTextReaderRead(reader), 1);
3833 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3834
3835 assert_eq!(xmlTextReaderRead(reader), 1);
3837
3838 let uri = xmlTextReaderLookupNamespace(reader, b"ns\0" as *const u8 as *const xmlChar);
3840 assert!(!uri.is_null());
3841 assert_eq!(xmlstr_to_bytes(uri), b"http://example.com");
3842 xmlFree(uri as *mut c_void);
3843
3844 let uri = xmlTextReaderLookupNamespace(reader, ptr::null());
3846 assert!(uri.is_null());
3847
3848 let uri = xmlTextReaderLookupNamespace(
3850 reader,
3851 b"nonexistent\0" as *const u8 as *const xmlChar,
3852 );
3853 assert!(uri.is_null());
3854
3855 free_reader(reader);
3856 }
3857 }
3858
3859 #[test]
3860 fn test_parser_properties() {
3861 unsafe {
3862 let reader = create_reader("<root/>");
3863 assert!(!reader.is_null());
3864
3865 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);
3873 assert_eq!(xmlTextReaderGetParserProp(reader, 1), 1);
3874
3875 assert_eq!(xmlTextReaderSetParserProp(reader, 4, 1), 0);
3876 assert_eq!(xmlTextReaderGetParserProp(reader, 4), 1);
3877
3878 assert_eq!(xmlTextReaderGetParserProp(reader, 99), -1);
3880 assert_eq!(xmlTextReaderSetParserProp(reader, 99, 1), -1);
3881
3882 free_reader(reader);
3883 }
3884 }
3885
3886 #[test]
3887 fn test_current_doc() {
3888 unsafe {
3889 let reader = create_reader("<root/>");
3890 assert!(!reader.is_null());
3891
3892 assert!((*reader).CurrentDoc().is_null());
3894
3895 assert_eq!(xmlTextReaderRead(reader), 1);
3897 let doc = xmlTextReaderCurrentDoc(reader);
3898 assert!(!doc.is_null());
3899
3900 free_reader(reader);
3901 }
3902 }
3903
3904 #[test]
3905 fn test_free_reader_after_read() {
3906 unsafe {
3907 let reader = create_reader("<root><child/></root>");
3908 assert!(!reader.is_null());
3909
3910 while xmlTextReaderRead(reader) > 0 {}
3912 assert_eq!((*reader).ReadState(), ReadState::EOF);
3913
3914 free_reader(reader);
3916 }
3917 }
3918
3919 #[test]
3920 fn test_reader_for_memory_null_buffer() {
3921 unsafe {
3922 let reader = xmlReaderForMemory(ptr::null(), 10, ptr::null(), ptr::null(), 0);
3923 assert!(reader.is_null());
3924 }
3925 }
3926
3927 #[test]
3928 fn test_reader_for_memory_empty_size() {
3929 unsafe {
3930 let data = b"<root/>";
3931 let reader = xmlReaderForMemory(
3932 data.as_ptr() as *const c_char,
3933 0,
3934 ptr::null(),
3935 ptr::null(),
3936 0,
3937 );
3938 assert!(reader.is_null());
3939 }
3940 }
3941
3942 #[test]
3943 fn test_reader_for_file_not_found() {
3944 unsafe {
3945 let filename = b"/nonexistent/file.xml\0" as *const u8 as *const c_char;
3946 let reader = xmlReaderForFile(filename, ptr::null(), 0);
3947 assert!(reader.is_null());
3948 }
3949 }
3950
3951 #[test]
3952 fn test_const_name_and_value() {
3953 unsafe {
3954 let reader = create_reader("<root>text</root>");
3955 assert!(!reader.is_null());
3956
3957 assert_eq!(xmlTextReaderRead(reader), 1);
3959 let cname = xmlTextReaderConstName(reader);
3960 assert!(!cname.is_null());
3961 assert_eq!(xmlstr_to_bytes(cname), b"root");
3962
3963 assert_eq!(xmlTextReaderRead(reader), 1);
3965 let cval = xmlTextReaderConstValue(reader);
3966 assert!(!cval.is_null());
3967 assert_eq!(xmlstr_to_bytes(cval), b"text");
3968
3969 free_reader(reader);
3970 }
3971 }
3972
3973 #[test]
3974 fn test_complex_nested_document() {
3975 unsafe {
3976 let xml = r#"<?xml version="1.0"?>
3977<library>
3978 <book id="1">
3979 <title>XML Fundamentals</title>
3980 <author>John Doe</author>
3981 </book>
3982 <book id="2">
3983 <title>XSLT Recipes</title>
3984 <author>Jane Smith</author>
3985 </book>
3986</library>"#;
3987
3988 let reader = create_reader(xml);
3989 assert!(!reader.is_null());
3990
3991 let mut element_count = 0;
3992 let mut end_element_count = 0;
3993 let mut text_count = 0;
3994 let mut pi_count = 0;
3995
3996 loop {
3997 let ret = xmlTextReaderRead(reader);
3998 if ret <= 0 {
3999 break;
4000 }
4001 match (*reader).NodeType() {
4002 ReaderNodeType::ELEMENT => element_count += 1,
4003 ReaderNodeType::END_ELEMENT => end_element_count += 1,
4004 ReaderNodeType::TEXT => text_count += 1,
4005 ReaderNodeType::PROCESSING_INSTRUCTION => pi_count += 1,
4006 _ => {}
4007 }
4008 }
4009
4010 assert_eq!(element_count, 7);
4012 assert_eq!(end_element_count, 7);
4014 assert_eq!(text_count, 4);
4016 assert_eq!(pi_count, 0);
4021
4022 free_reader(reader);
4023 }
4024 }
4025
4026 #[test]
4027 fn test_setup_reinitialize() {
4028 unsafe {
4029 let reader = create_reader("<root/>");
4030 assert!(!reader.is_null());
4031
4032 assert_eq!(xmlTextReaderRead(reader), 1);
4034 assert_eq!((*reader).ReadState(), ReadState::READING);
4035
4036 assert_eq!(
4040 xmlTextReaderSetup(reader, ptr::null_mut(), ptr::null(), ptr::null(), 0),
4041 0
4042 );
4043 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
4044
4045 free_reader(reader);
4046 }
4047 }
4048
4049 #[test]
4050 fn test_has_attributes_on_non_element() {
4051 unsafe {
4052 let reader = create_reader("<root>text</root>");
4053 assert!(!reader.is_null());
4054
4055 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0); assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0);
4060
4061 free_reader(reader);
4062 }
4063 }
4064
4065 #[test]
4066 fn test_prev_sibling() {
4067 unsafe {
4068 let reader = create_reader("<root><a/><b/><c/></root>");
4069 assert!(!reader.is_null());
4070
4071 while xmlTextReaderRead(reader) > 0 {
4073 }
4075
4076 assert_eq!(xmlTextReaderPrev(reader), -1);
4078
4079 free_reader(reader);
4080 }
4081 }
4082
4083 #[test]
4084 fn test_move_to_attribute_no_not_on_element() {
4085 unsafe {
4086 let reader = create_reader("<root>text</root>");
4087 assert!(!reader.is_null());
4088
4089 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4091
4092 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 0), 0);
4094
4095 free_reader(reader);
4096 }
4097 }
4098
4099 #[test]
4100 fn test_get_attribute_ns() {
4101 unsafe {
4102 let reader = create_reader(r#"<root a="1" b="2"/>"#);
4103 assert!(!reader.is_null());
4104
4105 assert_eq!(xmlTextReaderRead(reader), 1);
4106
4107 let val = xmlTextReaderGetAttributeNs(
4109 reader,
4110 b"a\0" as *const u8 as *const xmlChar,
4111 ptr::null(),
4112 );
4113 assert!(!val.is_null());
4114 assert_eq!(xmlstr_to_bytes(val), b"1");
4115 xmlFree(val as *mut c_void);
4116
4117 free_reader(reader);
4118 }
4119 }
4120
4121 #[test]
4122 fn test_mixed_content() {
4123 unsafe {
4124 let reader = create_reader("<root>before<child/>after</root>");
4125 assert!(!reader.is_null());
4126
4127 let nodes = collect_nodes(reader);
4128 assert_eq!(nodes.len(), 5);
4133 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
4134 assert_eq!(nodes[1].0, ReaderNodeType::TEXT);
4135 assert_eq!(nodes[2], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
4136 assert_eq!(nodes[3].0, ReaderNodeType::TEXT);
4137
4138 free_reader(reader);
4139 }
4140 }
4141
4142 #[test]
4143 fn test_error_handling_invalid_xml() {
4144 unsafe {
4145 let data = b"<root><\0" as *const u8 as *const c_char;
4147 let reader = xmlReaderForMemory(data, 7, ptr::null(), ptr::null(), 0);
4148 assert!(!reader.is_null());
4149
4150 let ret = xmlTextReaderRead(reader);
4152 assert!(ret == -1 || ret == 0);
4153
4154 free_reader(reader);
4155 }
4156 }
4157
4158 #[test]
4159 fn test_reader_with_options() {
4160 unsafe {
4161 let data = b"<root/>\0" as *const u8 as *const c_char;
4162 let reader = xmlReaderForMemory(
4163 data,
4164 7,
4165 ptr::null(),
4166 ptr::null(),
4167 XML_PARSE_NOENT | XML_PARSE_DTDLOAD,
4168 );
4169 assert!(!reader.is_null());
4170
4171 assert_eq!((*reader).options & XML_PARSE_NOENT, XML_PARSE_NOENT);
4173 assert_eq!((*reader).options & XML_PARSE_DTDLOAD, XML_PARSE_DTDLOAD);
4174
4175 assert_eq!(xmlTextReaderRead(reader), 1);
4176 free_reader(reader);
4177 }
4178 }
4179
4180 #[test]
4181 fn test_reader_for_fd() {
4182 unsafe {
4183 let tmp_path = "/tmp/libxml_rs_test_reader_fd.xml";
4185 let tmp_cstr = std::ffi::CString::new(tmp_path).unwrap();
4186 let content = b"<root><data/></root>";
4187 let fd = libc::open(
4188 tmp_cstr.as_ptr(),
4189 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
4190 0o644,
4191 );
4192 assert!(fd >= 0);
4193 libc::write(fd, content.as_ptr() as *const c_void, content.len());
4194 libc::close(fd);
4195
4196 let fd = libc::open(tmp_cstr.as_ptr(), libc::O_RDONLY, 0);
4198 assert!(fd >= 0);
4199
4200 let reader = xmlReaderForFd(fd, ptr::null(), ptr::null(), 0);
4201 assert!(!reader.is_null());
4202
4203 let nodes = collect_nodes(reader);
4204 assert_eq!(nodes.len(), 3);
4207
4208 free_reader(reader);
4209 libc::close(fd);
4210 std::fs::remove_file(tmp_path).ok();
4211 }
4212 }
4213
4214 #[test]
4215 fn test_reader_for_io() {
4216 unsafe {
4217 extern "C" fn io_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
4218 if context.is_null() || buffer.is_null() || len <= 0 {
4219 return -1;
4220 }
4221 let ctx = unsafe { &mut *(context as *mut IoCtx) };
4223 if ctx.pos >= ctx.data.len() {
4224 return 0;
4225 }
4226 let remaining = ctx.data.len() - ctx.pos;
4227 let to_copy = if (remaining as c_int) < len {
4228 remaining
4229 } else {
4230 len as usize
4231 };
4232 unsafe {
4234 std::ptr::copy_nonoverlapping(
4235 ctx.data.as_ptr().add(ctx.pos),
4236 buffer as *mut u8,
4237 to_copy,
4238 );
4239 }
4240 ctx.pos += to_copy;
4241 to_copy as c_int
4242 }
4243
4244 extern "C" fn io_close(_context: *mut c_void) -> c_int {
4245 0
4246 }
4247
4248 struct IoCtx {
4249 data: &'static [u8],
4250 pos: usize,
4251 }
4252 let mut ctx = IoCtx {
4253 data: b"<root/>",
4254 pos: 0,
4255 };
4256
4257 let reader = xmlReaderForIO(
4258 Some(io_read),
4259 Some(io_close),
4260 &mut ctx as *mut IoCtx as *mut c_void,
4261 ptr::null(),
4262 ptr::null(),
4263 0,
4264 );
4265 assert!(!reader.is_null());
4266
4267 assert_eq!(xmlTextReaderRead(reader), 1);
4269 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4270 let cname = xmlTextReaderConstName(reader);
4271 assert!(!cname.is_null());
4272 assert_eq!(xmlstr_to_bytes(cname), b"root");
4273
4274 assert_eq!(xmlTextReaderRead(reader), 0);
4277
4278 free_reader(reader);
4279 }
4280 }
4281}
4282
4283pub const XML_PARSER_SEVERITY_VALIDITY_WARNING: c_int = 1;
4289pub const XML_PARSER_SEVERITY_VALIDITY_ERROR: c_int = 2;
4290pub const XML_PARSER_SEVERITY_WARNING: c_int = 3;
4291pub const XML_PARSER_SEVERITY_ERROR: c_int = 4;
4292
4293#[repr(C)]
4296pub struct XmlTextReaderLocator {
4297 pub reader: *mut XmlTextReader,
4298}
4299
4300pub type xmlTextReaderErrorFunc = unsafe extern "C" fn(
4302 arg: *mut c_void,
4303 msg: *const c_char,
4304 severity: c_int,
4305 locator: *mut XmlTextReaderLocator,
4306);
4307
4308#[no_mangle]
4315pub unsafe extern "C" fn xmlReaderForDoc(
4316 cur: *const xmlChar,
4317 URL: *const c_char,
4318 encoding: *const c_char,
4319 options: c_int,
4320) -> *mut XmlTextReader {
4321 if cur.is_null() {
4322 return ptr::null_mut();
4323 }
4324 let len = unsafe { libc::strlen(cur as *const libc::c_char) } as c_int;
4325 unsafe { xmlReaderForMemory(cur as *const c_char, len, URL, encoding, options) }
4326}
4327
4328#[no_mangle]
4330pub unsafe extern "C" fn xmlNewTextReaderFilename(
4331 URI: *const c_char,
4332 encoding: *const c_char,
4333 options: c_int,
4334) -> *mut XmlTextReader {
4335 unsafe { xmlReaderForFile(URI, encoding, options) }
4336}
4337
4338unsafe fn reader_renew(reader: *mut XmlTextReader, new_reader: *mut XmlTextReader) {
4350 debug_assert!(!reader.is_null() && !new_reader.is_null() && reader != new_reader);
4351 unsafe {
4352 core::ptr::drop_in_place(reader);
4356 core::ptr::copy_nonoverlapping(new_reader, reader, 1);
4357 let layout = std::alloc::Layout::new::<XmlTextReader>();
4358 std::alloc::dealloc(new_reader as *mut u8, layout);
4359 }
4360}
4361
4362#[no_mangle]
4364pub unsafe extern "C" fn xmlReaderNewDoc(
4365 reader: *mut XmlTextReader,
4366 cur: *const xmlChar,
4367 URL: *const c_char,
4368 encoding: *const c_char,
4369 options: c_int,
4370) -> c_int {
4371 if reader.is_null() || cur.is_null() {
4374 return -1;
4375 }
4376 let r = unsafe { xmlReaderForDoc(cur, URL, encoding, options) };
4377 if r.is_null() {
4378 return -1;
4379 }
4380 unsafe { reader_renew(reader, r) };
4381 0
4382}
4383
4384#[no_mangle]
4386pub unsafe extern "C" fn xmlReaderNewFile(
4387 reader: *mut XmlTextReader,
4388 filename: *const c_char,
4389 encoding: *const c_char,
4390 options: c_int,
4391) -> c_int {
4392 if reader.is_null() {
4393 return -1;
4394 }
4395 let r = unsafe { xmlReaderForFile(filename, encoding, options) };
4396 if r.is_null() {
4397 return -1;
4398 }
4399 unsafe { reader_renew(reader, r) };
4400 0
4401}
4402
4403#[no_mangle]
4405pub unsafe extern "C" fn xmlReaderNewMemory(
4406 reader: *mut XmlTextReader,
4407 buffer: *const c_char,
4408 size: c_int,
4409 URL: *const c_char,
4410 encoding: *const c_char,
4411 options: c_int,
4412) -> c_int {
4413 if reader.is_null() || buffer.is_null() {
4414 return -1;
4415 }
4416 let r = unsafe { xmlReaderForMemory(buffer, size, URL, encoding, options) };
4417 if r.is_null() {
4418 return -1;
4419 }
4420 unsafe { reader_renew(reader, r) };
4421 0
4422}
4423
4424#[no_mangle]
4426pub unsafe extern "C" fn xmlReaderNewFd(
4427 reader: *mut XmlTextReader,
4428 fd: c_int,
4429 URL: *const c_char,
4430 encoding: *const c_char,
4431 options: c_int,
4432) -> c_int {
4433 if reader.is_null() {
4434 return -1;
4435 }
4436 let r = unsafe { xmlReaderForFd(fd, URL, encoding, options) };
4437 if r.is_null() {
4438 return -1;
4439 }
4440 unsafe { reader_renew(reader, r) };
4441 0
4442}
4443
4444#[no_mangle]
4446pub unsafe extern "C" fn xmlReaderNewIO(
4447 reader: *mut XmlTextReader,
4448 ioread: Option<xmlInputReadCallback>,
4449 ioclose: Option<xmlInputCloseCallback>,
4450 ioctx: *mut c_void,
4451 URL: *const c_char,
4452 encoding: *const c_char,
4453 options: c_int,
4454) -> c_int {
4455 if reader.is_null() || ioread.is_none() {
4457 return -1;
4458 }
4459 let r = unsafe { xmlReaderForIO(ioread, ioclose, ioctx, URL, encoding, options) };
4460 if r.is_null() {
4461 return -1;
4462 }
4463 unsafe { reader_renew(reader, r) };
4464 0
4465}
4466
4467#[no_mangle]
4474pub unsafe extern "C" fn xmlReaderWalker(doc: *mut _xmlDoc) -> *mut XmlTextReader {
4475 if doc.is_null() {
4476 return ptr::null_mut();
4477 }
4478 let mut reader = XmlTextReader::new(ptr::null_mut(), None, None);
4479 reader.doc = doc;
4480 reader.parsed = true;
4481 reader.owns_doc = false; reader.state = ReadState::READING;
4483 reader.build_events();
4484 Box::into_raw(Box::new(reader))
4485}
4486
4487#[no_mangle]
4489pub unsafe extern "C" fn xmlReaderNewWalker(
4490 reader: *mut XmlTextReader,
4491 doc: *mut _xmlDoc,
4492) -> c_int {
4493 if reader.is_null() || doc.is_null() {
4495 return -1;
4496 }
4497 let r = unsafe { xmlReaderWalker(doc) };
4498 if r.is_null() {
4499 return -1;
4500 }
4501 unsafe { reader_renew(reader, r) };
4502 0
4503}
4504
4505#[no_mangle]
4510pub unsafe extern "C" fn xmlTextReaderByteConsumed(reader: *mut XmlTextReader) -> c_long {
4511 if reader.is_null() {
4512 return -1;
4513 }
4514 0
4515}
4516
4517#[no_mangle]
4520pub unsafe extern "C" fn xmlTextReaderConstBaseUri(reader: *mut XmlTextReader) -> *const xmlChar {
4521 if reader.is_null() {
4522 return ptr::null();
4523 }
4524 unsafe { (*reader).URL }
4525}
4526
4527#[no_mangle]
4529pub unsafe extern "C" fn xmlTextReaderConstEncoding(reader: *mut XmlTextReader) -> *const xmlChar {
4530 if reader.is_null() {
4531 return ptr::null();
4532 }
4533 let r = unsafe { &*reader };
4534 if !r.encoding.is_null() {
4535 return r.encoding;
4536 }
4537 if !r.doc.is_null() {
4538 return unsafe { (*r.doc).encoding };
4539 }
4540 ptr::null()
4541}
4542
4543#[no_mangle]
4549pub unsafe extern "C" fn xmlTextReaderConstLocalName(reader: *mut XmlTextReader) -> *const xmlChar {
4550 if reader.is_null() {
4551 return ptr::null();
4552 }
4553 let r = unsafe { &*reader };
4554 if r.cur_node.is_null() {
4555 return ptr::null();
4556 }
4557 if r.cur_attribute >= 0 {
4560 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4561 return match target {
4562 AttrTarget::Ns(ns) => {
4563 if ns.is_null() {
4564 ptr::null()
4565 } else if unsafe { (*ns).prefix }.is_null() {
4566 b"xmlns\0".as_ptr() as *const xmlChar
4567 } else {
4568 unsafe { (*ns).prefix }
4569 }
4570 }
4571 AttrTarget::Prop(p) => {
4572 if p.is_null() || unsafe { (*p).name }.is_null() {
4573 ptr::null()
4574 } else {
4575 unsafe { (*p).name }
4576 }
4577 }
4578 AttrTarget::None => ptr::null(),
4579 };
4580 }
4581 let etype = unsafe { (*r.cur_node).type_ };
4583 if etype == XML_ELEMENT_NODE as c_int || etype == XML_ATTRIBUTE_NODE as c_int {
4584 unsafe { (*r.cur_node).name }
4585 } else {
4586 ptr::null()
4587 }
4588}
4589
4590#[no_mangle]
4595pub unsafe extern "C" fn xmlTextReaderConstNamespaceUri(
4596 reader: *mut XmlTextReader,
4597) -> *const xmlChar {
4598 if reader.is_null() {
4599 return ptr::null();
4600 }
4601 let r = unsafe { &*reader };
4602 if r.cur_node.is_null() {
4603 return ptr::null();
4604 }
4605 if r.cur_attribute >= 0 {
4607 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4608 return match target {
4609 AttrTarget::Ns(_ns) => {
4610 b"http://www.w3.org/2000/xmlns/\0".as_ptr() as *const xmlChar
4614 }
4615 AttrTarget::Prop(p) => {
4616 if p.is_null() || unsafe { (*p).ns }.is_null() {
4617 ptr::null()
4618 } else {
4619 unsafe { (*(*p).ns).href }
4620 }
4621 }
4622 AttrTarget::None => ptr::null(),
4623 };
4624 }
4625 let ns = unsafe { (*r.cur_node).ns };
4626 if ns.is_null() || unsafe { (*ns).href }.is_null() {
4627 ptr::null()
4628 } else {
4629 unsafe { (*ns).href }
4630 }
4631}
4632
4633#[no_mangle]
4639pub unsafe extern "C" fn xmlTextReaderConstPrefix(reader: *mut XmlTextReader) -> *const xmlChar {
4640 if reader.is_null() {
4641 return ptr::null();
4642 }
4643 let r = unsafe { &*reader };
4644 if r.cur_node.is_null() {
4645 return ptr::null();
4646 }
4647 if r.cur_attribute >= 0 {
4649 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4650 return match target {
4651 AttrTarget::Ns(ns) => {
4652 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4653 ptr::null()
4654 } else {
4655 b"xmlns\0".as_ptr() as *const xmlChar
4656 }
4657 }
4658 AttrTarget::Prop(p) => {
4659 if p.is_null() || unsafe { (*p).ns }.is_null() {
4660 ptr::null()
4661 } else {
4662 unsafe { (*(*p).ns).prefix }
4663 }
4664 }
4665 AttrTarget::None => ptr::null(),
4666 };
4667 }
4668 let ns = unsafe { (*r.cur_node).ns };
4669 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4670 ptr::null()
4671 } else {
4672 unsafe { (*ns).prefix }
4673 }
4674}
4675
4676#[no_mangle]
4680pub unsafe extern "C" fn xmlTextReaderConstString(
4681 _reader: *mut XmlTextReader,
4682 str: *const xmlChar,
4683) -> *const xmlChar {
4684 str
4685}
4686
4687#[no_mangle]
4689pub unsafe extern "C" fn xmlTextReaderConstXmlLang(reader: *mut XmlTextReader) -> *const xmlChar {
4690 if reader.is_null() {
4691 return ptr::null();
4692 }
4693 let r = unsafe { &*reader };
4694 let mut node = r.cur_node;
4695 while !node.is_null() {
4696 let mut prop = unsafe { (*node).properties };
4697 while !prop.is_null() {
4698 let p = unsafe { &*prop };
4699 if !p.name.is_null()
4700 && unsafe { *p.name } == b'x'
4701 && unsafe { *p.name.add(1) } == b'm'
4702 && unsafe { *p.name.add(2) } == b'l'
4703 && unsafe { *p.name.add(3) } == b':'
4704 && unsafe { *p.name.add(4) } == b'l'
4705 && unsafe { *p.name.add(5) } == b'a'
4706 && unsafe { *p.name.add(6) } == b'n'
4707 && unsafe { *p.name.add(7) } == b'g'
4708 && unsafe { *p.name.add(8) } == 0
4709 {
4710 if !p.children.is_null() {
4711 let txt = p.children;
4712 if unsafe { (*txt).type_ }
4713 == crate::abi::types::xmlElementType::XML_TEXT_NODE as c_int
4714 {
4715 return unsafe { (*txt).content };
4716 }
4717 }
4718 return ptr::null();
4719 }
4720 prop = p.next;
4721 }
4722 node = unsafe { (*node).parent };
4723 }
4724 ptr::null()
4725}
4726
4727#[no_mangle]
4729pub unsafe extern "C" fn xmlTextReaderConstXmlVersion(
4730 reader: *mut XmlTextReader,
4731) -> *const xmlChar {
4732 if reader.is_null() {
4733 return ptr::null();
4734 }
4735 let r = unsafe { &*reader };
4736 if r.doc.is_null() {
4737 return ptr::null();
4738 }
4739 unsafe { (*r.doc).version }
4740}
4741
4742#[no_mangle]
4749pub unsafe extern "C" fn xmlTextReaderQuoteChar(reader: *mut XmlTextReader) -> c_int {
4750 if reader.is_null() {
4751 return -1;
4752 }
4753 b'"' as c_int
4754}
4755
4756#[no_mangle]
4761pub unsafe extern "C" fn xmlTextReaderIsDefault(reader: *mut XmlTextReader) -> c_int {
4762 if reader.is_null() {
4763 return -1;
4764 }
4765 0
4766}
4767
4768#[no_mangle]
4771pub unsafe extern "C" fn xmlTextReaderIsNamespaceDecl(reader: *mut XmlTextReader) -> c_int {
4772 if reader.is_null() {
4773 return -1;
4774 }
4775 let r = unsafe { &*reader };
4776 if r.cur_node.is_null() {
4777 return -1;
4778 }
4779 r.cur_attr_is_ns as c_int
4780}
4781
4782#[no_mangle]
4795pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNs(
4796 reader: *mut XmlTextReader,
4797 localName: *const xmlChar,
4798 namespaceURI: *const xmlChar,
4799) -> c_int {
4800 if reader.is_null() || localName.is_null() || namespaceURI.is_null() {
4801 return -1;
4802 }
4803 let r = unsafe { &mut *reader };
4804 let node = r.cur_node;
4805 if node.is_null() {
4806 return -1;
4807 }
4808 if unsafe { (*node).type_ } != XML_ELEMENT_NODE as c_int {
4809 return 0;
4810 }
4811
4812 const XMLNS_URI: &[u8] = b"http://www.w3.org/2000/xmlns/\0";
4813 if libc::strcmp(
4814 namespaceURI as *const libc::c_char,
4815 XMLNS_URI.as_ptr() as *const libc::c_char,
4816 ) == 0
4817 {
4818 let is_default = libc::strcmp(
4821 localName as *const libc::c_char,
4822 b"xmlns\0".as_ptr() as *const libc::c_char,
4823 ) == 0;
4824 let mut ns = unsafe { (*node).nsDef };
4825 let mut index = 0;
4826 while !ns.is_null() {
4827 let n = unsafe { &*ns };
4828 let prefix_match = if is_default {
4829 n.prefix.is_null()
4830 } else {
4831 !n.prefix.is_null()
4832 && libc::strcmp(
4833 n.prefix as *const libc::c_char,
4834 localName as *const libc::c_char,
4835 ) == 0
4836 };
4837 if prefix_match {
4838 r.cur_attribute = index;
4839 r.node_type = ReaderNodeType::ATTRIBUTE;
4840 r.cache_attribute_info(AttrTarget::Ns(ns));
4841 return 1;
4842 }
4843 index += 1;
4844 ns = unsafe { (*ns).next };
4845 }
4846 return 0;
4847 }
4848
4849 let mut prop = unsafe { (*node).properties };
4851 let mut index = 0;
4852 let mut ns_count = 0;
4853 let mut ns = unsafe { (*node).nsDef };
4854 while !ns.is_null() {
4855 ns_count += 1;
4856 ns = unsafe { (*ns).next };
4857 }
4858 while !prop.is_null() {
4859 let p = unsafe { &*prop };
4860 if !p.name.is_null()
4861 && !p.ns.is_null()
4862 && !(*p.ns).href.is_null()
4863 && libc::strcmp(
4864 p.name as *const libc::c_char,
4865 localName as *const libc::c_char,
4866 ) == 0
4867 && libc::strcmp(
4868 (*p.ns).href as *const libc::c_char,
4869 namespaceURI as *const libc::c_char,
4870 ) == 0
4871 {
4872 r.cur_attribute = ns_count + index;
4873 r.node_type = ReaderNodeType::ATTRIBUTE;
4874 r.cache_attribute_info(AttrTarget::Prop(prop));
4875 return 1;
4876 }
4877 index += 1;
4878 prop = unsafe { (*prop).next };
4879 }
4880 0
4881}
4882
4883#[no_mangle]
4887pub unsafe extern "C" fn xmlTextReaderPreserve(reader: *mut XmlTextReader) -> *mut _xmlNode {
4888 if reader.is_null() {
4889 return ptr::null_mut();
4890 }
4891 unsafe { (*reader).cur_node }
4892}
4893
4894#[no_mangle]
4899pub unsafe extern "C" fn xmlTextReaderPreservePattern(
4900 reader: *mut XmlTextReader,
4901 _pattern: *const xmlChar,
4902 _namespaces: *mut *const xmlChar,
4903) -> c_int {
4904 if reader.is_null() {
4905 return -1;
4906 }
4907 0
4908}
4909
4910#[no_mangle]
4916pub unsafe extern "C" fn xmlTextReaderSetErrorHandler(
4917 reader: *mut XmlTextReader,
4918 f: Option<xmlTextReaderErrorFunc>,
4919 arg: *mut c_void,
4920) {
4921 if reader.is_null() {
4922 return;
4923 }
4924 unsafe {
4925 (*reader).error_handler = f;
4926 (*reader).error_arg = arg;
4927 }
4928}
4929
4930#[no_mangle]
4936pub unsafe extern "C" fn xmlTextReaderGetErrorHandler(
4937 reader: *mut XmlTextReader,
4938 f: *mut Option<xmlTextReaderErrorFunc>,
4939 arg: *mut *mut c_void,
4940) {
4941 if reader.is_null() {
4942 return;
4943 }
4944 unsafe {
4945 if !f.is_null() {
4946 *f = (*reader).error_handler;
4947 }
4948 if !arg.is_null() {
4949 *arg = (*reader).error_arg;
4950 }
4951 }
4952}
4953
4954#[no_mangle]
4956pub unsafe extern "C" fn xmlTextReaderSetStructuredErrorHandler(
4957 reader: *mut XmlTextReader,
4958 f: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4959 arg: *mut c_void,
4960) {
4961 if reader.is_null() {
4962 return;
4963 }
4964 unsafe {
4965 (*reader).structured_handler = f;
4966 (*reader).structured_arg = arg;
4967 }
4968}
4969
4970#[no_mangle]
4975pub unsafe extern "C" fn xmlTextReaderGetLastError(
4976 reader: *mut XmlTextReader,
4977) -> *const crate::abi::structs::_xmlError {
4978 if reader.is_null() {
4979 return ptr::null();
4980 }
4981 let r = unsafe { &mut *reader };
4982 if let Some(msg) = r.errors.last() {
4986 unsafe {
4987 let bytes = msg.as_bytes();
4990 let m = libc::malloc(bytes.len() + 1) as *mut xmlChar;
4991 if !m.is_null() {
4992 libc::memcpy(
4993 m as *mut libc::c_void,
4994 bytes.as_ptr() as *const libc::c_void,
4995 bytes.len(),
4996 );
4997 *m.add(bytes.len()) = 0;
4998 if !r.last_err.message.is_null() {
4999 libc::free(r.last_err.message as *mut libc::c_void);
5000 }
5001 (*reader).last_err.message = m as *mut c_char;
5002 (*reader).last_err.domain = crate::abi::types::XML_FROM_PARSER as c_int;
5003 (*reader).last_err.level = crate::abi::types::xmlErrorLevel::XML_ERR_ERROR as c_int;
5004 (*reader).last_err.code = crate::abi::types::XML_ERR_INTERNAL_ERROR as c_int;
5005 }
5006 }
5007 }
5008 &(*reader).last_err as *const crate::abi::structs::_xmlError
5009}
5010
5011#[no_mangle]
5017pub unsafe extern "C" fn xmlTextReaderLocatorBaseURI(
5018 locator: *mut XmlTextReaderLocator,
5019) -> *mut xmlChar {
5020 if locator.is_null() {
5021 return ptr::null_mut();
5022 }
5023 unsafe {
5024 let r = (*locator).reader;
5025 if r.is_null() {
5026 return ptr::null_mut();
5027 }
5028 xml_strdup((*r).URL)
5029 }
5030}
5031
5032#[no_mangle]
5034pub unsafe extern "C" fn xmlTextReaderLocatorLineNumber(
5035 locator: *mut XmlTextReaderLocator,
5036) -> c_int {
5037 if locator.is_null() {
5038 return -1;
5039 }
5040 unsafe {
5041 let r = (*locator).reader;
5042 if r.is_null() {
5043 return -1;
5044 }
5045 let node = (*r).cur_node;
5046 if node.is_null() {
5047 return -1;
5048 }
5049 (*node).line as c_int
5050 }
5051}
5052
5053#[no_mangle]
5058pub unsafe extern "C" fn xmlTextReaderGetRemainder(
5059 _reader: *mut XmlTextReader,
5060) -> *mut crate::abi::structs::_xmlParserInputBuffer {
5061 ptr::null_mut()
5062}
5063
5064#[no_mangle]
5066pub unsafe extern "C" fn xmlTextReaderSetMaxAmplification(
5067 reader: *mut XmlTextReader,
5068 maxAmpl: c_uint,
5069) {
5070 if reader.is_null() {
5071 return;
5072 }
5073 unsafe { (*reader).max_amplification = maxAmpl as c_int };
5074}
5075
5076#[no_mangle]
5083pub unsafe extern "C" fn xmlTextReaderSchemaValidate(
5084 reader: *mut XmlTextReader,
5085 xsd: *const c_char,
5086) -> c_int {
5087 if reader.is_null() || xsd.is_null() {
5088 return -1;
5089 }
5090 if unsafe { (*reader).doc }.is_null() {
5092 if unsafe { (*reader).parsed } == false {
5093 unsafe { (*reader).Read() };
5094 }
5095 }
5096 let ctxt = crate::xml::schemas::xmlSchemaNewParserCtxt(xsd);
5097 if ctxt.is_null() {
5098 return -1;
5099 }
5100 let schema = crate::xml::schemas::xmlSchemaParse(ctxt);
5101 if schema.is_null() {
5102 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5103 return -1;
5104 }
5105 let vctxt = crate::xml::schemas::xmlSchemaNewValidCtxt(schema);
5106 if vctxt.is_null() {
5107 crate::xml::schemas::xmlSchemaFree(schema);
5108 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5109 return -1;
5110 }
5111 let ret = crate::xml::schemas::xmlSchemaValidateDoc(vctxt, unsafe { (*reader).doc });
5112 crate::xml::schemas::xmlSchemaFreeValidCtxt(vctxt);
5113 crate::xml::schemas::xmlSchemaFree(schema);
5114 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5115 ret
5116}
5117
5118#[no_mangle]
5120pub unsafe extern "C" fn xmlTextReaderSchemaValidateCtxt(
5121 reader: *mut XmlTextReader,
5122 ctxt: *mut c_void,
5123 _options: c_int,
5124) -> c_int {
5125 if reader.is_null() || ctxt.is_null() {
5126 return -1;
5127 }
5128 if unsafe { (*reader).doc }.is_null() {
5129 if unsafe { (*reader).parsed } == false {
5130 unsafe { (*reader).Read() };
5131 }
5132 }
5133 crate::xml::schemas::xmlSchemaValidateDoc(ctxt, unsafe { (*reader).doc })
5134}
5135
5136#[no_mangle]
5138pub unsafe extern "C" fn xmlTextReaderSetSchema(
5139 reader: *mut XmlTextReader,
5140 schema: *mut c_void,
5141) -> c_int {
5142 if reader.is_null() {
5143 return -1;
5144 }
5145 unsafe {
5146 (*reader).schema = schema;
5147 }
5148 0
5149}
5150
5151#[no_mangle]
5153pub unsafe extern "C" fn xmlTextReaderRelaxNGValidate(
5154 reader: *mut XmlTextReader,
5155 rng: *const c_char,
5156) -> c_int {
5157 if reader.is_null() || rng.is_null() {
5158 return -1;
5159 }
5160 if unsafe { (*reader).doc }.is_null() {
5161 if unsafe { (*reader).parsed } == false {
5162 unsafe { (*reader).Read() };
5163 }
5164 }
5165 let ctxt = crate::xml::relaxng::xmlRelaxNGNewParserCtxt(rng);
5166 if ctxt.is_null() {
5167 return -1;
5168 }
5169 let schema = crate::xml::relaxng::xmlRelaxNGParse(ctxt);
5170 if schema.is_null() {
5171 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5172 return -1;
5173 }
5174 let vctxt = crate::xml::relaxng::xmlRelaxNGNewValidCtxt(schema);
5175 if vctxt.is_null() {
5176 crate::xml::relaxng::xmlRelaxNGFree(schema);
5177 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5178 return -1;
5179 }
5180 let ret = crate::xml::relaxng::xmlRelaxNGValidateDoc(vctxt, unsafe { (*reader).doc });
5181 crate::xml::relaxng::xmlRelaxNGFreeValidCtxt(vctxt);
5182 crate::xml::relaxng::xmlRelaxNGFree(schema);
5183 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5184 ret
5185}
5186
5187#[no_mangle]
5189pub unsafe extern "C" fn xmlTextReaderRelaxNGValidateCtxt(
5190 reader: *mut XmlTextReader,
5191 ctxt: *mut c_void,
5192 _options: c_int,
5193) -> c_int {
5194 if reader.is_null() || ctxt.is_null() {
5195 return -1;
5196 }
5197 if unsafe { (*reader).doc }.is_null() {
5198 if unsafe { (*reader).parsed } == false {
5199 unsafe { (*reader).Read() };
5200 }
5201 }
5202 crate::xml::relaxng::xmlRelaxNGValidateDoc(ctxt, unsafe { (*reader).doc })
5203}
5204
5205#[no_mangle]
5207pub unsafe extern "C" fn xmlTextReaderRelaxNGSetSchema(
5208 reader: *mut XmlTextReader,
5209 schema: *mut c_void,
5210) -> c_int {
5211 if reader.is_null() {
5212 return -1;
5213 }
5214 unsafe {
5215 (*reader).rng = schema;
5216 }
5217 0
5218}