1#![allow(
24 missing_docs,
25 non_snake_case,
26 non_camel_case_types,
27 non_upper_case_globals
28)]
29
30use core::ffi::c_void;
31use core::ptr;
32use std::os::raw::{c_char, c_int, c_long, c_uint};
33
34use crate::abi::allocator::xmlFreeImpl;
35use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
36use crate::abi::structs::{_xmlAttr, _xmlDoc, _xmlNode, _xmlParserCtxt, _xmlParserInputBuffer};
37
38use crate::abi::types::xmlElementType::*;
39use crate::abi::types::*;
40use crate::xml::parser::helpers::{
41 create_parser_ctxt, free_parser_ctxt, input_from_file, input_from_io, input_from_memory,
42 input_from_memory_named, parse_document, setup_parser_input,
43};
44use crate::xml::parser::input::InputBuffer;
45use crate::xml::string::{bytes_to_xmlstr, xml_strdup, xmlstr_to_bytes, xmlstr_to_string};
46use crate::xml::tree;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79#[repr(i32)]
80pub(crate) enum ReaderNodeType {
81 NONE = 0,
82 ELEMENT = 1,
83 ATTRIBUTE = 2,
84 TEXT = 3,
85 CDATA = 4,
86 ENTITY_REFERENCE = 5,
87 ENTITY = 6,
88 PROCESSING_INSTRUCTION = 7,
89 COMMENT = 8,
90 DOCUMENT = 9,
91 DOCUMENT_TYPE = 10,
92 DOCUMENT_FRAGMENT = 11,
93 NOTATION = 12,
94 WHITESPACE = 13,
95 SIGNIFICANT_WHITESPACE = 14,
96 END_ELEMENT = 15,
97 END_ENTITY = 16,
98 XML_DECLARATION = 17,
99 NAMESPACE = 18,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[repr(i32)]
118pub(crate) enum ReadState {
119 NOT_INITIALIZED = 0,
120 INITIALIZED = 1,
121 READING = 2,
122 EOF = 3,
123 CLOSED = 4,
124 ERROR = 5,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140#[repr(i32)]
141pub(crate) enum ParserProp {
142 LOADDTD = 1,
143 DEFAULTATTRS = 2,
144 VALIDATE = 3,
145 SUBST_ENTITIES = 4,
146}
147
148#[derive(Debug, Clone)]
154struct TraversalEvent {
155 node: *mut _xmlNode,
157 is_end: bool,
159 depth: i32,
161}
162
163unsafe fn compute_depth(node: *mut _xmlNode) -> i32 {
171 if node.is_null() {
172 return 0;
173 }
174 let mut depth: i32 = 0;
175 let mut cur = unsafe { (*node).parent };
177 while !cur.is_null() {
178 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
180 depth += 1;
181 }
182 cur = unsafe { (*cur).parent };
184 }
185 depth
186}
187
188fn element_type_to_reader_type(etype: c_int) -> ReaderNodeType {
190 match etype {
191 x if x == XML_ELEMENT_NODE as c_int => ReaderNodeType::ELEMENT,
192 x if x == XML_ATTRIBUTE_NODE as c_int => ReaderNodeType::ATTRIBUTE,
193 x if x == XML_TEXT_NODE as c_int => ReaderNodeType::TEXT,
194 x if x == XML_CDATA_SECTION_NODE as c_int => ReaderNodeType::CDATA,
195 x if x == XML_ENTITY_REF_NODE as c_int => ReaderNodeType::ENTITY_REFERENCE,
196 x if x == XML_ENTITY_NODE as c_int => ReaderNodeType::ENTITY,
197 x if x == XML_PI_NODE as c_int => ReaderNodeType::PROCESSING_INSTRUCTION,
198 x if x == XML_COMMENT_NODE as c_int => ReaderNodeType::COMMENT,
199 x if x == XML_DOCUMENT_NODE as c_int => ReaderNodeType::DOCUMENT,
200 x if x == XML_DOCUMENT_TYPE_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
201 x if x == XML_DOCUMENT_FRAG_NODE as c_int => ReaderNodeType::DOCUMENT_FRAGMENT,
202 x if x == XML_NOTATION_NODE as c_int => ReaderNodeType::NOTATION,
203 x if x == XML_DTD_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
204 x if x == XML_NAMESPACE_DECL as c_int => ReaderNodeType::NONE,
205 _ => ReaderNodeType::NONE,
206 }
207}
208
209fn is_whitespace_only(text: &[u8]) -> bool {
211 text.iter()
212 .all(|&b| b == b' ' || b == b'\t' || b == b'\n' || b == b'\r')
213}
214
215#[derive(Clone, Copy)]
226enum AttrTarget {
227 None,
228 Ns(*mut crate::abi::structs::_xmlNs),
229 Prop(*mut _xmlAttr),
230}
231
232pub(crate) struct XmlTextReader {
233 doc: *mut _xmlDoc,
235 ctxt: *mut _xmlParserCtxt,
237 events: Vec<TraversalEvent>,
239 event_index: usize,
241 state: ReadState,
243 cur_node: *mut _xmlNode,
245 node_type: ReaderNodeType,
247 depth: i32,
249 name: *mut xmlChar,
251 value: *mut xmlChar,
253 attribute_count: i32,
255 cur_attribute: i32,
257 options: c_int,
259 encoding: *mut xmlChar,
261 URL: *mut xmlChar,
263 errors: Vec<String>,
265 parsed: bool,
267 error_handler: Option<xmlTextReaderErrorFunc>,
269 error_arg: *mut c_void,
271 structured_handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
273 structured_arg: *mut c_void,
275 last_err: crate::abi::structs::_xmlError,
277 max_amplification: c_int,
279 schema: *mut c_void,
281 rng: *mut c_void,
283 owns_doc: bool,
285 cur_attr_is_ns: bool,
288}
289
290impl XmlTextReader {
291 unsafe fn new(ctxt: *mut _xmlParserCtxt, URL: Option<&[u8]>, encoding: Option<&[u8]>) -> Self {
301 let url_ptr = URL
302 .map(|u| unsafe { bytes_to_xmlstr(u) })
303 .unwrap_or(ptr::null_mut());
304 let enc_ptr = encoding
305 .map(|e| unsafe { bytes_to_xmlstr(e) })
306 .unwrap_or(ptr::null_mut());
307
308 XmlTextReader {
309 doc: ptr::null_mut(),
310 ctxt,
311 events: Vec::new(),
312 event_index: 0,
313 state: ReadState::INITIALIZED,
314 cur_node: ptr::null_mut(),
315 node_type: ReaderNodeType::NONE,
316 depth: 0,
317 name: ptr::null_mut(),
318 value: ptr::null_mut(),
319 attribute_count: -1,
320 cur_attribute: -1,
321 options: 0,
322 encoding: enc_ptr,
323 URL: url_ptr,
324 errors: Vec::new(),
325 parsed: false,
326 error_handler: None,
327 error_arg: ptr::null_mut(),
328 structured_handler: None,
329 structured_arg: ptr::null_mut(),
330 last_err: unsafe { core::mem::zeroed() },
331 max_amplification: 0,
332 schema: ptr::null_mut(),
333 rng: ptr::null_mut(),
334 owns_doc: true,
335 cur_attr_is_ns: false,
336 }
337 }
338
339 unsafe fn parse_and_build_events(&mut self) -> c_int {
347 if self.ctxt.is_null() {
348 self.state = ReadState::ERROR;
349 self.errors.push("No parser context".to_string());
350 return -1;
351 }
352
353 unsafe {
355 (*self.ctxt).options = self.options;
356 }
357
358 let result = unsafe { parse_document(self.ctxt) };
360
361 let doc = unsafe { (*self.ctxt).myDoc };
363 self.doc = doc;
364
365 if !self.ctxt.is_null() {
367 unsafe { free_parser_ctxt(self.ctxt) };
368 }
369 self.ctxt = ptr::null_mut();
370
371 if result != 0 || doc.is_null() {
372 self.state = ReadState::ERROR;
373 self.errors.push("Failed to parse document".to_string());
374 return -1;
375 }
376
377 if self.encoding.is_null() && !doc.is_null() {
379 let doc_enc = unsafe { (*doc).encoding };
381 if !doc_enc.is_null() {
382 self.encoding = unsafe { xml_strdup(doc_enc as *const xmlChar) };
383 }
384 }
385
386 self.build_events();
388
389 self.parsed = true;
390 0
391 }
392
393 fn build_events(&mut self) {
398 self.events.clear();
399
400 if self.doc.is_null() {
401 return;
402 }
403
404 let root = unsafe { (*self.doc).children };
406 if root.is_null() {
407 return;
408 }
409
410 unsafe {
413 let mut n = root;
414 while !n.is_null() {
415 self.walk_tree(n, 0);
416 n = (*n).next;
417 }
418 }
419 }
420
421 unsafe fn walk_tree(&mut self, node: *mut _xmlNode, depth: i32) {
427 if node.is_null() {
428 return;
429 }
430
431 let node_type = unsafe { (*node).type_ };
433
434 if node_type == XML_ELEMENT_NODE as c_int {
438 self.events.push(TraversalEvent {
439 node,
440 is_end: false,
441 depth,
442 });
443
444 let mut child = unsafe { (*node).children };
447 while !child.is_null() {
448 let child_depth = depth + 1;
449 self.walk_tree(child, child_depth);
450 child = unsafe { (*child).next };
452 }
453
454 if !unsafe { (*node).children }.is_null() {
457 self.events.push(TraversalEvent {
458 node,
459 is_end: true,
460 depth,
461 });
462 }
463 } else if node_type == XML_TEXT_NODE as c_int
464 || node_type == XML_CDATA_SECTION_NODE as c_int
465 || node_type == XML_COMMENT_NODE as c_int
466 || node_type == XML_PI_NODE as c_int
467 || node_type == XML_ENTITY_REF_NODE as c_int
468 {
469 self.events.push(TraversalEvent {
474 node,
475 is_end: false,
476 depth,
477 });
478 } else {
479 self.events.push(TraversalEvent {
481 node,
482 is_end: false,
483 depth,
484 });
485 }
486 }
487
488 fn position_at(&mut self, index: usize) {
492 if index >= self.events.len() {
493 self.state = ReadState::EOF;
494 self.cur_node = ptr::null_mut();
495 self.node_type = ReaderNodeType::NONE;
496 self.depth = 0;
497 self.clear_cached_name();
498 self.clear_cached_value();
499 self.attribute_count = -1;
500 self.cur_attribute = -1;
501 return;
502 }
503
504 let ev_node: *mut _xmlNode;
506 let ev_is_end: bool;
507 let ev_depth: i32;
508 {
509 let event = &self.events[index];
510 ev_node = event.node;
511 ev_is_end = event.is_end;
512 ev_depth = event.depth;
513 }
514
515 self.event_index = index;
516 self.cur_node = ev_node;
517 self.depth = ev_depth;
518
519 let etype = unsafe { (*ev_node).type_ };
521
522 if ev_is_end {
523 self.node_type = ReaderNodeType::END_ELEMENT;
524 } else {
525 self.node_type = element_type_to_reader_type(etype);
526 if etype == XML_TEXT_NODE as c_int || etype == XML_CDATA_SECTION_NODE as c_int {
529 let content = unsafe { (*ev_node).content };
530 if !content.is_null() {
531 let len = unsafe { libc::strlen(content as *const libc::c_char) as usize };
533 let slice = unsafe { core::slice::from_raw_parts(content, len) };
535 if is_whitespace_only(slice) {
536 self.node_type = ReaderNodeType::SIGNIFICANT_WHITESPACE;
537 }
538 }
539 }
540 }
541
542 unsafe { self.cache_name_and_value(ev_node, ev_is_end) };
545
546 if etype == XML_ELEMENT_NODE as c_int && !ev_is_end {
548 self.attribute_count = unsafe { self.count_attributes(ev_node) };
550 } else {
551 self.attribute_count = -1;
552 }
553
554 self.cur_attribute = -1;
556 self.cur_attr_is_ns = false;
557 }
558
559 unsafe fn cache_name_and_value(&mut self, node: *mut _xmlNode, is_end: bool) {
565 self.clear_cached_name();
566 self.clear_cached_value();
567
568 if node.is_null() {
569 return;
570 }
571
572 let etype = unsafe { (*node).type_ };
574
575 let name: *mut xmlChar = if is_end {
577 unsafe { (*node).name as *mut xmlChar }
580 } else {
581 if etype == XML_ELEMENT_NODE as c_int
582 || etype == XML_PI_NODE as c_int
583 || etype == XML_ENTITY_REF_NODE as c_int
584 || etype == XML_ENTITY_NODE as c_int
585 || etype == XML_DOCUMENT_TYPE_NODE as c_int
586 || etype == XML_NOTATION_NODE as c_int
587 {
588 unsafe { (*node).name as *mut xmlChar }
590 } else if etype == XML_ATTRIBUTE_NODE as c_int {
591 ptr::null_mut()
593 } else {
594 ptr::null_mut()
595 }
596 };
597
598 if !name.is_null() {
599 let qualified: *mut xmlChar = if etype == XML_ELEMENT_NODE as c_int && !node.is_null() {
603 let ns = unsafe { (*node).ns };
604 if !ns.is_null() && !unsafe { (*ns).prefix }.is_null() {
605 let plen =
606 libc::strlen(unsafe { (*ns).prefix } as *const libc::c_char) as usize;
607 let nlen = libc::strlen(name as *const libc::c_char) as usize;
608 let p = crate::abi::allocator::xmlMallocImpl(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 { xmlFreeImpl(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 { xmlFreeImpl(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::xmlMallocImpl(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::xmlMallocImpl(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 { xmlFreeImpl(self.encoding as *mut c_void) };
1622 self.encoding = ptr::null_mut();
1623 }
1624 if !self.URL.is_null() {
1625 unsafe { xmlFreeImpl(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_named(buffer, size, URL) };
1857
1858 unsafe { setup_parser_input(ctxt, input) };
1860 unsafe {
1861 (*ctxt).options = options;
1862 }
1863
1864 let url_bytes = if URL.is_null() {
1865 None
1866 } else {
1867 unsafe {
1869 let cstr = std::ffi::CStr::from_ptr(URL);
1870 Some(cstr.to_bytes().to_vec())
1871 }
1872 };
1873
1874 let enc_bytes = if encoding.is_null() {
1875 None
1876 } else {
1877 unsafe {
1879 let cstr = std::ffi::CStr::from_ptr(encoding);
1880 Some(cstr.to_bytes().to_vec())
1881 }
1882 };
1883
1884 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1885 reader.options = options;
1886 Box::into_raw(Box::new(reader))
1887}
1888
1889#[no_mangle]
1903pub unsafe extern "C" fn xmlReaderForFd(
1904 fd: c_int,
1905 URL: *const c_char,
1906 encoding: *const c_char,
1907 options: c_int,
1908) -> *mut XmlTextReader {
1909 let ctxt = unsafe { create_parser_ctxt() };
1911 if ctxt.is_null() {
1912 return ptr::null_mut();
1913 }
1914
1915 let mut buf = Vec::new();
1917 let mut tmp = [0u8; 4096];
1918 loop {
1919 let n = unsafe { libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len()) };
1921 if n <= 0 {
1922 break;
1923 }
1924 buf.extend_from_slice(&tmp[..n as usize]);
1925 }
1926
1927 let input = unsafe { input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int) };
1929
1930 unsafe { setup_parser_input(ctxt, input) };
1932 unsafe {
1933 (*ctxt).options = options;
1934 }
1935
1936 let url_bytes = if URL.is_null() {
1937 None
1938 } else {
1939 unsafe {
1941 let cstr = std::ffi::CStr::from_ptr(URL);
1942 Some(cstr.to_bytes().to_vec())
1943 }
1944 };
1945
1946 let enc_bytes = if encoding.is_null() {
1947 None
1948 } else {
1949 unsafe {
1951 let cstr = std::ffi::CStr::from_ptr(encoding);
1952 Some(cstr.to_bytes().to_vec())
1953 }
1954 };
1955
1956 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1957 reader.options = options;
1958 Box::into_raw(Box::new(reader))
1959}
1960
1961#[no_mangle]
1977pub unsafe extern "C" fn xmlReaderForIO(
1978 ioread: Option<xmlInputReadCallback>,
1979 ioclose: Option<xmlInputCloseCallback>,
1980 ioctx: *mut c_void,
1981 URL: *const c_char,
1982 encoding: *const c_char,
1983 options: c_int,
1984) -> *mut XmlTextReader {
1985 let ctxt = unsafe { create_parser_ctxt() };
1987 if ctxt.is_null() {
1988 return ptr::null_mut();
1989 }
1990
1991 let input = unsafe { input_from_io(ioread, ioclose, ioctx) };
1993
1994 unsafe { setup_parser_input(ctxt, input) };
1996 unsafe {
1997 (*ctxt).options = options;
1998 }
1999
2000 let url_bytes = if URL.is_null() {
2001 None
2002 } else {
2003 unsafe {
2005 let cstr = std::ffi::CStr::from_ptr(URL);
2006 Some(cstr.to_bytes().to_vec())
2007 }
2008 };
2009
2010 let enc_bytes = if encoding.is_null() {
2011 None
2012 } else {
2013 unsafe {
2015 let cstr = std::ffi::CStr::from_ptr(encoding);
2016 Some(cstr.to_bytes().to_vec())
2017 }
2018 };
2019
2020 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
2021 reader.options = options;
2022 Box::into_raw(Box::new(reader))
2023}
2024
2025#[no_mangle]
2044pub unsafe extern "C" fn xmlTextReaderRead(reader: *mut XmlTextReader) -> c_int {
2045 if reader.is_null() {
2046 return -1;
2047 }
2048 unsafe { (*reader).Read() }
2050}
2051
2052#[no_mangle]
2066pub unsafe extern "C" fn xmlTextReaderNext(reader: *mut XmlTextReader) -> c_int {
2067 if reader.is_null() {
2068 return -1;
2069 }
2070 unsafe { (*reader).Next() }
2072}
2073
2074#[no_mangle]
2086pub unsafe extern "C" fn xmlTextReaderNextSibling(reader: *mut XmlTextReader) -> c_int {
2087 if reader.is_null() {
2088 return -1;
2089 }
2090 unsafe { (*reader).Next() }
2092}
2093
2094#[no_mangle]
2108pub unsafe extern "C" fn xmlTextReaderPrev(reader: *mut XmlTextReader) -> c_int {
2109 if reader.is_null() {
2110 return -1;
2111 }
2112 unsafe { (*reader).Prev() }
2114}
2115
2116#[no_mangle]
2130pub unsafe extern "C" fn xmlTextReaderMoveToElement(reader: *mut XmlTextReader) -> c_int {
2131 if reader.is_null() {
2132 return -1;
2133 }
2134 unsafe { (*reader).MoveToElement() }
2136}
2137
2138#[no_mangle]
2152pub unsafe extern "C" fn xmlTextReaderMoveToAttribute(
2153 reader: *mut XmlTextReader,
2154 name: *const xmlChar,
2155) -> c_int {
2156 if reader.is_null() || name.is_null() {
2157 return -1;
2158 }
2159 unsafe { (*reader).MoveToAttribute(name) }
2161}
2162
2163#[no_mangle]
2177pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNo(
2178 reader: *mut XmlTextReader,
2179 index: c_int,
2180) -> c_int {
2181 if reader.is_null() {
2182 return -1;
2183 }
2184 unsafe { (*reader).MoveToAttributeNo(index) }
2186}
2187
2188#[no_mangle]
2202pub unsafe extern "C" fn xmlTextReaderMoveToFirstAttribute(reader: *mut XmlTextReader) -> c_int {
2203 if reader.is_null() {
2204 return -1;
2205 }
2206 unsafe { (*reader).MoveToFirstAttribute() }
2208}
2209
2210#[no_mangle]
2224pub unsafe extern "C" fn xmlTextReaderMoveToNextAttribute(reader: *mut XmlTextReader) -> c_int {
2225 if reader.is_null() {
2226 return -1;
2227 }
2228 unsafe { (*reader).MoveToNextAttribute() }
2230}
2231
2232#[no_mangle]
2250pub unsafe extern "C" fn xmlTextReaderAttributeCount(reader: *mut XmlTextReader) -> c_int {
2251 if reader.is_null() {
2252 return -1;
2253 }
2254 unsafe { (*reader).AttributeCount() }
2256}
2257
2258#[no_mangle]
2272pub unsafe extern "C" fn xmlTextReaderDepth(reader: *mut XmlTextReader) -> c_int {
2273 if reader.is_null() {
2274 return -1;
2275 }
2276 unsafe { (*reader).Depth() }
2278}
2279
2280#[no_mangle]
2294pub unsafe extern "C" fn xmlTextReaderNodeType(reader: *mut XmlTextReader) -> c_int {
2295 if reader.is_null() {
2296 return -1;
2297 }
2298 unsafe { (*reader).NodeType() as c_int }
2300}
2301
2302#[no_mangle]
2317pub unsafe extern "C" fn xmlTextReaderName(reader: *mut XmlTextReader) -> *mut xmlChar {
2318 if reader.is_null() {
2319 return ptr::null_mut();
2320 }
2321 unsafe { (*reader).Name() }
2323}
2324
2325#[no_mangle]
2340pub unsafe extern "C" fn xmlTextReaderValue(reader: *mut XmlTextReader) -> *mut xmlChar {
2341 if reader.is_null() {
2342 return ptr::null_mut();
2343 }
2344 unsafe { (*reader).Value() }
2346}
2347
2348#[no_mangle]
2363pub unsafe extern "C" fn xmlTextReaderConstName(reader: *mut XmlTextReader) -> *const xmlChar {
2364 if reader.is_null() {
2365 return ptr::null();
2366 }
2367 unsafe { (*reader).ConstName() }
2369}
2370
2371#[no_mangle]
2386pub unsafe extern "C" fn xmlTextReaderConstValue(reader: *mut XmlTextReader) -> *const xmlChar {
2387 if reader.is_null() {
2388 return ptr::null();
2389 }
2390 unsafe { (*reader).ConstValue() }
2392}
2393
2394#[no_mangle]
2409pub unsafe extern "C" fn xmlTextReaderBaseUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2410 if reader.is_null() {
2411 return ptr::null_mut();
2412 }
2413 unsafe { (*reader).BaseUri() }
2415}
2416
2417#[no_mangle]
2431pub unsafe extern "C" fn xmlTextReaderLocalName(reader: *mut XmlTextReader) -> *mut xmlChar {
2432 if reader.is_null() {
2433 return ptr::null_mut();
2434 }
2435 unsafe { (*reader).LocalName() }
2437}
2438
2439#[no_mangle]
2453pub unsafe extern "C" fn xmlTextReaderNamespaceUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2454 if reader.is_null() {
2455 return ptr::null_mut();
2456 }
2457 unsafe { (*reader).NamespaceUri() }
2459}
2460
2461#[no_mangle]
2475pub unsafe extern "C" fn xmlTextReaderPrefix(reader: *mut XmlTextReader) -> *mut xmlChar {
2476 if reader.is_null() {
2477 return ptr::null_mut();
2478 }
2479 unsafe { (*reader).Prefix() }
2481}
2482
2483#[no_mangle]
2497pub unsafe extern "C" fn xmlTextReaderHasValue(reader: *mut XmlTextReader) -> c_int {
2498 if reader.is_null() {
2499 return 0;
2500 }
2501 unsafe { (*reader).HasValue() }
2503}
2504
2505#[no_mangle]
2519pub unsafe extern "C" fn xmlTextReaderHasAttributes(reader: *mut XmlTextReader) -> c_int {
2520 if reader.is_null() {
2521 return 0;
2522 }
2523 unsafe { (*reader).HasAttributes() }
2525}
2526
2527#[no_mangle]
2541pub unsafe extern "C" fn xmlTextReaderIsEmptyElement(reader: *mut XmlTextReader) -> c_int {
2542 if reader.is_null() {
2543 return 0;
2544 }
2545 unsafe { (*reader).IsEmptyElement() }
2547}
2548
2549#[no_mangle]
2563pub unsafe extern "C" fn xmlTextReaderReadState(reader: *mut XmlTextReader) -> c_int {
2564 if reader.is_null() {
2565 return ReadState::ERROR as c_int;
2566 }
2567 unsafe { (*reader).ReadState() as c_int }
2569}
2570
2571#[no_mangle]
2589pub unsafe extern "C" fn xmlTextReaderGetAttribute(
2590 reader: *mut XmlTextReader,
2591 name: *const xmlChar,
2592) -> *mut xmlChar {
2593 if reader.is_null() || name.is_null() {
2594 return ptr::null_mut();
2595 }
2596 unsafe { (*reader).GetAttribute(name) }
2598}
2599
2600#[no_mangle]
2614pub unsafe extern "C" fn xmlTextReaderGetAttributeNo(
2615 reader: *mut XmlTextReader,
2616 index: c_int,
2617) -> *mut xmlChar {
2618 if reader.is_null() {
2619 return ptr::null_mut();
2620 }
2621 unsafe { (*reader).GetAttributeNo(index) }
2623}
2624
2625#[no_mangle]
2641pub unsafe extern "C" fn xmlTextReaderGetAttributeNs(
2642 reader: *mut XmlTextReader,
2643 localName: *const xmlChar,
2644 namespaceURI: *const xmlChar,
2645) -> *mut xmlChar {
2646 if reader.is_null() || localName.is_null() {
2647 return ptr::null_mut();
2648 }
2649 unsafe { (*reader).GetAttributeNs(localName, namespaceURI) }
2651}
2652
2653#[no_mangle]
2667pub unsafe extern "C" fn xmlTextReaderLookupNamespace(
2668 reader: *mut XmlTextReader,
2669 prefix: *const xmlChar,
2670) -> *mut xmlChar {
2671 if reader.is_null() {
2672 return ptr::null_mut();
2673 }
2674 unsafe { (*reader).LookupNamespace(prefix) }
2676}
2677
2678#[no_mangle]
2696pub unsafe extern "C" fn xmlTextReaderGetParserProp(
2697 reader: *mut XmlTextReader,
2698 prop: c_int,
2699) -> c_int {
2700 if reader.is_null() {
2701 return -1;
2702 }
2703 unsafe { (*reader).GetParserProp(prop) }
2705}
2706
2707#[no_mangle]
2721pub unsafe extern "C" fn xmlTextReaderSetParserProp(
2722 reader: *mut XmlTextReader,
2723 prop: c_int,
2724 value: c_int,
2725) -> c_int {
2726 if reader.is_null() {
2727 return -1;
2728 }
2729 unsafe { (*reader).SetParserProp(prop, value) }
2731}
2732
2733#[no_mangle]
2750pub unsafe extern "C" fn xmlFreeTextReader(reader: *mut XmlTextReader) {
2751 if reader.is_null() {
2752 return;
2753 }
2754 unsafe {
2757 let _ = Box::from_raw(reader);
2758 }
2759}
2760
2761#[no_mangle]
2777pub unsafe extern "C" fn xmlTextReaderSetup(
2778 reader: *mut XmlTextReader,
2779 input: *mut _xmlParserInputBuffer,
2780 URL: *const c_char,
2781 encoding: *const c_char,
2782 options: c_int,
2783) -> c_int {
2784 if reader.is_null() {
2785 return -1;
2786 }
2787
2788 let r = unsafe { &mut *reader };
2790
2791 r.clear_cached_name();
2793 r.clear_cached_value();
2794
2795 if !r.doc.is_null() {
2797 unsafe { tree::free_doc(r.doc) };
2799 r.doc = ptr::null_mut();
2800 }
2801
2802 if !r.ctxt.is_null() {
2804 unsafe { free_parser_ctxt(r.ctxt) };
2806 r.ctxt = ptr::null_mut();
2807 }
2808
2809 r.events.clear();
2810 r.event_index = 0;
2811 r.state = ReadState::INITIALIZED;
2812 r.cur_node = ptr::null_mut();
2813 r.node_type = ReaderNodeType::NONE;
2814 r.depth = 0;
2815 r.attribute_count = -1;
2816 r.cur_attribute = -1;
2817 r.options = options;
2818 r.parsed = false;
2819 r.errors.clear();
2820
2821 if !r.URL.is_null() {
2823 unsafe { xmlFreeImpl(r.URL as *mut c_void) };
2825 r.URL = ptr::null_mut();
2826 }
2827 if !URL.is_null() {
2828 let url_str = unsafe { std::ffi::CStr::from_ptr(URL) };
2830 r.URL = unsafe { bytes_to_xmlstr(url_str.to_bytes()) };
2832 }
2833
2834 if !r.encoding.is_null() {
2836 unsafe { xmlFreeImpl(r.encoding as *mut c_void) };
2838 r.encoding = ptr::null_mut();
2839 }
2840 if !encoding.is_null() {
2841 let enc_str = unsafe { std::ffi::CStr::from_ptr(encoding) };
2843 r.encoding = unsafe { bytes_to_xmlstr(enc_str.to_bytes()) };
2845 }
2846
2847 if !input.is_null() {
2849 let ctxt = unsafe { create_parser_ctxt() };
2851 if ctxt.is_null() {
2852 return -1;
2853 }
2854
2855 let mut data = Vec::new();
2857 let mut tmp = [0u8; 4096];
2858
2859 let read_cb = unsafe { (*input).readcallback };
2861 let ioctx = unsafe { (*input).context };
2862
2863 if let Some(read) = read_cb {
2864 loop {
2865 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2867 if n <= 0 {
2868 break;
2869 }
2870 data.extend_from_slice(&tmp[..n as usize]);
2871 }
2872 }
2873
2874 let close_cb = unsafe { (*input).closecallback };
2876 if let Some(close) = close_cb {
2877 unsafe { close(ioctx) };
2879 }
2880
2881 let input_buf = InputBuffer::from_memory(&data, None);
2882
2883 unsafe { setup_parser_input(ctxt, input_buf) };
2885 unsafe {
2886 (*ctxt).options = options;
2887 }
2888
2889 r.ctxt = ctxt;
2890 }
2891
2892 0
2893}
2894
2895#[no_mangle]
2909pub unsafe extern "C" fn xmlTextReaderCurrentDoc(reader: *mut XmlTextReader) -> *mut _xmlDoc {
2910 if reader.is_null() {
2911 return ptr::null_mut();
2912 }
2913 unsafe { (*reader).CurrentDoc() }
2915}
2916
2917#[no_mangle]
2936pub unsafe extern "C" fn xmlTextReaderClose(reader: *mut XmlTextReader) -> c_int {
2937 if reader.is_null() {
2938 return -1;
2939 }
2940 unsafe {
2943 let r = &mut *reader;
2944 r.cur_node = ptr::null_mut();
2945 r.node_type = ReaderNodeType::NONE;
2946 r.clear_cached_name();
2947 r.clear_cached_value();
2948 r.state = ReadState::CLOSED;
2949 }
2950 0
2951}
2952
2953#[no_mangle]
2968pub unsafe extern "C" fn xmlTextReaderCurrentNode(reader: *mut XmlTextReader) -> *mut _xmlNode {
2969 if reader.is_null() {
2970 return ptr::null_mut();
2971 }
2972 unsafe { (*reader).cur_node }
2974}
2975
2976#[no_mangle]
2996pub unsafe extern "C" fn xmlTextReaderExpand(reader: *mut XmlTextReader) -> *mut _xmlNode {
2997 if reader.is_null() {
2998 return ptr::null_mut();
2999 }
3000 unsafe { (*reader).cur_node }
3002}
3003
3004#[no_mangle]
3022pub unsafe extern "C" fn xmlTextReaderGetParserLineNumber(reader: *mut XmlTextReader) -> c_int {
3023 if reader.is_null() {
3024 return 0;
3025 }
3026 unsafe {
3028 let node = (*reader).cur_node;
3029 if node.is_null() {
3030 0
3031 } else {
3032 (*node).line as c_int
3033 }
3034 }
3035}
3036
3037#[no_mangle]
3053pub unsafe extern "C" fn xmlTextReaderGetParserColumnNumber(reader: *mut XmlTextReader) -> c_int {
3054 if reader.is_null() {
3055 return -1;
3056 }
3057 -1
3058}
3059
3060#[no_mangle]
3078pub unsafe extern "C" fn xmlTextReaderIsValid(reader: *mut XmlTextReader) -> c_int {
3079 if reader.is_null() {
3080 return -1;
3081 }
3082 0
3083}
3084
3085#[no_mangle]
3102pub unsafe extern "C" fn xmlTextReaderNormalization(reader: *mut XmlTextReader) -> c_int {
3103 if reader.is_null() {
3104 return -1;
3105 }
3106 1
3107}
3108
3109#[no_mangle]
3128pub unsafe extern "C" fn xmlTextReaderReadAttributeValue(reader: *mut XmlTextReader) -> c_int {
3129 if reader.is_null() {
3130 return -1;
3131 }
3132 unsafe {
3134 let r = &*reader;
3135 if r.node_type == ReaderNodeType::ATTRIBUTE && !r.cur_node.is_null() {
3136 1
3137 } else {
3138 0
3139 }
3140 }
3141}
3142
3143#[no_mangle]
3161pub unsafe extern "C" fn xmlTextReaderReadString(reader: *mut XmlTextReader) -> *mut xmlChar {
3162 if reader.is_null() {
3163 return ptr::null_mut();
3164 }
3165 unsafe {
3167 let node = (*reader).cur_node;
3168 if node.is_null() {
3169 return ptr::null_mut();
3170 }
3171 tree::node_get_content(node)
3172 }
3173}
3174
3175#[no_mangle]
3192pub unsafe extern "C" fn xmlTextReaderReadInnerXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3193 if reader.is_null() {
3194 return ptr::null_mut();
3195 }
3196 unsafe {
3198 let node = (*reader).cur_node;
3199 if node.is_null() {
3200 return ptr::null_mut();
3201 }
3202 let buf = crate::xml::io::buf_create(-1);
3203 if buf.is_null() {
3204 return ptr::null_mut();
3205 }
3206 let mut child = (*node).children;
3207 while !child.is_null() {
3208 tree::serialize_node(child, buf, 0, 0);
3209 child = (*child).next;
3210 }
3211 let len = crate::xml::io::buf_length(buf) as usize;
3212 let content = crate::xml::io::buf_content(buf);
3213 if content.is_null() || len == 0 {
3214 crate::xml::io::buf_free(buf);
3215 return ptr::null_mut();
3216 }
3217 let out = xml_strdup(content);
3218 crate::xml::io::buf_free(buf);
3219 out
3220 }
3221}
3222
3223#[no_mangle]
3239pub unsafe extern "C" fn xmlTextReaderReadOuterXml(reader: *mut XmlTextReader) -> *mut xmlChar {
3240 if reader.is_null() {
3241 return ptr::null_mut();
3242 }
3243 unsafe {
3245 let node = (*reader).cur_node;
3246 if node.is_null() {
3247 return ptr::null_mut();
3248 }
3249 let buf = crate::xml::io::buf_create(-1);
3250 if buf.is_null() {
3251 return ptr::null_mut();
3252 }
3253 tree::serialize_node(node, buf, 0, 0);
3254 let len = crate::xml::io::buf_length(buf) as usize;
3255 let content = crate::xml::io::buf_content(buf);
3256 if content.is_null() || len == 0 {
3257 crate::xml::io::buf_free(buf);
3258 return ptr::null_mut();
3259 }
3260 let out = xml_strdup(content);
3261 crate::xml::io::buf_free(buf);
3262 out
3263 }
3264}
3265
3266#[no_mangle]
3281pub unsafe extern "C" fn xmlTextReaderStandalone(reader: *mut XmlTextReader) -> c_int {
3282 if reader.is_null() {
3283 return -1;
3284 }
3285 unsafe {
3287 let doc = (*reader).doc;
3288 if doc.is_null() {
3289 return -1;
3290 }
3291 (*doc).standalone
3292 }
3293}
3294
3295#[no_mangle]
3312pub unsafe extern "C" fn xmlTextReaderXmlLang(reader: *mut XmlTextReader) -> *mut xmlChar {
3313 if reader.is_null() {
3314 return ptr::null_mut();
3315 }
3316 unsafe {
3318 let mut node = (*reader).cur_node;
3319 while !node.is_null() {
3320 let mut prop = (*node).properties;
3322 while !prop.is_null() {
3323 if !(*prop).name.is_null() {
3324 let name = crate::xml::string::xmlstr_to_bytes((*prop).name);
3325 if name == b"lang" && !(*prop).ns.is_null() {
3326 let ns_href = crate::xml::string::xmlstr_to_bytes((*(*prop).ns).href);
3327 if ns_href == b"http://www.w3.org/XML/1998/namespace" {
3328 let v = (*prop).children;
3329 if !v.is_null() && !(*v).content.is_null() {
3330 return xml_strdup((*v).content);
3331 }
3332 }
3333 }
3334 }
3335 prop = (*prop).next;
3336 }
3337 node = (*node).parent;
3338 }
3339 ptr::null_mut()
3340 }
3341}
3342
3343#[cfg(test)]
3348mod tests {
3349 use super::*;
3350 use crate::abi::allocator::xmlFreeImpl;
3351 use core::ffi::c_void;
3352 use std::os::raw::c_char;
3353
3354 unsafe fn create_reader(xml: &str) -> *mut XmlTextReader {
3356 let bytes = xml.as_bytes();
3357 xmlReaderForMemory(
3358 bytes.as_ptr() as *const c_char,
3359 bytes.len() as c_int,
3360 ptr::null(),
3361 ptr::null(),
3362 0,
3363 )
3364 }
3365
3366 unsafe fn free_reader(reader: *mut XmlTextReader) {
3368 if !reader.is_null() {
3369 xmlFreeTextReader(reader);
3370 }
3371 }
3372
3373 unsafe fn collect_nodes(reader: *mut XmlTextReader) -> Vec<(ReaderNodeType, String, i32)> {
3375 let mut result = Vec::new();
3376 loop {
3377 let ret = xmlTextReaderRead(reader);
3378 if ret <= 0 {
3379 break;
3380 }
3381 let r = &*reader;
3383 let ntype = r.NodeType();
3384 let name = if r.name.is_null() {
3385 String::new()
3386 } else {
3387 xmlstr_to_string(r.name as *const xmlChar)
3388 };
3389 let depth = r.Depth();
3390 result.push((ntype, name, depth));
3391 }
3392 result
3393 }
3394
3395 #[test]
3398 fn test_create_reader_from_memory() {
3399 unsafe {
3400 let reader = create_reader("<root/>");
3401 assert!(!reader.is_null());
3402 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3403 free_reader(reader);
3404 }
3405 }
3406
3407 #[test]
3408 fn test_read_simple_document() {
3409 unsafe {
3410 let reader = create_reader("<root><child>text</child></root>");
3411 assert!(!reader.is_null());
3412
3413 let nodes = collect_nodes(reader);
3414 assert_eq!(nodes.len(), 5);
3422 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
3423 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
3424 assert_eq!(nodes[2], (ReaderNodeType::TEXT, "#text".to_string(), 2));
3426 assert_eq!(
3427 nodes[3],
3428 (ReaderNodeType::END_ELEMENT, "child".to_string(), 1)
3429 );
3430 assert_eq!(
3431 nodes[4],
3432 (ReaderNodeType::END_ELEMENT, "root".to_string(), 0)
3433 );
3434
3435 assert_eq!((*reader).ReadState(), ReadState::EOF);
3436 free_reader(reader);
3437 }
3438 }
3439
3440 #[test]
3441 fn test_read_state_transitions() {
3442 unsafe {
3443 let reader = create_reader("<root/>");
3444 assert!(!reader.is_null());
3445 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3446
3447 assert_eq!(xmlTextReaderRead(reader), 1);
3449 assert_eq!((*reader).ReadState(), ReadState::READING);
3450 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3451 assert_eq!((*reader).Depth(), 0);
3452
3453 assert_eq!(xmlTextReaderRead(reader), 0);
3456 assert_eq!((*reader).ReadState(), ReadState::EOF);
3457
3458 free_reader(reader);
3459 }
3460 }
3461
3462 #[test]
3463 fn test_null_reader_returns_error() {
3464 unsafe {
3465 assert_eq!(xmlTextReaderRead(ptr::null_mut()), -1);
3466 assert_eq!(xmlTextReaderDepth(ptr::null_mut()), -1);
3467 assert_eq!(xmlTextReaderNodeType(ptr::null_mut()), -1);
3468 assert!(xmlTextReaderName(ptr::null_mut()).is_null());
3469 assert!(xmlTextReaderValue(ptr::null_mut()).is_null());
3470 assert_eq!(xmlTextReaderHasValue(ptr::null_mut()), 0);
3471 assert_eq!(xmlTextReaderIsEmptyElement(ptr::null_mut()), 0);
3472 assert_eq!(
3473 xmlTextReaderReadState(ptr::null_mut()),
3474 ReadState::ERROR as c_int
3475 );
3476 }
3477 }
3478
3479 #[test]
3480 fn test_xmlFreeTextReader_null() {
3481 unsafe {
3482 xmlFreeTextReader(ptr::null_mut());
3484 }
3485 }
3486
3487 #[test]
3488 fn test_reader_name_and_value() {
3489 unsafe {
3490 let reader = create_reader("<root>hello</root>");
3491 assert!(!reader.is_null());
3492
3493 assert_eq!(xmlTextReaderRead(reader), 1);
3495 let name = xmlTextReaderName(reader);
3496 assert!(!name.is_null());
3497 assert_eq!(xmlstr_to_string(name), "root");
3498 xmlFreeImpl(name as *mut c_void);
3499
3500 assert_eq!(xmlTextReaderHasValue(reader), 0);
3501
3502 assert_eq!(xmlTextReaderRead(reader), 1);
3504 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3505 assert_eq!((*reader).HasValue(), 1);
3506
3507 let val = xmlTextReaderValue(reader);
3508 assert!(!val.is_null());
3509 assert_eq!(xmlstr_to_string(val), "hello");
3510 xmlFreeImpl(val as *mut c_void);
3511
3512 free_reader(reader);
3513 }
3514 }
3515
3516 #[test]
3517 fn test_empty_element() {
3518 unsafe {
3519 let reader = create_reader("<empty/>");
3520 assert!(!reader.is_null());
3521
3522 assert_eq!(xmlTextReaderRead(reader), 1);
3523 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3524 assert_eq!((*reader).IsEmptyElement(), 1);
3525 assert_eq!((*reader).HasAttributes(), 0);
3526 assert_eq!((*reader).AttributeCount(), 0);
3527
3528 assert_eq!(xmlTextReaderRead(reader), 0);
3531 assert_eq!((*reader).ReadState(), ReadState::EOF);
3532
3533 free_reader(reader);
3534 }
3535 }
3536
3537 #[test]
3538 fn test_element_with_attributes() {
3539 unsafe {
3540 let reader = create_reader(r#"<root a="1" b="2"/>"#);
3541 assert!(!reader.is_null());
3542
3543 assert_eq!(xmlTextReaderRead(reader), 1);
3544 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3545 assert_eq!((*reader).HasAttributes(), 1);
3546
3547 let attrs = xmlTextReaderAttributeCount(reader);
3550 assert_eq!(attrs, 2);
3551
3552 free_reader(reader);
3553 }
3554 }
3555
3556 #[test]
3557 fn test_attribute_navigation() {
3558 unsafe {
3559 let reader = create_reader(r#"<root a="1" b="2"></root>"#);
3560 assert!(!reader.is_null());
3561
3562 assert_eq!(xmlTextReaderRead(reader), 1);
3564 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3565
3566 assert_eq!(xmlTextReaderMoveToFirstAttribute(reader), 1);
3568 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3569
3570 let name = xmlTextReaderConstName(reader);
3571 assert!(!name.is_null());
3572 assert_eq!(xmlstr_to_bytes(name), b"a");
3573
3574 let val = xmlTextReaderConstValue(reader);
3575 assert!(!val.is_null());
3576 assert_eq!(xmlstr_to_bytes(val), b"1");
3577
3578 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 1);
3580 let name = xmlTextReaderConstName(reader);
3581 assert!(!name.is_null());
3582 assert_eq!(xmlstr_to_bytes(name), b"b");
3583 let val = xmlTextReaderConstValue(reader);
3584 assert!(!val.is_null());
3585 assert_eq!(xmlstr_to_bytes(val), b"2");
3586
3587 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 0);
3589
3590 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3592 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3593
3594 assert_eq!(
3596 xmlTextReaderMoveToAttribute(reader, b"a\0" as *const u8 as *const xmlChar),
3597 1
3598 );
3599 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3600
3601 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
3603 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 1), 1);
3604 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
3605
3606 free_reader(reader);
3607 }
3608 }
3609
3610 #[test]
3611 fn test_get_attribute() {
3612 unsafe {
3613 let reader = create_reader(r#"<root a="hello" b="world"/>"#);
3614 assert!(!reader.is_null());
3615
3616 assert_eq!(xmlTextReaderRead(reader), 1);
3617
3618 let val = xmlTextReaderGetAttribute(reader, b"a\0" as *const u8 as *const xmlChar);
3620 assert!(!val.is_null());
3621 assert_eq!(xmlstr_to_bytes(val), b"hello");
3622 xmlFreeImpl(val as *mut c_void);
3623
3624 let val = xmlTextReaderGetAttribute(reader, b"b\0" as *const u8 as *const xmlChar);
3625 assert!(!val.is_null());
3626 assert_eq!(xmlstr_to_bytes(val), b"world");
3627 xmlFreeImpl(val as *mut c_void);
3628
3629 let val = xmlTextReaderGetAttribute(reader, b"c\0" as *const u8 as *const xmlChar);
3631 assert!(val.is_null());
3632
3633 let val = xmlTextReaderGetAttributeNo(reader, 0);
3635 assert!(!val.is_null());
3636 assert_eq!(xmlstr_to_bytes(val), b"hello");
3637 xmlFreeImpl(val as *mut c_void);
3638
3639 let val = xmlTextReaderGetAttributeNo(reader, 1);
3640 assert!(!val.is_null());
3641 assert_eq!(xmlstr_to_bytes(val), b"world");
3642 xmlFreeImpl(val as *mut c_void);
3643
3644 let val = xmlTextReaderGetAttributeNo(reader, 2);
3645 assert!(val.is_null());
3646
3647 free_reader(reader);
3648 }
3649 }
3650
3651 #[test]
3652 fn test_depth_tracking() {
3653 unsafe {
3654 let reader = create_reader("<a><b><c/></b></a>");
3655 assert!(!reader.is_null());
3656
3657 let nodes = collect_nodes(reader);
3658 assert_eq!(nodes.len(), 5);
3663 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);
3670 }
3671 }
3672
3673 #[test]
3674 fn test_multiple_siblings() {
3675 unsafe {
3676 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3677 assert!(!reader.is_null());
3678
3679 let nodes = collect_nodes(reader);
3680 assert_eq!(nodes.len(), 11);
3685
3686 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "a".to_string(), 1));
3688 assert_eq!(nodes[4], (ReaderNodeType::ELEMENT, "b".to_string(), 1));
3689 assert_eq!(nodes[7], (ReaderNodeType::ELEMENT, "c".to_string(), 1));
3690
3691 free_reader(reader);
3692 }
3693 }
3694
3695 #[test]
3696 fn test_next_skip_to_sibling() {
3697 unsafe {
3698 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3699 assert!(!reader.is_null());
3700
3701 assert_eq!(xmlTextReaderRead(reader), 1);
3703 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3704
3705 assert_eq!(xmlTextReaderRead(reader), 1);
3707 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3708 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "a");
3709
3710 assert_eq!(xmlTextReaderRead(reader), 1);
3712 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3713
3714 assert_eq!(xmlTextReaderNext(reader), 1);
3716 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3717 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "b");
3718
3719 assert_eq!(xmlTextReaderNext(reader), 1);
3721 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3722 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "c");
3723
3724 assert_eq!(xmlTextReaderNext(reader), 0);
3726
3727 free_reader(reader);
3728 }
3729 }
3730
3731 #[test]
3732 fn test_comment_and_pi_nodes() {
3733 unsafe {
3734 let xml = b"<?pi target?><root><!-- comment -->text</root>\0";
3735 let reader = xmlReaderForMemory(
3736 xml.as_ptr() as *const c_char,
3737 (xml.len() - 1) as c_int,
3738 ptr::null(),
3739 ptr::null(),
3740 0,
3741 );
3742 assert!(!reader.is_null());
3743
3744 let nodes = collect_nodes(reader);
3745 assert!(!nodes.is_empty(), "no nodes collected: {:?}", nodes);
3748
3749 assert_eq!(
3751 nodes[0].0,
3752 ReaderNodeType::PROCESSING_INSTRUCTION,
3753 "expected PI at nodes[0], got {:?} name={}",
3754 nodes[0].0,
3755 nodes[0].1
3756 );
3757 assert_eq!(
3758 nodes[0].0,
3759 ReaderNodeType::PROCESSING_INSTRUCTION,
3760 "expected PI at nodes[0], got {:?} name={}",
3761 nodes[0].0,
3762 nodes[0].1
3763 );
3764
3765 let root_idx = nodes
3767 .iter()
3768 .position(|(t, n, _)| *t == ReaderNodeType::ELEMENT && n == "root");
3769 assert!(
3770 root_idx.is_some(),
3771 "no ELEMENT root found in nodes: {:?}",
3772 nodes
3773 .iter()
3774 .map(|(t, n, _)| format!("{:?}:{}", t, n))
3775 .collect::<Vec<_>>()
3776 );
3777
3778 let comment_idx = nodes
3780 .iter()
3781 .position(|(t, _, _)| *t == ReaderNodeType::COMMENT);
3782 assert!(comment_idx.is_some(), "no COMMENT found");
3783
3784 let text_idx = nodes
3786 .iter()
3787 .position(|(t, _, _)| *t == ReaderNodeType::TEXT);
3788 assert!(text_idx.is_some(), "no TEXT found");
3789
3790 free_reader(reader);
3791 }
3792 }
3793
3794 #[test]
3795 fn test_local_name() {
3796 unsafe {
3797 let reader = create_reader("<root/>");
3799 assert!(!reader.is_null());
3800
3801 assert_eq!(xmlTextReaderRead(reader), 1);
3802 let local = xmlTextReaderLocalName(reader);
3803 assert!(!local.is_null());
3804 assert_eq!(xmlstr_to_bytes(local), b"root");
3805 xmlFreeImpl(local as *mut c_void);
3806
3807 free_reader(reader);
3808 }
3809 }
3810
3811 #[test]
3812 fn test_base_uri() {
3813 unsafe {
3814 let reader = create_reader("<root/>");
3815 assert!(!reader.is_null());
3816
3817 assert_eq!(xmlTextReaderRead(reader), 1);
3818 let uri = xmlTextReaderBaseUri(reader);
3820 assert!(uri.is_null());
3821
3822 free_reader(reader);
3823 }
3824 }
3825
3826 #[test]
3827 fn test_lookup_namespace() {
3828 unsafe {
3829 let reader = create_reader(r#"<root xmlns:ns="http://example.com"><ns:child/></root>"#);
3830 assert!(!reader.is_null());
3831
3832 assert_eq!(xmlTextReaderRead(reader), 1);
3834 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3835
3836 assert_eq!(xmlTextReaderRead(reader), 1);
3838
3839 let uri = xmlTextReaderLookupNamespace(reader, b"ns\0" as *const u8 as *const xmlChar);
3841 assert!(!uri.is_null());
3842 assert_eq!(xmlstr_to_bytes(uri), b"http://example.com");
3843 xmlFreeImpl(uri as *mut c_void);
3844
3845 let uri = xmlTextReaderLookupNamespace(reader, ptr::null());
3847 assert!(uri.is_null());
3848
3849 let uri = xmlTextReaderLookupNamespace(
3851 reader,
3852 b"nonexistent\0" as *const u8 as *const xmlChar,
3853 );
3854 assert!(uri.is_null());
3855
3856 free_reader(reader);
3857 }
3858 }
3859
3860 #[test]
3861 fn test_parser_properties() {
3862 unsafe {
3863 let reader = create_reader("<root/>");
3864 assert!(!reader.is_null());
3865
3866 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);
3874 assert_eq!(xmlTextReaderGetParserProp(reader, 1), 1);
3875
3876 assert_eq!(xmlTextReaderSetParserProp(reader, 4, 1), 0);
3877 assert_eq!(xmlTextReaderGetParserProp(reader, 4), 1);
3878
3879 assert_eq!(xmlTextReaderGetParserProp(reader, 99), -1);
3881 assert_eq!(xmlTextReaderSetParserProp(reader, 99, 1), -1);
3882
3883 free_reader(reader);
3884 }
3885 }
3886
3887 #[test]
3888 fn test_current_doc() {
3889 unsafe {
3890 let reader = create_reader("<root/>");
3891 assert!(!reader.is_null());
3892
3893 assert!((*reader).CurrentDoc().is_null());
3895
3896 assert_eq!(xmlTextReaderRead(reader), 1);
3898 let doc = xmlTextReaderCurrentDoc(reader);
3899 assert!(!doc.is_null());
3900
3901 free_reader(reader);
3902 }
3903 }
3904
3905 #[test]
3906 fn test_free_reader_after_read() {
3907 unsafe {
3908 let reader = create_reader("<root><child/></root>");
3909 assert!(!reader.is_null());
3910
3911 while xmlTextReaderRead(reader) > 0 {}
3913 assert_eq!((*reader).ReadState(), ReadState::EOF);
3914
3915 free_reader(reader);
3917 }
3918 }
3919
3920 #[test]
3921 fn test_reader_for_memory_null_buffer() {
3922 unsafe {
3923 let reader = xmlReaderForMemory(ptr::null(), 10, ptr::null(), ptr::null(), 0);
3924 assert!(reader.is_null());
3925 }
3926 }
3927
3928 #[test]
3929 fn test_reader_for_memory_empty_size() {
3930 unsafe {
3931 let data = b"<root/>";
3932 let reader = xmlReaderForMemory(
3933 data.as_ptr() as *const c_char,
3934 0,
3935 ptr::null(),
3936 ptr::null(),
3937 0,
3938 );
3939 assert!(reader.is_null());
3940 }
3941 }
3942
3943 #[test]
3944 fn test_reader_for_file_not_found() {
3945 unsafe {
3946 let filename = b"/nonexistent/file.xml\0" as *const u8 as *const c_char;
3947 let reader = xmlReaderForFile(filename, ptr::null(), 0);
3948 assert!(reader.is_null());
3949 }
3950 }
3951
3952 #[test]
3953 fn test_const_name_and_value() {
3954 unsafe {
3955 let reader = create_reader("<root>text</root>");
3956 assert!(!reader.is_null());
3957
3958 assert_eq!(xmlTextReaderRead(reader), 1);
3960 let cname = xmlTextReaderConstName(reader);
3961 assert!(!cname.is_null());
3962 assert_eq!(xmlstr_to_bytes(cname), b"root");
3963
3964 assert_eq!(xmlTextReaderRead(reader), 1);
3966 let cval = xmlTextReaderConstValue(reader);
3967 assert!(!cval.is_null());
3968 assert_eq!(xmlstr_to_bytes(cval), b"text");
3969
3970 free_reader(reader);
3971 }
3972 }
3973
3974 #[test]
3975 fn test_complex_nested_document() {
3976 unsafe {
3977 let xml = r#"<?xml version="1.0"?>
3978<library>
3979 <book id="1">
3980 <title>XML Fundamentals</title>
3981 <author>John Doe</author>
3982 </book>
3983 <book id="2">
3984 <title>XSLT Recipes</title>
3985 <author>Jane Smith</author>
3986 </book>
3987</library>"#;
3988
3989 let reader = create_reader(xml);
3990 assert!(!reader.is_null());
3991
3992 let mut element_count = 0;
3993 let mut end_element_count = 0;
3994 let mut text_count = 0;
3995 let mut pi_count = 0;
3996
3997 loop {
3998 let ret = xmlTextReaderRead(reader);
3999 if ret <= 0 {
4000 break;
4001 }
4002 match (*reader).NodeType() {
4003 ReaderNodeType::ELEMENT => element_count += 1,
4004 ReaderNodeType::END_ELEMENT => end_element_count += 1,
4005 ReaderNodeType::TEXT => text_count += 1,
4006 ReaderNodeType::PROCESSING_INSTRUCTION => pi_count += 1,
4007 _ => {}
4008 }
4009 }
4010
4011 assert_eq!(element_count, 7);
4013 assert_eq!(end_element_count, 7);
4015 assert_eq!(text_count, 4);
4017 assert_eq!(pi_count, 0);
4022
4023 free_reader(reader);
4024 }
4025 }
4026
4027 #[test]
4028 fn test_setup_reinitialize() {
4029 unsafe {
4030 let reader = create_reader("<root/>");
4031 assert!(!reader.is_null());
4032
4033 assert_eq!(xmlTextReaderRead(reader), 1);
4035 assert_eq!((*reader).ReadState(), ReadState::READING);
4036
4037 assert_eq!(
4041 xmlTextReaderSetup(reader, ptr::null_mut(), ptr::null(), ptr::null(), 0),
4042 0
4043 );
4044 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
4045
4046 free_reader(reader);
4047 }
4048 }
4049
4050 #[test]
4051 fn test_has_attributes_on_non_element() {
4052 unsafe {
4053 let reader = create_reader("<root>text</root>");
4054 assert!(!reader.is_null());
4055
4056 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0); assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0);
4061
4062 free_reader(reader);
4063 }
4064 }
4065
4066 #[test]
4067 fn test_prev_sibling() {
4068 unsafe {
4069 let reader = create_reader("<root><a/><b/><c/></root>");
4070 assert!(!reader.is_null());
4071
4072 while xmlTextReaderRead(reader) > 0 {
4074 }
4076
4077 assert_eq!(xmlTextReaderPrev(reader), -1);
4079
4080 free_reader(reader);
4081 }
4082 }
4083
4084 #[test]
4085 fn test_move_to_attribute_no_not_on_element() {
4086 unsafe {
4087 let reader = create_reader("<root>text</root>");
4088 assert!(!reader.is_null());
4089
4090 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4092
4093 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 0), 0);
4095
4096 free_reader(reader);
4097 }
4098 }
4099
4100 #[test]
4101 fn test_get_attribute_ns() {
4102 unsafe {
4103 let reader = create_reader(r#"<root a="1" b="2"/>"#);
4104 assert!(!reader.is_null());
4105
4106 assert_eq!(xmlTextReaderRead(reader), 1);
4107
4108 let val = xmlTextReaderGetAttributeNs(
4110 reader,
4111 b"a\0" as *const u8 as *const xmlChar,
4112 ptr::null(),
4113 );
4114 assert!(!val.is_null());
4115 assert_eq!(xmlstr_to_bytes(val), b"1");
4116 xmlFreeImpl(val as *mut c_void);
4117
4118 free_reader(reader);
4119 }
4120 }
4121
4122 #[test]
4123 fn test_mixed_content() {
4124 unsafe {
4125 let reader = create_reader("<root>before<child/>after</root>");
4126 assert!(!reader.is_null());
4127
4128 let nodes = collect_nodes(reader);
4129 assert_eq!(nodes.len(), 5);
4134 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
4135 assert_eq!(nodes[1].0, ReaderNodeType::TEXT);
4136 assert_eq!(nodes[2], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
4137 assert_eq!(nodes[3].0, ReaderNodeType::TEXT);
4138
4139 free_reader(reader);
4140 }
4141 }
4142
4143 #[test]
4144 fn test_error_handling_invalid_xml() {
4145 unsafe {
4146 let data = b"<root><\0" as *const u8 as *const c_char;
4148 let reader = xmlReaderForMemory(data, 7, ptr::null(), ptr::null(), 0);
4149 assert!(!reader.is_null());
4150
4151 let ret = xmlTextReaderRead(reader);
4153 assert!(ret == -1 || ret == 0);
4154
4155 free_reader(reader);
4156 }
4157 }
4158
4159 #[test]
4160 fn test_reader_with_options() {
4161 unsafe {
4162 let data = b"<root/>\0" as *const u8 as *const c_char;
4163 let reader = xmlReaderForMemory(
4164 data,
4165 7,
4166 ptr::null(),
4167 ptr::null(),
4168 XML_PARSE_NOENT | XML_PARSE_DTDLOAD,
4169 );
4170 assert!(!reader.is_null());
4171
4172 assert_eq!((*reader).options & XML_PARSE_NOENT, XML_PARSE_NOENT);
4174 assert_eq!((*reader).options & XML_PARSE_DTDLOAD, XML_PARSE_DTDLOAD);
4175
4176 assert_eq!(xmlTextReaderRead(reader), 1);
4177 free_reader(reader);
4178 }
4179 }
4180
4181 #[test]
4182 fn test_reader_for_fd() {
4183 unsafe {
4184 let tmp_path = "/tmp/libxml_rs_test_reader_fd.xml";
4186 let tmp_cstr = std::ffi::CString::new(tmp_path).unwrap();
4187 let content = b"<root><data/></root>";
4188 let fd = libc::open(
4189 tmp_cstr.as_ptr(),
4190 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
4191 0o644,
4192 );
4193 assert!(fd >= 0);
4194 libc::write(fd, content.as_ptr() as *const c_void, content.len());
4195 libc::close(fd);
4196
4197 let fd = libc::open(tmp_cstr.as_ptr(), libc::O_RDONLY, 0);
4199 assert!(fd >= 0);
4200
4201 let reader = xmlReaderForFd(fd, ptr::null(), ptr::null(), 0);
4202 assert!(!reader.is_null());
4203
4204 let nodes = collect_nodes(reader);
4205 assert_eq!(nodes.len(), 3);
4208
4209 free_reader(reader);
4210 libc::close(fd);
4211 std::fs::remove_file(tmp_path).ok();
4212 }
4213 }
4214
4215 #[test]
4216 fn test_reader_for_io() {
4217 unsafe {
4218 extern "C" fn io_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
4219 if context.is_null() || buffer.is_null() || len <= 0 {
4220 return -1;
4221 }
4222 let ctx = unsafe { &mut *(context as *mut IoCtx) };
4224 if ctx.pos >= ctx.data.len() {
4225 return 0;
4226 }
4227 let remaining = ctx.data.len() - ctx.pos;
4228 let to_copy = if (remaining as c_int) < len {
4229 remaining
4230 } else {
4231 len as usize
4232 };
4233 unsafe {
4235 std::ptr::copy_nonoverlapping(
4236 ctx.data.as_ptr().add(ctx.pos),
4237 buffer as *mut u8,
4238 to_copy,
4239 );
4240 }
4241 ctx.pos += to_copy;
4242 to_copy as c_int
4243 }
4244
4245 extern "C" fn io_close(_context: *mut c_void) -> c_int {
4246 0
4247 }
4248
4249 struct IoCtx {
4250 data: &'static [u8],
4251 pos: usize,
4252 }
4253 let mut ctx = IoCtx {
4254 data: b"<root/>",
4255 pos: 0,
4256 };
4257
4258 let reader = xmlReaderForIO(
4259 Some(io_read),
4260 Some(io_close),
4261 &mut ctx as *mut IoCtx as *mut c_void,
4262 ptr::null(),
4263 ptr::null(),
4264 0,
4265 );
4266 assert!(!reader.is_null());
4267
4268 assert_eq!(xmlTextReaderRead(reader), 1);
4270 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
4271 let cname = xmlTextReaderConstName(reader);
4272 assert!(!cname.is_null());
4273 assert_eq!(xmlstr_to_bytes(cname), b"root");
4274
4275 assert_eq!(xmlTextReaderRead(reader), 0);
4278
4279 free_reader(reader);
4280 }
4281 }
4282}
4283
4284pub const XML_PARSER_SEVERITY_VALIDITY_WARNING: c_int = 1;
4290pub const XML_PARSER_SEVERITY_VALIDITY_ERROR: c_int = 2;
4291pub const XML_PARSER_SEVERITY_WARNING: c_int = 3;
4292pub const XML_PARSER_SEVERITY_ERROR: c_int = 4;
4293
4294#[repr(C)]
4297pub struct XmlTextReaderLocator {
4298 pub reader: *mut XmlTextReader,
4299}
4300
4301pub type xmlTextReaderErrorFunc = unsafe extern "C" fn(
4303 arg: *mut c_void,
4304 msg: *const c_char,
4305 severity: c_int,
4306 locator: *mut XmlTextReaderLocator,
4307);
4308
4309#[no_mangle]
4316pub unsafe extern "C" fn xmlReaderForDoc(
4317 cur: *const xmlChar,
4318 URL: *const c_char,
4319 encoding: *const c_char,
4320 options: c_int,
4321) -> *mut XmlTextReader {
4322 if cur.is_null() {
4323 return ptr::null_mut();
4324 }
4325 let len = unsafe { libc::strlen(cur as *const libc::c_char) } as c_int;
4326 unsafe { xmlReaderForMemory(cur as *const c_char, len, URL, encoding, options) }
4327}
4328
4329#[no_mangle]
4331pub unsafe extern "C" fn xmlNewTextReaderFilename(
4332 URI: *const c_char,
4333 encoding: *const c_char,
4334 options: c_int,
4335) -> *mut XmlTextReader {
4336 unsafe { xmlReaderForFile(URI, encoding, options) }
4337}
4338
4339unsafe fn reader_renew(reader: *mut XmlTextReader, new_reader: *mut XmlTextReader) {
4351 debug_assert!(!reader.is_null() && !new_reader.is_null() && reader != new_reader);
4352 unsafe {
4353 core::ptr::drop_in_place(reader);
4357 core::ptr::copy_nonoverlapping(new_reader, reader, 1);
4358 let layout = std::alloc::Layout::new::<XmlTextReader>();
4359 std::alloc::dealloc(new_reader as *mut u8, layout);
4360 }
4361}
4362
4363#[no_mangle]
4365pub unsafe extern "C" fn xmlReaderNewDoc(
4366 reader: *mut XmlTextReader,
4367 cur: *const xmlChar,
4368 URL: *const c_char,
4369 encoding: *const c_char,
4370 options: c_int,
4371) -> c_int {
4372 if reader.is_null() || cur.is_null() {
4375 return -1;
4376 }
4377 let r = unsafe { xmlReaderForDoc(cur, URL, encoding, options) };
4378 if r.is_null() {
4379 return -1;
4380 }
4381 unsafe { reader_renew(reader, r) };
4382 0
4383}
4384
4385#[no_mangle]
4387pub unsafe extern "C" fn xmlReaderNewFile(
4388 reader: *mut XmlTextReader,
4389 filename: *const c_char,
4390 encoding: *const c_char,
4391 options: c_int,
4392) -> c_int {
4393 if reader.is_null() {
4394 return -1;
4395 }
4396 let r = unsafe { xmlReaderForFile(filename, encoding, options) };
4397 if r.is_null() {
4398 return -1;
4399 }
4400 unsafe { reader_renew(reader, r) };
4401 0
4402}
4403
4404#[no_mangle]
4406pub unsafe extern "C" fn xmlReaderNewMemory(
4407 reader: *mut XmlTextReader,
4408 buffer: *const c_char,
4409 size: c_int,
4410 URL: *const c_char,
4411 encoding: *const c_char,
4412 options: c_int,
4413) -> c_int {
4414 if reader.is_null() || buffer.is_null() {
4415 return -1;
4416 }
4417 let r = unsafe { xmlReaderForMemory(buffer, size, URL, encoding, options) };
4418 if r.is_null() {
4419 return -1;
4420 }
4421 unsafe { reader_renew(reader, r) };
4422 0
4423}
4424
4425#[no_mangle]
4427pub unsafe extern "C" fn xmlReaderNewFd(
4428 reader: *mut XmlTextReader,
4429 fd: c_int,
4430 URL: *const c_char,
4431 encoding: *const c_char,
4432 options: c_int,
4433) -> c_int {
4434 if reader.is_null() {
4435 return -1;
4436 }
4437 let r = unsafe { xmlReaderForFd(fd, URL, encoding, options) };
4438 if r.is_null() {
4439 return -1;
4440 }
4441 unsafe { reader_renew(reader, r) };
4442 0
4443}
4444
4445#[no_mangle]
4447pub unsafe extern "C" fn xmlReaderNewIO(
4448 reader: *mut XmlTextReader,
4449 ioread: Option<xmlInputReadCallback>,
4450 ioclose: Option<xmlInputCloseCallback>,
4451 ioctx: *mut c_void,
4452 URL: *const c_char,
4453 encoding: *const c_char,
4454 options: c_int,
4455) -> c_int {
4456 if reader.is_null() || ioread.is_none() {
4458 return -1;
4459 }
4460 let r = unsafe { xmlReaderForIO(ioread, ioclose, ioctx, URL, encoding, options) };
4461 if r.is_null() {
4462 return -1;
4463 }
4464 unsafe { reader_renew(reader, r) };
4465 0
4466}
4467
4468#[no_mangle]
4475pub unsafe extern "C" fn xmlReaderWalker(doc: *mut _xmlDoc) -> *mut XmlTextReader {
4476 if doc.is_null() {
4477 return ptr::null_mut();
4478 }
4479 let mut reader = XmlTextReader::new(ptr::null_mut(), None, None);
4480 reader.doc = doc;
4481 reader.parsed = true;
4482 reader.owns_doc = false; reader.state = ReadState::READING;
4484 reader.build_events();
4485 Box::into_raw(Box::new(reader))
4486}
4487
4488#[no_mangle]
4490pub unsafe extern "C" fn xmlReaderNewWalker(
4491 reader: *mut XmlTextReader,
4492 doc: *mut _xmlDoc,
4493) -> c_int {
4494 if reader.is_null() || doc.is_null() {
4496 return -1;
4497 }
4498 let r = unsafe { xmlReaderWalker(doc) };
4499 if r.is_null() {
4500 return -1;
4501 }
4502 unsafe { reader_renew(reader, r) };
4503 0
4504}
4505
4506#[no_mangle]
4511pub unsafe extern "C" fn xmlTextReaderByteConsumed(reader: *mut XmlTextReader) -> c_long {
4512 if reader.is_null() {
4513 return -1;
4514 }
4515 0
4516}
4517
4518#[no_mangle]
4521pub unsafe extern "C" fn xmlTextReaderConstBaseUri(reader: *mut XmlTextReader) -> *const xmlChar {
4522 if reader.is_null() {
4523 return ptr::null();
4524 }
4525 unsafe { (*reader).URL }
4526}
4527
4528#[no_mangle]
4530pub unsafe extern "C" fn xmlTextReaderConstEncoding(reader: *mut XmlTextReader) -> *const xmlChar {
4531 if reader.is_null() {
4532 return ptr::null();
4533 }
4534 let r = unsafe { &*reader };
4535 if !r.encoding.is_null() {
4536 return r.encoding;
4537 }
4538 if !r.doc.is_null() {
4539 return unsafe { (*r.doc).encoding };
4540 }
4541 ptr::null()
4542}
4543
4544#[no_mangle]
4550pub unsafe extern "C" fn xmlTextReaderConstLocalName(reader: *mut XmlTextReader) -> *const xmlChar {
4551 if reader.is_null() {
4552 return ptr::null();
4553 }
4554 let r = unsafe { &*reader };
4555 if r.cur_node.is_null() {
4556 return ptr::null();
4557 }
4558 if r.cur_attribute >= 0 {
4561 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4562 return match target {
4563 AttrTarget::Ns(ns) => {
4564 if ns.is_null() {
4565 ptr::null()
4566 } else if unsafe { (*ns).prefix }.is_null() {
4567 b"xmlns\0".as_ptr() as *const xmlChar
4568 } else {
4569 unsafe { (*ns).prefix }
4570 }
4571 }
4572 AttrTarget::Prop(p) => {
4573 if p.is_null() || unsafe { (*p).name }.is_null() {
4574 ptr::null()
4575 } else {
4576 unsafe { (*p).name }
4577 }
4578 }
4579 AttrTarget::None => ptr::null(),
4580 };
4581 }
4582 let etype = unsafe { (*r.cur_node).type_ };
4584 if etype == XML_ELEMENT_NODE as c_int || etype == XML_ATTRIBUTE_NODE as c_int {
4585 unsafe { (*r.cur_node).name }
4586 } else {
4587 ptr::null()
4588 }
4589}
4590
4591#[no_mangle]
4596pub unsafe extern "C" fn xmlTextReaderConstNamespaceUri(
4597 reader: *mut XmlTextReader,
4598) -> *const xmlChar {
4599 if reader.is_null() {
4600 return ptr::null();
4601 }
4602 let r = unsafe { &*reader };
4603 if r.cur_node.is_null() {
4604 return ptr::null();
4605 }
4606 if r.cur_attribute >= 0 {
4608 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4609 return match target {
4610 AttrTarget::Ns(_ns) => {
4611 b"http://www.w3.org/2000/xmlns/\0".as_ptr() as *const xmlChar
4615 }
4616 AttrTarget::Prop(p) => {
4617 if p.is_null() || unsafe { (*p).ns }.is_null() {
4618 ptr::null()
4619 } else {
4620 unsafe { (*(*p).ns).href }
4621 }
4622 }
4623 AttrTarget::None => ptr::null(),
4624 };
4625 }
4626 let ns = unsafe { (*r.cur_node).ns };
4627 if ns.is_null() || unsafe { (*ns).href }.is_null() {
4628 ptr::null()
4629 } else {
4630 unsafe { (*ns).href }
4631 }
4632}
4633
4634#[no_mangle]
4640pub unsafe extern "C" fn xmlTextReaderConstPrefix(reader: *mut XmlTextReader) -> *const xmlChar {
4641 if reader.is_null() {
4642 return ptr::null();
4643 }
4644 let r = unsafe { &*reader };
4645 if r.cur_node.is_null() {
4646 return ptr::null();
4647 }
4648 if r.cur_attribute >= 0 {
4650 let target = unsafe { r.attr_at(r.cur_node, r.cur_attribute) };
4651 return match target {
4652 AttrTarget::Ns(ns) => {
4653 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4654 ptr::null()
4655 } else {
4656 b"xmlns\0".as_ptr() as *const xmlChar
4657 }
4658 }
4659 AttrTarget::Prop(p) => {
4660 if p.is_null() || unsafe { (*p).ns }.is_null() {
4661 ptr::null()
4662 } else {
4663 unsafe { (*(*p).ns).prefix }
4664 }
4665 }
4666 AttrTarget::None => ptr::null(),
4667 };
4668 }
4669 let ns = unsafe { (*r.cur_node).ns };
4670 if ns.is_null() || unsafe { (*ns).prefix }.is_null() {
4671 ptr::null()
4672 } else {
4673 unsafe { (*ns).prefix }
4674 }
4675}
4676
4677#[no_mangle]
4681pub unsafe extern "C" fn xmlTextReaderConstString(
4682 _reader: *mut XmlTextReader,
4683 str: *const xmlChar,
4684) -> *const xmlChar {
4685 str
4686}
4687
4688#[no_mangle]
4690pub unsafe extern "C" fn xmlTextReaderConstXmlLang(reader: *mut XmlTextReader) -> *const xmlChar {
4691 if reader.is_null() {
4692 return ptr::null();
4693 }
4694 let r = unsafe { &*reader };
4695 let mut node = r.cur_node;
4696 while !node.is_null() {
4697 let mut prop = unsafe { (*node).properties };
4698 while !prop.is_null() {
4699 let p = unsafe { &*prop };
4700 if !p.name.is_null()
4701 && unsafe { *p.name } == b'x'
4702 && unsafe { *p.name.add(1) } == b'm'
4703 && unsafe { *p.name.add(2) } == b'l'
4704 && unsafe { *p.name.add(3) } == b':'
4705 && unsafe { *p.name.add(4) } == b'l'
4706 && unsafe { *p.name.add(5) } == b'a'
4707 && unsafe { *p.name.add(6) } == b'n'
4708 && unsafe { *p.name.add(7) } == b'g'
4709 && unsafe { *p.name.add(8) } == 0
4710 {
4711 if !p.children.is_null() {
4712 let txt = p.children;
4713 if unsafe { (*txt).type_ }
4714 == crate::abi::types::xmlElementType::XML_TEXT_NODE as c_int
4715 {
4716 return unsafe { (*txt).content };
4717 }
4718 }
4719 return ptr::null();
4720 }
4721 prop = p.next;
4722 }
4723 node = unsafe { (*node).parent };
4724 }
4725 ptr::null()
4726}
4727
4728#[no_mangle]
4730pub unsafe extern "C" fn xmlTextReaderConstXmlVersion(
4731 reader: *mut XmlTextReader,
4732) -> *const xmlChar {
4733 if reader.is_null() {
4734 return ptr::null();
4735 }
4736 let r = unsafe { &*reader };
4737 if r.doc.is_null() {
4738 return ptr::null();
4739 }
4740 unsafe { (*r.doc).version }
4741}
4742
4743#[no_mangle]
4750pub unsafe extern "C" fn xmlTextReaderQuoteChar(reader: *mut XmlTextReader) -> c_int {
4751 if reader.is_null() {
4752 return -1;
4753 }
4754 b'"' as c_int
4755}
4756
4757#[no_mangle]
4762pub unsafe extern "C" fn xmlTextReaderIsDefault(reader: *mut XmlTextReader) -> c_int {
4763 if reader.is_null() {
4764 return -1;
4765 }
4766 0
4767}
4768
4769#[no_mangle]
4772pub unsafe extern "C" fn xmlTextReaderIsNamespaceDecl(reader: *mut XmlTextReader) -> c_int {
4773 if reader.is_null() {
4774 return -1;
4775 }
4776 let r = unsafe { &*reader };
4777 if r.cur_node.is_null() {
4778 return -1;
4779 }
4780 r.cur_attr_is_ns as c_int
4781}
4782
4783#[no_mangle]
4796pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNs(
4797 reader: *mut XmlTextReader,
4798 localName: *const xmlChar,
4799 namespaceURI: *const xmlChar,
4800) -> c_int {
4801 if reader.is_null() || localName.is_null() || namespaceURI.is_null() {
4802 return -1;
4803 }
4804 let r = unsafe { &mut *reader };
4805 let node = r.cur_node;
4806 if node.is_null() {
4807 return -1;
4808 }
4809 if unsafe { (*node).type_ } != XML_ELEMENT_NODE as c_int {
4810 return 0;
4811 }
4812
4813 const XMLNS_URI: &[u8] = b"http://www.w3.org/2000/xmlns/\0";
4814 if libc::strcmp(
4815 namespaceURI as *const libc::c_char,
4816 XMLNS_URI.as_ptr() as *const libc::c_char,
4817 ) == 0
4818 {
4819 let is_default = libc::strcmp(
4822 localName as *const libc::c_char,
4823 b"xmlns\0".as_ptr() as *const libc::c_char,
4824 ) == 0;
4825 let mut ns = unsafe { (*node).nsDef };
4826 let mut index = 0;
4827 while !ns.is_null() {
4828 let n = unsafe { &*ns };
4829 let prefix_match = if is_default {
4830 n.prefix.is_null()
4831 } else {
4832 !n.prefix.is_null()
4833 && libc::strcmp(
4834 n.prefix as *const libc::c_char,
4835 localName as *const libc::c_char,
4836 ) == 0
4837 };
4838 if prefix_match {
4839 r.cur_attribute = index;
4840 r.node_type = ReaderNodeType::ATTRIBUTE;
4841 r.cache_attribute_info(AttrTarget::Ns(ns));
4842 return 1;
4843 }
4844 index += 1;
4845 ns = unsafe { (*ns).next };
4846 }
4847 return 0;
4848 }
4849
4850 let mut prop = unsafe { (*node).properties };
4852 let mut index = 0;
4853 let mut ns_count = 0;
4854 let mut ns = unsafe { (*node).nsDef };
4855 while !ns.is_null() {
4856 ns_count += 1;
4857 ns = unsafe { (*ns).next };
4858 }
4859 while !prop.is_null() {
4860 let p = unsafe { &*prop };
4861 if !p.name.is_null()
4862 && !p.ns.is_null()
4863 && !(*p.ns).href.is_null()
4864 && libc::strcmp(
4865 p.name as *const libc::c_char,
4866 localName as *const libc::c_char,
4867 ) == 0
4868 && libc::strcmp(
4869 (*p.ns).href as *const libc::c_char,
4870 namespaceURI as *const libc::c_char,
4871 ) == 0
4872 {
4873 r.cur_attribute = ns_count + index;
4874 r.node_type = ReaderNodeType::ATTRIBUTE;
4875 r.cache_attribute_info(AttrTarget::Prop(prop));
4876 return 1;
4877 }
4878 index += 1;
4879 prop = unsafe { (*prop).next };
4880 }
4881 0
4882}
4883
4884#[no_mangle]
4888pub unsafe extern "C" fn xmlTextReaderPreserve(reader: *mut XmlTextReader) -> *mut _xmlNode {
4889 if reader.is_null() {
4890 return ptr::null_mut();
4891 }
4892 unsafe { (*reader).cur_node }
4893}
4894
4895#[no_mangle]
4900pub unsafe extern "C" fn xmlTextReaderPreservePattern(
4901 reader: *mut XmlTextReader,
4902 _pattern: *const xmlChar,
4903 _namespaces: *mut *const xmlChar,
4904) -> c_int {
4905 if reader.is_null() {
4906 return -1;
4907 }
4908 0
4909}
4910
4911#[no_mangle]
4917pub unsafe extern "C" fn xmlTextReaderSetErrorHandler(
4918 reader: *mut XmlTextReader,
4919 f: Option<xmlTextReaderErrorFunc>,
4920 arg: *mut c_void,
4921) {
4922 if reader.is_null() {
4923 return;
4924 }
4925 unsafe {
4926 (*reader).error_handler = f;
4927 (*reader).error_arg = arg;
4928 }
4929}
4930
4931#[no_mangle]
4937pub unsafe extern "C" fn xmlTextReaderGetErrorHandler(
4938 reader: *mut XmlTextReader,
4939 f: *mut Option<xmlTextReaderErrorFunc>,
4940 arg: *mut *mut c_void,
4941) {
4942 if reader.is_null() {
4943 return;
4944 }
4945 unsafe {
4946 if !f.is_null() {
4947 *f = (*reader).error_handler;
4948 }
4949 if !arg.is_null() {
4950 *arg = (*reader).error_arg;
4951 }
4952 }
4953}
4954
4955#[no_mangle]
4957pub unsafe extern "C" fn xmlTextReaderSetStructuredErrorHandler(
4958 reader: *mut XmlTextReader,
4959 f: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4960 arg: *mut c_void,
4961) {
4962 if reader.is_null() {
4963 return;
4964 }
4965 unsafe {
4966 (*reader).structured_handler = f;
4967 (*reader).structured_arg = arg;
4968 }
4969}
4970
4971#[no_mangle]
4976pub unsafe extern "C" fn xmlTextReaderGetLastError(
4977 reader: *mut XmlTextReader,
4978) -> *const crate::abi::structs::_xmlError {
4979 if reader.is_null() {
4980 return ptr::null();
4981 }
4982 let r = unsafe { &mut *reader };
4983 if let Some(msg) = r.errors.last() {
4987 unsafe {
4988 let bytes = msg.as_bytes();
4991 let m = libc::malloc(bytes.len() + 1) as *mut xmlChar;
4992 if !m.is_null() {
4993 libc::memcpy(
4994 m as *mut libc::c_void,
4995 bytes.as_ptr() as *const libc::c_void,
4996 bytes.len(),
4997 );
4998 *m.add(bytes.len()) = 0;
4999 if !r.last_err.message.is_null() {
5000 libc::free(r.last_err.message as *mut libc::c_void);
5001 }
5002 (*reader).last_err.message = m as *mut c_char;
5003 (*reader).last_err.domain = crate::abi::types::XML_FROM_PARSER as c_int;
5004 (*reader).last_err.level = crate::abi::types::xmlErrorLevel::XML_ERR_ERROR as c_int;
5005 (*reader).last_err.code = crate::abi::types::XML_ERR_INTERNAL_ERROR as c_int;
5006 }
5007 }
5008 }
5009 &(*reader).last_err as *const crate::abi::structs::_xmlError
5010}
5011
5012#[no_mangle]
5018pub unsafe extern "C" fn xmlTextReaderLocatorBaseURI(
5019 locator: *mut XmlTextReaderLocator,
5020) -> *mut xmlChar {
5021 if locator.is_null() {
5022 return ptr::null_mut();
5023 }
5024 unsafe {
5025 let r = (*locator).reader;
5026 if r.is_null() {
5027 return ptr::null_mut();
5028 }
5029 xml_strdup((*r).URL)
5030 }
5031}
5032
5033#[no_mangle]
5035pub unsafe extern "C" fn xmlTextReaderLocatorLineNumber(
5036 locator: *mut XmlTextReaderLocator,
5037) -> c_int {
5038 if locator.is_null() {
5039 return -1;
5040 }
5041 unsafe {
5042 let r = (*locator).reader;
5043 if r.is_null() {
5044 return -1;
5045 }
5046 let node = (*r).cur_node;
5047 if node.is_null() {
5048 return -1;
5049 }
5050 (*node).line as c_int
5051 }
5052}
5053
5054#[no_mangle]
5059pub unsafe extern "C" fn xmlTextReaderGetRemainder(
5060 _reader: *mut XmlTextReader,
5061) -> *mut crate::abi::structs::_xmlParserInputBuffer {
5062 ptr::null_mut()
5063}
5064
5065#[no_mangle]
5067pub unsafe extern "C" fn xmlTextReaderSetMaxAmplification(
5068 reader: *mut XmlTextReader,
5069 maxAmpl: c_uint,
5070) {
5071 if reader.is_null() {
5072 return;
5073 }
5074 unsafe { (*reader).max_amplification = maxAmpl as c_int };
5075}
5076
5077#[no_mangle]
5084pub unsafe extern "C" fn xmlTextReaderSchemaValidate(
5085 reader: *mut XmlTextReader,
5086 xsd: *const c_char,
5087) -> c_int {
5088 if reader.is_null() || xsd.is_null() {
5089 return -1;
5090 }
5091 if unsafe { (*reader).doc }.is_null() {
5093 if unsafe { (*reader).parsed } == false {
5094 unsafe { (*reader).Read() };
5095 }
5096 }
5097 let ctxt = crate::xml::schemas::xmlSchemaNewParserCtxt(xsd);
5098 if ctxt.is_null() {
5099 return -1;
5100 }
5101 let schema = crate::xml::schemas::xmlSchemaParse(ctxt);
5102 if schema.is_null() {
5103 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5104 return -1;
5105 }
5106 let vctxt = crate::xml::schemas::xmlSchemaNewValidCtxt(schema);
5107 if vctxt.is_null() {
5108 crate::xml::schemas::xmlSchemaFree(schema);
5109 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5110 return -1;
5111 }
5112 let ret = crate::xml::schemas::xmlSchemaValidateDoc(vctxt, unsafe { (*reader).doc });
5113 crate::xml::schemas::xmlSchemaFreeValidCtxt(vctxt);
5114 crate::xml::schemas::xmlSchemaFree(schema);
5115 crate::xml::schemas::xmlSchemaFreeParserCtxt(ctxt);
5116 ret
5117}
5118
5119#[no_mangle]
5121pub unsafe extern "C" fn xmlTextReaderSchemaValidateCtxt(
5122 reader: *mut XmlTextReader,
5123 ctxt: *mut c_void,
5124 _options: c_int,
5125) -> c_int {
5126 if reader.is_null() || ctxt.is_null() {
5127 return -1;
5128 }
5129 if unsafe { (*reader).doc }.is_null() {
5130 if unsafe { (*reader).parsed } == false {
5131 unsafe { (*reader).Read() };
5132 }
5133 }
5134 crate::xml::schemas::xmlSchemaValidateDoc(ctxt, unsafe { (*reader).doc })
5135}
5136
5137#[no_mangle]
5139pub unsafe extern "C" fn xmlTextReaderSetSchema(
5140 reader: *mut XmlTextReader,
5141 schema: *mut c_void,
5142) -> c_int {
5143 if reader.is_null() {
5144 return -1;
5145 }
5146 unsafe {
5147 (*reader).schema = schema;
5148 }
5149 0
5150}
5151
5152#[no_mangle]
5154pub unsafe extern "C" fn xmlTextReaderRelaxNGValidate(
5155 reader: *mut XmlTextReader,
5156 rng: *const c_char,
5157) -> c_int {
5158 if reader.is_null() || rng.is_null() {
5159 return -1;
5160 }
5161 if unsafe { (*reader).doc }.is_null() {
5162 if unsafe { (*reader).parsed } == false {
5163 unsafe { (*reader).Read() };
5164 }
5165 }
5166 let ctxt = crate::xml::relaxng::xmlRelaxNGNewParserCtxt(rng);
5167 if ctxt.is_null() {
5168 return -1;
5169 }
5170 let schema = crate::xml::relaxng::xmlRelaxNGParse(ctxt);
5171 if schema.is_null() {
5172 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5173 return -1;
5174 }
5175 let vctxt = crate::xml::relaxng::xmlRelaxNGNewValidCtxt(schema);
5176 if vctxt.is_null() {
5177 crate::xml::relaxng::xmlRelaxNGFree(schema);
5178 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5179 return -1;
5180 }
5181 let ret = crate::xml::relaxng::xmlRelaxNGValidateDoc(vctxt, unsafe { (*reader).doc });
5182 crate::xml::relaxng::xmlRelaxNGFreeValidCtxt(vctxt);
5183 crate::xml::relaxng::xmlRelaxNGFree(schema);
5184 crate::xml::relaxng::xmlRelaxNGFreeParserCtxt(ctxt);
5185 ret
5186}
5187
5188#[no_mangle]
5190pub unsafe extern "C" fn xmlTextReaderRelaxNGValidateCtxt(
5191 reader: *mut XmlTextReader,
5192 ctxt: *mut c_void,
5193 _options: c_int,
5194) -> c_int {
5195 if reader.is_null() || ctxt.is_null() {
5196 return -1;
5197 }
5198 if unsafe { (*reader).doc }.is_null() {
5199 if unsafe { (*reader).parsed } == false {
5200 unsafe { (*reader).Read() };
5201 }
5202 }
5203 crate::xml::relaxng::xmlRelaxNGValidateDoc(ctxt, unsafe { (*reader).doc })
5204}
5205
5206#[no_mangle]
5208pub unsafe extern "C" fn xmlTextReaderRelaxNGSetSchema(
5209 reader: *mut XmlTextReader,
5210 schema: *mut c_void,
5211) -> c_int {
5212 if reader.is_null() {
5213 return -1;
5214 }
5215 unsafe {
5216 (*reader).rng = schema;
5217 }
5218 0
5219}