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};
33
34use crate::abi::allocator::xmlFree;
35use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
36use crate::abi::structs::{_xmlAttr, _xmlDoc, _xmlNode, _xmlParserCtxt, _xmlParserInputBuffer};
37
38use crate::abi::types::xmlElementType::*;
39use crate::abi::types::*;
40use crate::xml::parser::helpers::{
41 create_parser_ctxt, free_parser_ctxt, input_from_file, input_from_io, input_from_memory,
42 parse_document, setup_parser_input,
43};
44use crate::xml::parser::input::InputBuffer;
45use crate::xml::string::{bytes_to_xmlstr, xml_strdup, xmlstr_to_bytes, xmlstr_to_string};
46use crate::xml::tree;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79#[repr(i32)]
80pub(crate) enum ReaderNodeType {
81 NONE = 0,
82 ELEMENT = 1,
83 ATTRIBUTE = 2,
84 TEXT = 3,
85 CDATA = 4,
86 ENTITY_REFERENCE = 5,
87 ENTITY = 6,
88 PROCESSING_INSTRUCTION = 7,
89 COMMENT = 8,
90 DOCUMENT = 9,
91 DOCUMENT_TYPE = 10,
92 DOCUMENT_FRAGMENT = 11,
93 NOTATION = 12,
94 WHITESPACE = 13,
95 SIGNIFICANT_WHITESPACE = 14,
96 END_ELEMENT = 15,
97 END_ENTITY = 16,
98 XML_DECLARATION = 17,
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116#[repr(i32)]
117pub(crate) enum ReadState {
118 NOT_INITIALIZED = 0,
119 INITIALIZED = 1,
120 READING = 2,
121 EOF = 3,
122 CLOSED = 4,
123 ERROR = 5,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139#[repr(i32)]
140pub(crate) enum ParserProp {
141 LOADDTD = 1,
142 DEFAULTATTRS = 2,
143 VALIDATE = 3,
144 SUBST_ENTITIES = 4,
145}
146
147#[derive(Debug, Clone)]
153struct TraversalEvent {
154 node: *mut _xmlNode,
156 is_end: bool,
158 depth: i32,
160}
161
162unsafe fn compute_depth(node: *mut _xmlNode) -> i32 {
170 if node.is_null() {
171 return 0;
172 }
173 let mut depth: i32 = 0;
174 let mut cur = unsafe { (*node).parent };
176 while !cur.is_null() {
177 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
179 depth += 1;
180 }
181 cur = unsafe { (*cur).parent };
183 }
184 depth
185}
186
187fn element_type_to_reader_type(etype: c_int) -> ReaderNodeType {
189 match etype {
190 x if x == XML_ELEMENT_NODE as c_int => ReaderNodeType::ELEMENT,
191 x if x == XML_ATTRIBUTE_NODE as c_int => ReaderNodeType::ATTRIBUTE,
192 x if x == XML_TEXT_NODE as c_int => ReaderNodeType::TEXT,
193 x if x == XML_CDATA_SECTION_NODE as c_int => ReaderNodeType::CDATA,
194 x if x == XML_ENTITY_REF_NODE as c_int => ReaderNodeType::ENTITY_REFERENCE,
195 x if x == XML_ENTITY_NODE as c_int => ReaderNodeType::ENTITY,
196 x if x == XML_PI_NODE as c_int => ReaderNodeType::PROCESSING_INSTRUCTION,
197 x if x == XML_COMMENT_NODE as c_int => ReaderNodeType::COMMENT,
198 x if x == XML_DOCUMENT_NODE as c_int => ReaderNodeType::DOCUMENT,
199 x if x == XML_DOCUMENT_TYPE_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
200 x if x == XML_DOCUMENT_FRAG_NODE as c_int => ReaderNodeType::DOCUMENT_FRAGMENT,
201 x if x == XML_NOTATION_NODE as c_int => ReaderNodeType::NOTATION,
202 x if x == XML_DTD_NODE as c_int => ReaderNodeType::DOCUMENT_TYPE,
203 x if x == XML_NAMESPACE_DECL as c_int => ReaderNodeType::NONE,
204 _ => ReaderNodeType::NONE,
205 }
206}
207
208fn is_whitespace_only(text: &[u8]) -> bool {
210 text.iter()
211 .all(|&b| b == b' ' || b == b'\t' || b == b'\n' || b == b'\r')
212}
213
214pub(crate) struct XmlTextReader {
224 doc: *mut _xmlDoc,
226 ctxt: *mut _xmlParserCtxt,
228 events: Vec<TraversalEvent>,
230 event_index: usize,
232 state: ReadState,
234 cur_node: *mut _xmlNode,
236 node_type: ReaderNodeType,
238 depth: i32,
240 name: *mut xmlChar,
242 value: *mut xmlChar,
244 attribute_count: i32,
246 cur_attribute: i32,
248 options: c_int,
250 encoding: *mut xmlChar,
252 URL: *mut xmlChar,
254 errors: Vec<String>,
256 parsed: bool,
258}
259
260impl XmlTextReader {
261 unsafe fn new(ctxt: *mut _xmlParserCtxt, URL: Option<&[u8]>, encoding: Option<&[u8]>) -> Self {
271 let url_ptr = URL
272 .map(|u| unsafe { bytes_to_xmlstr(u) })
273 .unwrap_or(ptr::null_mut());
274 let enc_ptr = encoding
275 .map(|e| unsafe { bytes_to_xmlstr(e) })
276 .unwrap_or(ptr::null_mut());
277
278 XmlTextReader {
279 doc: ptr::null_mut(),
280 ctxt,
281 events: Vec::new(),
282 event_index: 0,
283 state: ReadState::INITIALIZED,
284 cur_node: ptr::null_mut(),
285 node_type: ReaderNodeType::NONE,
286 depth: 0,
287 name: ptr::null_mut(),
288 value: ptr::null_mut(),
289 attribute_count: -1,
290 cur_attribute: -1,
291 options: 0,
292 encoding: enc_ptr,
293 URL: url_ptr,
294 errors: Vec::new(),
295 parsed: false,
296 }
297 }
298
299 unsafe fn parse_and_build_events(&mut self) -> c_int {
307 if self.ctxt.is_null() {
308 self.state = ReadState::ERROR;
309 self.errors.push("No parser context".to_string());
310 return -1;
311 }
312
313 unsafe {
315 (*self.ctxt).options = self.options;
316 }
317
318 let result = unsafe { parse_document(self.ctxt) };
320
321 let doc = unsafe { (*self.ctxt).myDoc };
323 self.doc = doc;
324
325 if !self.ctxt.is_null() {
327 unsafe { free_parser_ctxt(self.ctxt) };
328 }
329 self.ctxt = ptr::null_mut();
330
331 if result != 0 || doc.is_null() {
332 self.state = ReadState::ERROR;
333 self.errors.push("Failed to parse document".to_string());
334 return -1;
335 }
336
337 if self.encoding.is_null() && !doc.is_null() {
339 let doc_enc = unsafe { (*doc).encoding };
341 if !doc_enc.is_null() {
342 self.encoding = unsafe { xml_strdup(doc_enc as *const xmlChar) };
343 }
344 }
345
346 self.build_events();
348
349 self.parsed = true;
350 0
351 }
352
353 fn build_events(&mut self) {
358 self.events.clear();
359
360 if self.doc.is_null() {
361 return;
362 }
363
364 let root = unsafe { (*self.doc).children };
366 if root.is_null() {
367 return;
368 }
369
370 unsafe {
373 let mut n = root;
374 while !n.is_null() {
375 self.walk_tree(n, 0);
376 n = (*n).next;
377 }
378 }
379 }
380
381 unsafe fn walk_tree(&mut self, node: *mut _xmlNode, depth: i32) {
387 if node.is_null() {
388 return;
389 }
390
391 let node_type = unsafe { (*node).type_ };
393
394 if node_type == XML_ELEMENT_NODE as c_int {
397 self.events.push(TraversalEvent {
398 node,
399 is_end: false,
400 depth,
401 });
402
403 let mut child = unsafe { (*node).children };
406 while !child.is_null() {
407 let child_depth = depth + 1;
408 self.walk_tree(child, child_depth);
409 child = unsafe { (*child).next };
411 }
412
413 self.events.push(TraversalEvent {
415 node,
416 is_end: true,
417 depth,
418 });
419 } else if node_type == XML_TEXT_NODE as c_int
420 || node_type == XML_CDATA_SECTION_NODE as c_int
421 || node_type == XML_COMMENT_NODE as c_int
422 || node_type == XML_PI_NODE as c_int
423 || node_type == XML_ENTITY_REF_NODE as c_int
424 {
425 if node_type == XML_TEXT_NODE as c_int || node_type == XML_CDATA_SECTION_NODE as c_int {
428 let content = unsafe { (*node).content };
429 if !content.is_null() {
430 let len = crate::xml::tree::xml_strlen(content);
431 let slice = unsafe { core::slice::from_raw_parts(content, len as usize) };
432 if slice
433 .iter()
434 .all(|&b| b == b' ' || b == b'\t' || b == b'\n' || b == b'\r')
435 {
436 return;
438 }
439 }
440 }
441 self.events.push(TraversalEvent {
442 node,
443 is_end: false,
444 depth,
445 });
446 } else {
447 self.events.push(TraversalEvent {
449 node,
450 is_end: false,
451 depth,
452 });
453 }
454 }
455
456 fn position_at(&mut self, index: usize) {
460 if index >= self.events.len() {
461 self.state = ReadState::EOF;
462 self.cur_node = ptr::null_mut();
463 self.node_type = ReaderNodeType::NONE;
464 self.depth = 0;
465 self.clear_cached_name();
466 self.clear_cached_value();
467 self.attribute_count = -1;
468 self.cur_attribute = -1;
469 return;
470 }
471
472 let ev_node: *mut _xmlNode;
474 let ev_is_end: bool;
475 let ev_depth: i32;
476 {
477 let event = &self.events[index];
478 ev_node = event.node;
479 ev_is_end = event.is_end;
480 ev_depth = event.depth;
481 }
482
483 self.event_index = index;
484 self.cur_node = ev_node;
485 self.depth = ev_depth;
486
487 let etype = unsafe { (*ev_node).type_ };
489
490 if ev_is_end {
491 self.node_type = ReaderNodeType::END_ELEMENT;
492 } else {
493 self.node_type = element_type_to_reader_type(etype);
494 }
495
496 unsafe { self.cache_name_and_value(ev_node, ev_is_end) };
499
500 if etype == XML_ELEMENT_NODE as c_int && !ev_is_end {
502 self.attribute_count = unsafe { self.count_attributes(ev_node) };
504 } else {
505 self.attribute_count = -1;
506 }
507
508 self.cur_attribute = -1;
510 }
511
512 unsafe fn cache_name_and_value(&mut self, node: *mut _xmlNode, is_end: bool) {
518 self.clear_cached_name();
519 self.clear_cached_value();
520
521 if node.is_null() {
522 return;
523 }
524
525 let etype = unsafe { (*node).type_ };
527
528 let name: *mut xmlChar = if is_end {
530 unsafe { (*node).name as *mut xmlChar }
533 } else {
534 if etype == XML_ELEMENT_NODE as c_int
535 || etype == XML_PI_NODE as c_int
536 || etype == XML_ENTITY_REF_NODE as c_int
537 || etype == XML_ENTITY_NODE as c_int
538 || etype == XML_DOCUMENT_TYPE_NODE as c_int
539 || etype == XML_NOTATION_NODE as c_int
540 {
541 unsafe { (*node).name as *mut xmlChar }
543 } else if etype == XML_ATTRIBUTE_NODE as c_int {
544 ptr::null_mut()
546 } else {
547 ptr::null_mut()
548 }
549 };
550
551 if !name.is_null() {
552 self.name = unsafe { xml_strdup(name as *const xmlChar) };
554 }
555
556 let value: *mut xmlChar = if etype == XML_TEXT_NODE as c_int
558 || etype == XML_CDATA_SECTION_NODE as c_int
559 || etype == XML_COMMENT_NODE as c_int
560 {
561 unsafe { (*node).content }
563 } else if etype == XML_PI_NODE as c_int {
564 unsafe { (*node).content }
567 } else if etype == XML_ENTITY_REF_NODE as c_int {
568 unsafe { (*node).content }
571 } else {
572 ptr::null_mut()
573 };
574
575 if !value.is_null() {
576 self.value = unsafe { xml_strdup(value as *const xmlChar) };
578 }
579 }
580
581 unsafe fn count_attributes(&self, node: *mut _xmlNode) -> i32 {
587 let mut count: i32 = 0;
588 let mut prop = unsafe { (*node).properties };
590 while !prop.is_null() {
591 count += 1;
592 prop = unsafe { (*prop).next };
594 }
595 count
596 }
597
598 fn clear_cached_name(&mut self) {
600 if !self.name.is_null() {
601 unsafe { xmlFree(self.name as *mut c_void) };
603 self.name = ptr::null_mut();
604 }
605 }
606
607 fn clear_cached_value(&mut self) {
609 if !self.value.is_null() {
610 unsafe { xmlFree(self.value as *mut c_void) };
612 self.value = ptr::null_mut();
613 }
614 }
615
616 pub unsafe fn Read(&mut self) -> c_int {
624 if self.state == ReadState::ERROR || self.state == ReadState::CLOSED {
625 return -1;
626 }
627
628 if !self.parsed {
630 if self.parse_and_build_events() != 0 {
631 self.state = ReadState::ERROR;
632 return -1;
633 }
634 self.state = ReadState::READING;
635 }
636
637 if self.state == ReadState::EOF {
638 return 0;
639 }
640
641 if self.cur_attribute >= 0 {
643 self.cur_attribute = -1;
644 if !self.cur_node.is_null() {
646 unsafe { self.cache_name_and_value(self.cur_node, false) };
648 }
649 }
650
651 if self.events.is_empty() {
654 self.state = ReadState::EOF;
655 return 0;
656 }
657
658 let next_index = if self.cur_node.is_null() {
665 0
667 } else {
668 self.event_index + 1
669 };
670
671 if next_index < self.events.len() {
672 self.position_at(next_index);
673 1
674 } else {
675 self.state = ReadState::EOF;
676 self.cur_node = ptr::null_mut();
677 self.node_type = ReaderNodeType::NONE;
678 self.depth = 0;
679 self.clear_cached_name();
680 self.clear_cached_value();
681 self.attribute_count = -1;
682 self.cur_attribute = -1;
683 0
684 }
685 }
686
687 pub unsafe fn Next(&mut self) -> c_int {
691 if self.state != ReadState::READING || self.cur_node.is_null() {
692 return -1;
693 }
694
695 let current_depth = self.depth;
701 let mut i = self.event_index + 1;
702
703 while i < self.events.len() {
704 let event = &self.events[i];
705 if event.depth <= current_depth && !event.is_end {
706 self.position_at(i);
707 return 1;
708 }
709 i += 1;
710 }
711
712 0
713 }
714
715 pub unsafe fn MoveToElement(&mut self) -> c_int {
719 if self.cur_attribute < 0 {
720 return 0;
721 }
722 self.cur_attribute = -1;
723 if !self.cur_node.is_null() {
724 unsafe { self.cache_name_and_value(self.cur_node, false) };
726 self.node_type = ReaderNodeType::ELEMENT;
727 }
728 1
729 }
730
731 pub unsafe fn MoveToAttribute(&mut self, name: *const xmlChar) -> c_int {
735 if self.cur_node.is_null() {
736 return -1;
737 }
738
739 let etype = unsafe { (*self.cur_node).type_ };
741 if etype != XML_ELEMENT_NODE as c_int {
742 return -1;
743 }
744
745 let mut prop = unsafe { (*self.cur_node).properties };
747 let mut index: i32 = 0;
748 while !prop.is_null() {
749 let prop_name = unsafe { (*prop).name };
751 if !prop_name.is_null() {
752 if unsafe { crate::xml::string::xml_strcmp(prop_name as *const xmlChar, name) == 0 }
755 {
756 self.cur_attribute = index;
757 self.cache_attribute_info(prop);
759 return 1;
760 }
761 }
762 index += 1;
763 prop = unsafe { (*prop).next };
765 }
766
767 0
768 }
769
770 pub unsafe fn MoveToAttributeNo(&mut self, index: c_int) -> c_int {
774 if self.cur_node.is_null() || index < 0 {
775 return -1;
776 }
777
778 let etype = unsafe { (*self.cur_node).type_ };
780 if etype != XML_ELEMENT_NODE as c_int {
781 return -1;
782 }
783
784 let mut prop = unsafe { (*self.cur_node).properties };
786 let mut i: i32 = 0;
787 while !prop.is_null() {
788 if i == index {
789 self.cur_attribute = index;
790 self.cache_attribute_info(prop);
792 return 1;
793 }
794 i += 1;
795 prop = unsafe { (*prop).next };
797 }
798
799 0
800 }
801
802 pub unsafe fn MoveToFirstAttribute(&mut self) -> c_int {
806 if self.cur_node.is_null() {
807 return -1;
808 }
809
810 let etype = unsafe { (*self.cur_node).type_ };
812 if etype != XML_ELEMENT_NODE as c_int {
813 return -1;
814 }
815
816 let first_prop = unsafe { (*self.cur_node).properties };
818 if first_prop.is_null() {
819 return 0;
820 }
821
822 self.cur_attribute = 0;
823 self.cache_attribute_info(first_prop);
825 1
826 }
827
828 pub unsafe fn MoveToNextAttribute(&mut self) -> c_int {
832 if self.cur_attribute < 0 || self.cur_node.is_null() {
833 return -1;
834 }
835
836 let etype = unsafe { (*self.cur_node).type_ };
838 if etype != XML_ELEMENT_NODE as c_int {
839 return -1;
840 }
841
842 let mut prop = unsafe { (*self.cur_node).properties };
845 let mut i: i32 = 0;
846 while !prop.is_null() && i <= self.cur_attribute {
847 if i == self.cur_attribute {
848 let next_prop = unsafe { (*prop).next };
851 if next_prop.is_null() {
852 return 0;
853 }
854 self.cur_attribute += 1;
855 self.cache_attribute_info(next_prop);
856 return 1;
857 }
858 i += 1;
859 prop = unsafe { (*prop).next };
861 }
862
863 0
864 }
865
866 unsafe fn cache_attribute_info(&mut self, prop: *mut _xmlAttr) {
872 self.node_type = ReaderNodeType::ATTRIBUTE;
873 self.clear_cached_name();
874 self.clear_cached_value();
875
876 let attr = unsafe { &*prop };
878
879 if !attr.name.is_null() {
881 self.name = unsafe { xml_strdup(attr.name as *const xmlChar) };
883 }
884
885 if !attr.children.is_null() {
887 let val = unsafe { (*attr.children).content };
889 if !val.is_null() {
890 self.value = unsafe { xml_strdup(val as *const xmlChar) };
892 }
893 }
894 }
895
896 pub unsafe fn Prev(&mut self) -> c_int {
900 if self.state != ReadState::READING || self.cur_node.is_null() {
901 return -1;
902 }
903
904 let current_depth = self.depth;
906 let mut i = if self.event_index > 0 {
907 self.event_index - 1
908 } else {
909 return 0;
910 };
911
912 loop {
913 let event = &self.events[i];
914 if event.depth == current_depth && !event.is_end {
915 self.position_at(i);
916 return 1;
917 }
918 if i == 0 {
919 break;
920 }
921 i -= 1;
922 }
923
924 0
925 }
926
927 pub fn Depth(&self) -> c_int {
933 self.depth
934 }
935
936 pub fn NodeType(&self) -> ReaderNodeType {
938 self.node_type
939 }
940
941 pub unsafe fn Name(&self) -> *mut xmlChar {
946 if self.name.is_null() {
947 return ptr::null_mut();
948 }
949 unsafe { xml_strdup(self.name as *const xmlChar) }
951 }
952
953 pub unsafe fn Value(&self) -> *mut xmlChar {
958 if self.value.is_null() {
959 return ptr::null_mut();
960 }
961 unsafe { xml_strdup(self.value as *const xmlChar) }
963 }
964
965 pub fn ConstName(&self) -> *const xmlChar {
970 self.name as *const xmlChar
971 }
972
973 pub fn ConstValue(&self) -> *const xmlChar {
978 self.value as *const xmlChar
979 }
980
981 pub fn HasValue(&self) -> c_int {
983 if self.value.is_null() {
984 0
985 } else {
986 1
987 }
988 }
989
990 pub fn HasAttributes(&self) -> c_int {
992 if self.cur_node.is_null() {
993 return 0;
994 }
995 let etype = unsafe { (*self.cur_node).type_ };
997 if etype != XML_ELEMENT_NODE as c_int {
998 return 0;
999 }
1000 let props = unsafe { (*self.cur_node).properties };
1002 if props.is_null() {
1003 0
1004 } else {
1005 1
1006 }
1007 }
1008
1009 pub fn IsEmptyElement(&self) -> c_int {
1011 if self.cur_node.is_null() {
1012 return 0;
1013 }
1014 let etype = unsafe { (*self.cur_node).type_ };
1016 if etype != XML_ELEMENT_NODE as c_int {
1017 return 0;
1018 }
1019 let children = unsafe { (*self.cur_node).children };
1021 if children.is_null() {
1022 1
1023 } else {
1024 0
1025 }
1026 }
1027
1028 pub unsafe fn BaseUri(&self) -> *mut xmlChar {
1033 if self.doc.is_null() {
1035 return ptr::null_mut();
1036 }
1037 let url = unsafe { (*self.doc).URL };
1039 if url.is_null() {
1040 return ptr::null_mut();
1041 }
1042 unsafe { xml_strdup(url as *const xmlChar) }
1044 }
1045
1046 pub unsafe fn LocalName(&self) -> *mut xmlChar {
1051 if self.name.is_null() {
1052 return ptr::null_mut();
1053 }
1054
1055 let name_bytes = unsafe { xmlstr_to_bytes(self.name as *const xmlChar) };
1057
1058 if let Some(pos) = name_bytes.iter().position(|&b| b == b':') {
1060 let local = &name_bytes[pos + 1..];
1062 if local.is_empty() {
1063 return ptr::null_mut();
1064 }
1065 unsafe { bytes_to_xmlstr(local) }
1067 } else {
1068 unsafe { xml_strdup(self.name as *const xmlChar) }
1071 }
1072 }
1073
1074 pub unsafe fn NamespaceUri(&self) -> *mut xmlChar {
1078 if self.cur_node.is_null() {
1079 return ptr::null_mut();
1080 }
1081
1082 let ns = unsafe { (*self.cur_node).ns };
1084 if ns.is_null() {
1085 return ptr::null_mut();
1086 }
1087
1088 let href = unsafe { (*ns).href };
1090 if href.is_null() {
1091 return ptr::null_mut();
1092 }
1093
1094 unsafe { xml_strdup(href as *const xmlChar) }
1096 }
1097
1098 pub unsafe fn Prefix(&self) -> *mut xmlChar {
1102 if self.cur_node.is_null() {
1103 return ptr::null_mut();
1104 }
1105
1106 let ns = unsafe { (*self.cur_node).ns };
1108 if ns.is_null() {
1109 return ptr::null_mut();
1110 }
1111
1112 let prefix = unsafe { (*ns).prefix };
1114 if prefix.is_null() {
1115 return ptr::null_mut();
1116 }
1117
1118 unsafe { xml_strdup(prefix as *const xmlChar) }
1120 }
1121
1122 pub fn AttributeCount(&self) -> c_int {
1124 self.attribute_count
1125 }
1126
1127 pub fn ReadState(&self) -> ReadState {
1129 self.state
1130 }
1131
1132 pub unsafe fn GetAttribute(&self, name: *const xmlChar) -> *mut xmlChar {
1136 if self.cur_node.is_null() {
1137 return ptr::null_mut();
1138 }
1139
1140 let etype = unsafe { (*self.cur_node).type_ };
1142 if etype != XML_ELEMENT_NODE as c_int {
1143 return ptr::null_mut();
1144 }
1145
1146 let mut prop = unsafe { (*self.cur_node).properties };
1148 while !prop.is_null() {
1149 let prop_name = unsafe { (*prop).name };
1151 if !prop_name.is_null() {
1152 if unsafe { crate::xml::string::xml_strcmp(prop_name as *const xmlChar, name) == 0 }
1154 {
1155 let val = unsafe { (*prop).children };
1158 if !val.is_null() {
1159 let content = unsafe { (*val).content };
1161 if !content.is_null() {
1162 return unsafe { xml_strdup(content as *const xmlChar) };
1164 }
1165 }
1166 return ptr::null_mut();
1167 }
1168 }
1169 prop = unsafe { (*prop).next };
1171 }
1172
1173 ptr::null_mut()
1174 }
1175
1176 pub unsafe fn GetAttributeNo(&self, index: c_int) -> *mut xmlChar {
1180 if self.cur_node.is_null() || index < 0 {
1181 return ptr::null_mut();
1182 }
1183
1184 let etype = unsafe { (*self.cur_node).type_ };
1186 if etype != XML_ELEMENT_NODE as c_int {
1187 return ptr::null_mut();
1188 }
1189
1190 let mut prop = unsafe { (*self.cur_node).properties };
1192 let mut i: i32 = 0;
1193 while !prop.is_null() {
1194 if i == index {
1195 let val = unsafe { (*prop).children };
1197 if !val.is_null() {
1198 let content = unsafe { (*val).content };
1200 if !content.is_null() {
1201 return unsafe { xml_strdup(content as *const xmlChar) };
1203 }
1204 }
1205 return ptr::null_mut();
1206 }
1207 i += 1;
1208 prop = unsafe { (*prop).next };
1210 }
1211
1212 ptr::null_mut()
1213 }
1214
1215 pub unsafe fn GetAttributeNs(
1219 &self,
1220 localName: *const xmlChar,
1221 namespaceURI: *const xmlChar,
1222 ) -> *mut xmlChar {
1223 if self.cur_node.is_null() {
1224 return ptr::null_mut();
1225 }
1226
1227 let etype = unsafe { (*self.cur_node).type_ };
1229 if etype != XML_ELEMENT_NODE as c_int {
1230 return ptr::null_mut();
1231 }
1232
1233 let mut prop = unsafe { (*self.cur_node).properties };
1235 while !prop.is_null() {
1236 let prop_local = unsafe { (*prop).name };
1238 let prop_ns = unsafe { (*prop).ns };
1239
1240 if prop_local.is_null() {
1242 prop = unsafe { (*prop).next };
1244 continue;
1245 }
1246
1247 let name_match = unsafe {
1249 crate::xml::string::xml_strcmp(prop_local as *const xmlChar, localName) == 0
1250 };
1251
1252 if name_match {
1253 let ns_match = if namespaceURI.is_null() {
1255 prop_ns.is_null()
1256 } else if prop_ns.is_null() {
1257 false
1258 } else {
1259 unsafe {
1261 crate::xml::string::xml_strcmp(
1262 (*prop_ns).href as *const xmlChar,
1263 namespaceURI,
1264 ) == 0
1265 }
1266 };
1267
1268 if ns_match {
1269 let val = unsafe { (*prop).children };
1271 if !val.is_null() {
1272 let content = unsafe { (*val).content };
1274 if !content.is_null() {
1275 return unsafe { xml_strdup(content as *const xmlChar) };
1277 }
1278 }
1279 return ptr::null_mut();
1280 }
1281 }
1282
1283 prop = unsafe { (*prop).next };
1285 }
1286
1287 ptr::null_mut()
1288 }
1289
1290 pub unsafe fn LookupNamespace(&self, prefix: *const xmlChar) -> *mut xmlChar {
1294 if self.cur_node.is_null() {
1295 return ptr::null_mut();
1296 }
1297
1298 let mut cur = self.cur_node;
1301 while !cur.is_null() {
1302 let mut ns_def = unsafe { (*cur).nsDef };
1304 while !ns_def.is_null() {
1305 let ns_prefix = unsafe { (*ns_def).prefix };
1307
1308 let match_prefix = if prefix.is_null() || *prefix == 0 {
1309 ns_prefix.is_null()
1311 } else if ns_prefix.is_null() {
1312 false
1313 } else {
1314 unsafe {
1316 crate::xml::string::xml_strcmp(ns_prefix as *const xmlChar, prefix) == 0
1317 }
1318 };
1319
1320 if match_prefix {
1321 let href = unsafe { (*ns_def).href };
1323 if !href.is_null() {
1324 return unsafe { xml_strdup(href as *const xmlChar) };
1326 }
1327 return ptr::null_mut();
1328 }
1329
1330 ns_def = unsafe { (*ns_def).next };
1332 }
1333
1334 cur = unsafe { (*cur).parent };
1336 }
1337
1338 ptr::null_mut()
1339 }
1340
1341 pub fn GetParserProp(&self, prop: c_int) -> c_int {
1343 match prop {
1344 1 => {
1345 if (self.options & XML_PARSE_DTDLOAD) != 0 { 1 } else { 0 }
1346 }
1347 2 => {
1348 if (self.options & XML_PARSE_DTDATTR) != 0 { 1 } else { 0 }
1349 }
1350 3 => {
1351 if (self.options & XML_PARSE_DTDVALID) != 0 { 1 } else { 0 }
1352 }
1353 4 => {
1354 if (self.options & XML_PARSE_NOENT) != 0 { 1 } else { 0 }
1355 }
1356 _ => -1,
1357 }
1358 }
1359
1360 pub fn SetParserProp(&mut self, prop: c_int, value: c_int) -> c_int {
1362 match prop {
1363 1 => {
1364 if value != 0 {
1365 self.options |= XML_PARSE_DTDLOAD;
1366 } else {
1367 self.options &= !XML_PARSE_DTDLOAD;
1368 }
1369 0
1370 }
1371 2 => {
1372 if value != 0 {
1373 self.options |= XML_PARSE_DTDATTR;
1374 } else {
1375 self.options &= !XML_PARSE_DTDATTR;
1376 }
1377 0
1378 }
1379 3 => {
1380 if value != 0 {
1381 self.options |= XML_PARSE_DTDVALID;
1382 } else {
1383 self.options &= !XML_PARSE_DTDVALID;
1384 }
1385 0
1386 }
1387 4 => {
1388 if value != 0 {
1389 self.options |= XML_PARSE_NOENT;
1390 } else {
1391 self.options &= !XML_PARSE_NOENT;
1392 }
1393 0
1394 }
1395 _ => -1,
1396 }
1397 }
1398
1399 pub fn CurrentDoc(&self) -> *mut _xmlDoc {
1401 self.doc
1402 }
1403}
1404
1405impl Drop for XmlTextReader {
1406 fn drop(&mut self) {
1407 self.clear_cached_name();
1409 self.clear_cached_value();
1410
1411 if !self.encoding.is_null() {
1413 unsafe { xmlFree(self.encoding as *mut c_void) };
1415 self.encoding = ptr::null_mut();
1416 }
1417 if !self.URL.is_null() {
1418 unsafe { xmlFree(self.URL as *mut c_void) };
1420 self.URL = ptr::null_mut();
1421 }
1422
1423 if !self.doc.is_null() {
1425 unsafe { tree::free_doc(self.doc) };
1428 self.doc = ptr::null_mut();
1429 }
1430
1431 if !self.ctxt.is_null() {
1433 unsafe { free_parser_ctxt(self.ctxt) };
1435 self.ctxt = ptr::null_mut();
1436 }
1437 }
1438}
1439
1440unsafe fn reader_from_input(
1450 input: *mut _xmlParserInputBuffer,
1451 URL: *const c_char,
1452 encoding: *const c_char,
1453 options: c_int,
1454) -> *mut XmlTextReader {
1455 if input.is_null() {
1456 return ptr::null_mut();
1457 }
1458
1459 let ctxt = create_parser_ctxt();
1461 if ctxt.is_null() {
1462 return ptr::null_mut();
1463 }
1464
1465 let mut data = Vec::new();
1467 let mut tmp = [0u8; 4096];
1468
1469 let read_cb = unsafe { (*input).readcallback };
1471 let ioctx = unsafe { (*input).context };
1472
1473 if let Some(read) = read_cb {
1474 loop {
1475 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
1477 if n <= 0 {
1478 break;
1479 }
1480 data.extend_from_slice(&tmp[..n as usize]);
1481 }
1482 }
1483
1484 let close_cb = unsafe { (*input).closecallback };
1487 if let Some(close) = close_cb {
1488 unsafe { close(ioctx) };
1490 }
1491
1492 let input_buf = InputBuffer::from_memory(&data, None);
1494
1495 setup_parser_input(ctxt, input_buf);
1497
1498 unsafe {
1500 (*ctxt).options = options;
1501 }
1502
1503 let url_bytes = if URL.is_null() {
1505 None
1506 } else {
1507 unsafe {
1509 let cstr = std::ffi::CStr::from_ptr(URL);
1510 Some(cstr.to_bytes().to_vec())
1511 }
1512 };
1513
1514 let enc_bytes = if encoding.is_null() {
1515 None
1516 } else {
1517 unsafe {
1519 let cstr = std::ffi::CStr::from_ptr(encoding);
1520 Some(cstr.to_bytes().to_vec())
1521 }
1522 };
1523
1524 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1526 reader.options = options;
1527
1528 Box::into_raw(Box::new(reader))
1530}
1531
1532#[no_mangle]
1549pub unsafe extern "C" fn xmlNewTextReader(
1550 input: *mut _xmlParserInputBuffer,
1551 URI: *const c_char,
1552) -> *mut XmlTextReader {
1553 unsafe { reader_from_input(input, URI, ptr::null(), 0) }
1555}
1556
1557#[no_mangle]
1570pub unsafe extern "C" fn xmlReaderForFile(
1571 filename: *const c_char,
1572 encoding: *const c_char,
1573 options: c_int,
1574) -> *mut XmlTextReader {
1575 if filename.is_null() {
1576 return ptr::null_mut();
1577 }
1578
1579 let ctxt = unsafe { create_parser_ctxt() };
1581 if ctxt.is_null() {
1582 return ptr::null_mut();
1583 }
1584
1585 let input = match unsafe { input_from_file(filename) } {
1587 Ok(input) => input,
1588 Err(_) => {
1589 unsafe { free_parser_ctxt(ctxt) };
1591 return ptr::null_mut();
1592 }
1593 };
1594
1595 unsafe { setup_parser_input(ctxt, input) };
1597 unsafe {
1598 (*ctxt).options = options;
1599 }
1600
1601 let enc_bytes = if encoding.is_null() {
1602 None
1603 } else {
1604 unsafe {
1606 let cstr = std::ffi::CStr::from_ptr(encoding);
1607 Some(cstr.to_bytes().to_vec())
1608 }
1609 };
1610
1611 let mut reader = XmlTextReader::new(ctxt, None, enc_bytes.as_deref());
1612 reader.options = options;
1613 Box::into_raw(Box::new(reader))
1614}
1615
1616#[no_mangle]
1630pub unsafe extern "C" fn xmlReaderForMemory(
1631 buffer: *const c_char,
1632 size: c_int,
1633 URL: *const c_char,
1634 encoding: *const c_char,
1635 options: c_int,
1636) -> *mut XmlTextReader {
1637 if buffer.is_null() || size <= 0 {
1638 return ptr::null_mut();
1639 }
1640
1641 let ctxt = unsafe { create_parser_ctxt() };
1643 if ctxt.is_null() {
1644 return ptr::null_mut();
1645 }
1646
1647 let input = unsafe { input_from_memory(buffer, size) };
1649
1650 unsafe { setup_parser_input(ctxt, input) };
1652 unsafe {
1653 (*ctxt).options = options;
1654 }
1655
1656 let url_bytes = if URL.is_null() {
1657 None
1658 } else {
1659 unsafe {
1661 let cstr = std::ffi::CStr::from_ptr(URL);
1662 Some(cstr.to_bytes().to_vec())
1663 }
1664 };
1665
1666 let enc_bytes = if encoding.is_null() {
1667 None
1668 } else {
1669 unsafe {
1671 let cstr = std::ffi::CStr::from_ptr(encoding);
1672 Some(cstr.to_bytes().to_vec())
1673 }
1674 };
1675
1676 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1677 reader.options = options;
1678 Box::into_raw(Box::new(reader))
1679}
1680
1681#[no_mangle]
1695pub unsafe extern "C" fn xmlReaderForFd(
1696 fd: c_int,
1697 URL: *const c_char,
1698 encoding: *const c_char,
1699 options: c_int,
1700) -> *mut XmlTextReader {
1701 let ctxt = unsafe { create_parser_ctxt() };
1703 if ctxt.is_null() {
1704 return ptr::null_mut();
1705 }
1706
1707 let mut buf = Vec::new();
1709 let mut tmp = [0u8; 4096];
1710 loop {
1711 let n = unsafe { libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len()) };
1713 if n <= 0 {
1714 break;
1715 }
1716 buf.extend_from_slice(&tmp[..n as usize]);
1717 }
1718
1719 let input = unsafe { input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int) };
1721
1722 unsafe { setup_parser_input(ctxt, input) };
1724 unsafe {
1725 (*ctxt).options = options;
1726 }
1727
1728 let url_bytes = if URL.is_null() {
1729 None
1730 } else {
1731 unsafe {
1733 let cstr = std::ffi::CStr::from_ptr(URL);
1734 Some(cstr.to_bytes().to_vec())
1735 }
1736 };
1737
1738 let enc_bytes = if encoding.is_null() {
1739 None
1740 } else {
1741 unsafe {
1743 let cstr = std::ffi::CStr::from_ptr(encoding);
1744 Some(cstr.to_bytes().to_vec())
1745 }
1746 };
1747
1748 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1749 reader.options = options;
1750 Box::into_raw(Box::new(reader))
1751}
1752
1753#[no_mangle]
1769pub unsafe extern "C" fn xmlReaderForIO(
1770 ioread: Option<xmlInputReadCallback>,
1771 ioclose: Option<xmlInputCloseCallback>,
1772 ioctx: *mut c_void,
1773 URL: *const c_char,
1774 encoding: *const c_char,
1775 options: c_int,
1776) -> *mut XmlTextReader {
1777 let ctxt = unsafe { create_parser_ctxt() };
1779 if ctxt.is_null() {
1780 return ptr::null_mut();
1781 }
1782
1783 let input = unsafe { input_from_io(ioread, ioclose, ioctx) };
1785
1786 unsafe { setup_parser_input(ctxt, input) };
1788 unsafe {
1789 (*ctxt).options = options;
1790 }
1791
1792 let url_bytes = if URL.is_null() {
1793 None
1794 } else {
1795 unsafe {
1797 let cstr = std::ffi::CStr::from_ptr(URL);
1798 Some(cstr.to_bytes().to_vec())
1799 }
1800 };
1801
1802 let enc_bytes = if encoding.is_null() {
1803 None
1804 } else {
1805 unsafe {
1807 let cstr = std::ffi::CStr::from_ptr(encoding);
1808 Some(cstr.to_bytes().to_vec())
1809 }
1810 };
1811
1812 let mut reader = XmlTextReader::new(ctxt, url_bytes.as_deref(), enc_bytes.as_deref());
1813 reader.options = options;
1814 Box::into_raw(Box::new(reader))
1815}
1816
1817#[no_mangle]
1836pub unsafe extern "C" fn xmlTextReaderRead(reader: *mut XmlTextReader) -> c_int {
1837 if reader.is_null() {
1838 return -1;
1839 }
1840 unsafe { (*reader).Read() }
1842}
1843
1844#[no_mangle]
1858pub unsafe extern "C" fn xmlTextReaderNext(reader: *mut XmlTextReader) -> c_int {
1859 if reader.is_null() {
1860 return -1;
1861 }
1862 unsafe { (*reader).Next() }
1864}
1865
1866#[no_mangle]
1878pub unsafe extern "C" fn xmlTextReaderNextSibling(reader: *mut XmlTextReader) -> c_int {
1879 if reader.is_null() {
1880 return -1;
1881 }
1882 unsafe { (*reader).Next() }
1884}
1885
1886#[no_mangle]
1900pub unsafe extern "C" fn xmlTextReaderPrev(reader: *mut XmlTextReader) -> c_int {
1901 if reader.is_null() {
1902 return -1;
1903 }
1904 unsafe { (*reader).Prev() }
1906}
1907
1908#[no_mangle]
1922pub unsafe extern "C" fn xmlTextReaderMoveToElement(reader: *mut XmlTextReader) -> c_int {
1923 if reader.is_null() {
1924 return -1;
1925 }
1926 unsafe { (*reader).MoveToElement() }
1928}
1929
1930#[no_mangle]
1944pub unsafe extern "C" fn xmlTextReaderMoveToAttribute(
1945 reader: *mut XmlTextReader,
1946 name: *const xmlChar,
1947) -> c_int {
1948 if reader.is_null() || name.is_null() {
1949 return -1;
1950 }
1951 unsafe { (*reader).MoveToAttribute(name) }
1953}
1954
1955#[no_mangle]
1969pub unsafe extern "C" fn xmlTextReaderMoveToAttributeNo(
1970 reader: *mut XmlTextReader,
1971 index: c_int,
1972) -> c_int {
1973 if reader.is_null() {
1974 return -1;
1975 }
1976 unsafe { (*reader).MoveToAttributeNo(index) }
1978}
1979
1980#[no_mangle]
1994pub unsafe extern "C" fn xmlTextReaderMoveToFirstAttribute(reader: *mut XmlTextReader) -> c_int {
1995 if reader.is_null() {
1996 return -1;
1997 }
1998 unsafe { (*reader).MoveToFirstAttribute() }
2000}
2001
2002#[no_mangle]
2016pub unsafe extern "C" fn xmlTextReaderMoveToNextAttribute(reader: *mut XmlTextReader) -> c_int {
2017 if reader.is_null() {
2018 return -1;
2019 }
2020 unsafe { (*reader).MoveToNextAttribute() }
2022}
2023
2024#[no_mangle]
2042pub unsafe extern "C" fn xmlTextReaderAttributeCount(reader: *mut XmlTextReader) -> c_int {
2043 if reader.is_null() {
2044 return -1;
2045 }
2046 unsafe { (*reader).AttributeCount() }
2048}
2049
2050#[no_mangle]
2064pub unsafe extern "C" fn xmlTextReaderDepth(reader: *mut XmlTextReader) -> c_int {
2065 if reader.is_null() {
2066 return -1;
2067 }
2068 unsafe { (*reader).Depth() }
2070}
2071
2072#[no_mangle]
2086pub unsafe extern "C" fn xmlTextReaderNodeType(reader: *mut XmlTextReader) -> c_int {
2087 if reader.is_null() {
2088 return -1;
2089 }
2090 unsafe { (*reader).NodeType() as c_int }
2092}
2093
2094#[no_mangle]
2109pub unsafe extern "C" fn xmlTextReaderName(reader: *mut XmlTextReader) -> *mut xmlChar {
2110 if reader.is_null() {
2111 return ptr::null_mut();
2112 }
2113 unsafe { (*reader).Name() }
2115}
2116
2117#[no_mangle]
2132pub unsafe extern "C" fn xmlTextReaderValue(reader: *mut XmlTextReader) -> *mut xmlChar {
2133 if reader.is_null() {
2134 return ptr::null_mut();
2135 }
2136 unsafe { (*reader).Value() }
2138}
2139
2140#[no_mangle]
2155pub unsafe extern "C" fn xmlTextReaderConstName(reader: *mut XmlTextReader) -> *const xmlChar {
2156 if reader.is_null() {
2157 return ptr::null();
2158 }
2159 unsafe { (*reader).ConstName() }
2161}
2162
2163#[no_mangle]
2178pub unsafe extern "C" fn xmlTextReaderConstValue(reader: *mut XmlTextReader) -> *const xmlChar {
2179 if reader.is_null() {
2180 return ptr::null();
2181 }
2182 unsafe { (*reader).ConstValue() }
2184}
2185
2186#[no_mangle]
2201pub unsafe extern "C" fn xmlTextReaderBaseUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2202 if reader.is_null() {
2203 return ptr::null_mut();
2204 }
2205 unsafe { (*reader).BaseUri() }
2207}
2208
2209#[no_mangle]
2223pub unsafe extern "C" fn xmlTextReaderLocalName(reader: *mut XmlTextReader) -> *mut xmlChar {
2224 if reader.is_null() {
2225 return ptr::null_mut();
2226 }
2227 unsafe { (*reader).LocalName() }
2229}
2230
2231#[no_mangle]
2245pub unsafe extern "C" fn xmlTextReaderNamespaceUri(reader: *mut XmlTextReader) -> *mut xmlChar {
2246 if reader.is_null() {
2247 return ptr::null_mut();
2248 }
2249 unsafe { (*reader).NamespaceUri() }
2251}
2252
2253#[no_mangle]
2267pub unsafe extern "C" fn xmlTextReaderPrefix(reader: *mut XmlTextReader) -> *mut xmlChar {
2268 if reader.is_null() {
2269 return ptr::null_mut();
2270 }
2271 unsafe { (*reader).Prefix() }
2273}
2274
2275#[no_mangle]
2289pub unsafe extern "C" fn xmlTextReaderHasValue(reader: *mut XmlTextReader) -> c_int {
2290 if reader.is_null() {
2291 return 0;
2292 }
2293 unsafe { (*reader).HasValue() }
2295}
2296
2297#[no_mangle]
2311pub unsafe extern "C" fn xmlTextReaderHasAttributes(reader: *mut XmlTextReader) -> c_int {
2312 if reader.is_null() {
2313 return 0;
2314 }
2315 unsafe { (*reader).HasAttributes() }
2317}
2318
2319#[no_mangle]
2333pub unsafe extern "C" fn xmlTextReaderIsEmptyElement(reader: *mut XmlTextReader) -> c_int {
2334 if reader.is_null() {
2335 return 0;
2336 }
2337 unsafe { (*reader).IsEmptyElement() }
2339}
2340
2341#[no_mangle]
2355pub unsafe extern "C" fn xmlTextReaderReadState(reader: *mut XmlTextReader) -> c_int {
2356 if reader.is_null() {
2357 return ReadState::ERROR as c_int;
2358 }
2359 unsafe { (*reader).ReadState() as c_int }
2361}
2362
2363#[no_mangle]
2381pub unsafe extern "C" fn xmlTextReaderGetAttribute(
2382 reader: *mut XmlTextReader,
2383 name: *const xmlChar,
2384) -> *mut xmlChar {
2385 if reader.is_null() || name.is_null() {
2386 return ptr::null_mut();
2387 }
2388 unsafe { (*reader).GetAttribute(name) }
2390}
2391
2392#[no_mangle]
2406pub unsafe extern "C" fn xmlTextReaderGetAttributeNo(
2407 reader: *mut XmlTextReader,
2408 index: c_int,
2409) -> *mut xmlChar {
2410 if reader.is_null() {
2411 return ptr::null_mut();
2412 }
2413 unsafe { (*reader).GetAttributeNo(index) }
2415}
2416
2417#[no_mangle]
2433pub unsafe extern "C" fn xmlTextReaderGetAttributeNs(
2434 reader: *mut XmlTextReader,
2435 localName: *const xmlChar,
2436 namespaceURI: *const xmlChar,
2437) -> *mut xmlChar {
2438 if reader.is_null() || localName.is_null() {
2439 return ptr::null_mut();
2440 }
2441 unsafe { (*reader).GetAttributeNs(localName, namespaceURI) }
2443}
2444
2445#[no_mangle]
2459pub unsafe extern "C" fn xmlTextReaderLookupNamespace(
2460 reader: *mut XmlTextReader,
2461 prefix: *const xmlChar,
2462) -> *mut xmlChar {
2463 if reader.is_null() {
2464 return ptr::null_mut();
2465 }
2466 unsafe { (*reader).LookupNamespace(prefix) }
2468}
2469
2470#[no_mangle]
2488pub unsafe extern "C" fn xmlTextReaderGetParserProp(
2489 reader: *mut XmlTextReader,
2490 prop: c_int,
2491) -> c_int {
2492 if reader.is_null() {
2493 return -1;
2494 }
2495 unsafe { (*reader).GetParserProp(prop) }
2497}
2498
2499#[no_mangle]
2513pub unsafe extern "C" fn xmlTextReaderSetParserProp(
2514 reader: *mut XmlTextReader,
2515 prop: c_int,
2516 value: c_int,
2517) -> c_int {
2518 if reader.is_null() {
2519 return -1;
2520 }
2521 unsafe { (*reader).SetParserProp(prop, value) }
2523}
2524
2525#[no_mangle]
2542pub unsafe extern "C" fn xmlFreeTextReader(reader: *mut XmlTextReader) {
2543 if reader.is_null() {
2544 return;
2545 }
2546 unsafe {
2549 let _ = Box::from_raw(reader);
2550 }
2551}
2552
2553#[no_mangle]
2569pub unsafe extern "C" fn xmlTextReaderSetup(
2570 reader: *mut XmlTextReader,
2571 input: *mut _xmlParserInputBuffer,
2572 URL: *const c_char,
2573 encoding: *const c_char,
2574 options: c_int,
2575) -> c_int {
2576 if reader.is_null() {
2577 return -1;
2578 }
2579
2580 let r = unsafe { &mut *reader };
2582
2583 r.clear_cached_name();
2585 r.clear_cached_value();
2586
2587 if !r.doc.is_null() {
2589 unsafe { tree::free_doc(r.doc) };
2591 r.doc = ptr::null_mut();
2592 }
2593
2594 if !r.ctxt.is_null() {
2596 unsafe { free_parser_ctxt(r.ctxt) };
2598 r.ctxt = ptr::null_mut();
2599 }
2600
2601 r.events.clear();
2602 r.event_index = 0;
2603 r.state = ReadState::INITIALIZED;
2604 r.cur_node = ptr::null_mut();
2605 r.node_type = ReaderNodeType::NONE;
2606 r.depth = 0;
2607 r.attribute_count = -1;
2608 r.cur_attribute = -1;
2609 r.options = options;
2610 r.parsed = false;
2611 r.errors.clear();
2612
2613 if !r.URL.is_null() {
2615 unsafe { xmlFree(r.URL as *mut c_void) };
2617 r.URL = ptr::null_mut();
2618 }
2619 if !URL.is_null() {
2620 let url_str = unsafe { std::ffi::CStr::from_ptr(URL) };
2622 r.URL = unsafe { bytes_to_xmlstr(url_str.to_bytes()) };
2624 }
2625
2626 if !r.encoding.is_null() {
2628 unsafe { xmlFree(r.encoding as *mut c_void) };
2630 r.encoding = ptr::null_mut();
2631 }
2632 if !encoding.is_null() {
2633 let enc_str = unsafe { std::ffi::CStr::from_ptr(encoding) };
2635 r.encoding = unsafe { bytes_to_xmlstr(enc_str.to_bytes()) };
2637 }
2638
2639 if !input.is_null() {
2641 let ctxt = unsafe { create_parser_ctxt() };
2643 if ctxt.is_null() {
2644 return -1;
2645 }
2646
2647 let mut data = Vec::new();
2649 let mut tmp = [0u8; 4096];
2650
2651 let read_cb = unsafe { (*input).readcallback };
2653 let ioctx = unsafe { (*input).context };
2654
2655 if let Some(read) = read_cb {
2656 loop {
2657 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2659 if n <= 0 {
2660 break;
2661 }
2662 data.extend_from_slice(&tmp[..n as usize]);
2663 }
2664 }
2665
2666 let close_cb = unsafe { (*input).closecallback };
2668 if let Some(close) = close_cb {
2669 unsafe { close(ioctx) };
2671 }
2672
2673 let input_buf = InputBuffer::from_memory(&data, None);
2674
2675 unsafe { setup_parser_input(ctxt, input_buf) };
2677 unsafe {
2678 (*ctxt).options = options;
2679 }
2680
2681 r.ctxt = ctxt;
2682 }
2683
2684 0
2685}
2686
2687#[no_mangle]
2701pub unsafe extern "C" fn xmlTextReaderCurrentDoc(reader: *mut XmlTextReader) -> *mut _xmlDoc {
2702 if reader.is_null() {
2703 return ptr::null_mut();
2704 }
2705 unsafe { (*reader).CurrentDoc() }
2707}
2708
2709#[cfg(test)]
2714mod tests {
2715 use super::*;
2716 use crate::abi::allocator::xmlFree;
2717 use core::ffi::c_void;
2718 use std::os::raw::c_char;
2719
2720 unsafe fn create_reader(xml: &str) -> *mut XmlTextReader {
2722 let bytes = xml.as_bytes();
2723 xmlReaderForMemory(
2724 bytes.as_ptr() as *const c_char,
2725 bytes.len() as c_int,
2726 ptr::null(),
2727 ptr::null(),
2728 0,
2729 )
2730 }
2731
2732 unsafe fn free_reader(reader: *mut XmlTextReader) {
2734 if !reader.is_null() {
2735 xmlFreeTextReader(reader);
2736 }
2737 }
2738
2739 unsafe fn collect_nodes(reader: *mut XmlTextReader) -> Vec<(ReaderNodeType, String, i32)> {
2741 let mut result = Vec::new();
2742 loop {
2743 let ret = xmlTextReaderRead(reader);
2744 if ret <= 0 {
2745 break;
2746 }
2747 let r = &*reader;
2749 let ntype = r.NodeType();
2750 let name = if r.name.is_null() {
2751 String::new()
2752 } else {
2753 xmlstr_to_string(r.name as *const xmlChar)
2754 };
2755 let depth = r.Depth();
2756 result.push((ntype, name, depth));
2757 }
2758 result
2759 }
2760
2761 #[test]
2764 fn test_create_reader_from_memory() {
2765 unsafe {
2766 let reader = create_reader("<root/>");
2767 assert!(!reader.is_null());
2768 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
2769 free_reader(reader);
2770 }
2771 }
2772
2773 #[test]
2774 fn test_read_simple_document() {
2775 unsafe {
2776 let reader = create_reader("<root><child>text</child></root>");
2777 assert!(!reader.is_null());
2778
2779 let nodes = collect_nodes(reader);
2780 assert_eq!(nodes.len(), 5);
2788 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
2789 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
2790 assert_eq!(nodes[2], (ReaderNodeType::TEXT, "".to_string(), 2));
2791 assert_eq!(
2792 nodes[3],
2793 (ReaderNodeType::END_ELEMENT, "child".to_string(), 1)
2794 );
2795 assert_eq!(
2796 nodes[4],
2797 (ReaderNodeType::END_ELEMENT, "root".to_string(), 0)
2798 );
2799
2800 assert_eq!((*reader).ReadState(), ReadState::EOF);
2801 free_reader(reader);
2802 }
2803 }
2804
2805 #[test]
2806 fn test_read_state_transitions() {
2807 unsafe {
2808 let reader = create_reader("<root/>");
2809 assert!(!reader.is_null());
2810 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
2811
2812 assert_eq!(xmlTextReaderRead(reader), 1);
2814 assert_eq!((*reader).ReadState(), ReadState::READING);
2815 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
2816 assert_eq!((*reader).Depth(), 0);
2817
2818 assert_eq!(xmlTextReaderRead(reader), 1);
2820 assert_eq!((*reader).NodeType(), ReaderNodeType::END_ELEMENT);
2821
2822 assert_eq!(xmlTextReaderRead(reader), 0);
2824 assert_eq!((*reader).ReadState(), ReadState::EOF);
2825
2826 free_reader(reader);
2827 }
2828 }
2829
2830 #[test]
2831 fn test_null_reader_returns_error() {
2832 unsafe {
2833 assert_eq!(xmlTextReaderRead(ptr::null_mut()), -1);
2834 assert_eq!(xmlTextReaderDepth(ptr::null_mut()), -1);
2835 assert_eq!(xmlTextReaderNodeType(ptr::null_mut()), -1);
2836 assert!(xmlTextReaderName(ptr::null_mut()).is_null());
2837 assert!(xmlTextReaderValue(ptr::null_mut()).is_null());
2838 assert_eq!(xmlTextReaderHasValue(ptr::null_mut()), 0);
2839 assert_eq!(xmlTextReaderIsEmptyElement(ptr::null_mut()), 0);
2840 assert_eq!(
2841 xmlTextReaderReadState(ptr::null_mut()),
2842 ReadState::ERROR as c_int
2843 );
2844 }
2845 }
2846
2847 #[test]
2848 fn test_xmlFreeTextReader_null() {
2849 unsafe {
2850 xmlFreeTextReader(ptr::null_mut());
2852 }
2853 }
2854
2855 #[test]
2856 fn test_reader_name_and_value() {
2857 unsafe {
2858 let reader = create_reader("<root>hello</root>");
2859 assert!(!reader.is_null());
2860
2861 assert_eq!(xmlTextReaderRead(reader), 1);
2863 let name = xmlTextReaderName(reader);
2864 assert!(!name.is_null());
2865 assert_eq!(xmlstr_to_string(name), "root");
2866 xmlFree(name as *mut c_void);
2867
2868 assert_eq!(xmlTextReaderHasValue(reader), 0);
2869
2870 assert_eq!(xmlTextReaderRead(reader), 1);
2872 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
2873 assert_eq!((*reader).HasValue(), 1);
2874
2875 let val = xmlTextReaderValue(reader);
2876 assert!(!val.is_null());
2877 assert_eq!(xmlstr_to_string(val), "hello");
2878 xmlFree(val as *mut c_void);
2879
2880 free_reader(reader);
2881 }
2882 }
2883
2884 #[test]
2885 fn test_empty_element() {
2886 unsafe {
2887 let reader = create_reader("<empty/>");
2888 assert!(!reader.is_null());
2889
2890 assert_eq!(xmlTextReaderRead(reader), 1);
2891 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
2892 assert_eq!((*reader).IsEmptyElement(), 1);
2893 assert_eq!((*reader).HasAttributes(), 0);
2894 assert_eq!((*reader).AttributeCount(), 0);
2895
2896 assert_eq!(xmlTextReaderRead(reader), 1);
2898 assert_eq!((*reader).NodeType(), ReaderNodeType::END_ELEMENT);
2899
2900 free_reader(reader);
2901 }
2902 }
2903
2904 #[test]
2905 fn test_element_with_attributes() {
2906 unsafe {
2907 let reader = create_reader(r#"<root a="1" b="2"/>"#);
2908 assert!(!reader.is_null());
2909
2910 assert_eq!(xmlTextReaderRead(reader), 1);
2911 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
2912 assert_eq!((*reader).HasAttributes(), 1);
2913
2914 let attrs = xmlTextReaderAttributeCount(reader);
2917 assert_eq!(attrs, 2);
2918
2919 free_reader(reader);
2920 }
2921 }
2922
2923 #[test]
2924 fn test_attribute_navigation() {
2925 unsafe {
2926 let reader = create_reader(r#"<root a="1" b="2"></root>"#);
2927 assert!(!reader.is_null());
2928
2929 assert_eq!(xmlTextReaderRead(reader), 1);
2931 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
2932
2933 assert_eq!(xmlTextReaderMoveToFirstAttribute(reader), 1);
2935 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
2936
2937 let name = xmlTextReaderConstName(reader);
2938 assert!(!name.is_null());
2939 assert_eq!(xmlstr_to_bytes(name), b"a");
2940
2941 let val = xmlTextReaderConstValue(reader);
2942 assert!(!val.is_null());
2943 assert_eq!(xmlstr_to_bytes(val), b"1");
2944
2945 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 1);
2947 let name = xmlTextReaderConstName(reader);
2948 assert!(!name.is_null());
2949 assert_eq!(xmlstr_to_bytes(name), b"b");
2950 let val = xmlTextReaderConstValue(reader);
2951 assert!(!val.is_null());
2952 assert_eq!(xmlstr_to_bytes(val), b"2");
2953
2954 assert_eq!(xmlTextReaderMoveToNextAttribute(reader), 0);
2956
2957 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
2959 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
2960
2961 assert_eq!(
2963 xmlTextReaderMoveToAttribute(reader, b"a\0" as *const u8 as *const xmlChar),
2964 1
2965 );
2966 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
2967
2968 assert_eq!(xmlTextReaderMoveToElement(reader), 1);
2970 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 1), 1);
2971 assert_eq!((*reader).NodeType(), ReaderNodeType::ATTRIBUTE);
2972
2973 free_reader(reader);
2974 }
2975 }
2976
2977 #[test]
2978 fn test_get_attribute() {
2979 unsafe {
2980 let reader = create_reader(r#"<root a="hello" b="world"/>"#);
2981 assert!(!reader.is_null());
2982
2983 assert_eq!(xmlTextReaderRead(reader), 1);
2984
2985 let val = xmlTextReaderGetAttribute(reader, b"a\0" as *const u8 as *const xmlChar);
2987 assert!(!val.is_null());
2988 assert_eq!(xmlstr_to_bytes(val), b"hello");
2989 xmlFree(val as *mut c_void);
2990
2991 let val = xmlTextReaderGetAttribute(reader, b"b\0" as *const u8 as *const xmlChar);
2992 assert!(!val.is_null());
2993 assert_eq!(xmlstr_to_bytes(val), b"world");
2994 xmlFree(val as *mut c_void);
2995
2996 let val = xmlTextReaderGetAttribute(reader, b"c\0" as *const u8 as *const xmlChar);
2998 assert!(val.is_null());
2999
3000 let val = xmlTextReaderGetAttributeNo(reader, 0);
3002 assert!(!val.is_null());
3003 assert_eq!(xmlstr_to_bytes(val), b"hello");
3004 xmlFree(val as *mut c_void);
3005
3006 let val = xmlTextReaderGetAttributeNo(reader, 1);
3007 assert!(!val.is_null());
3008 assert_eq!(xmlstr_to_bytes(val), b"world");
3009 xmlFree(val as *mut c_void);
3010
3011 let val = xmlTextReaderGetAttributeNo(reader, 2);
3012 assert!(val.is_null());
3013
3014 free_reader(reader);
3015 }
3016 }
3017
3018 #[test]
3019 fn test_depth_tracking() {
3020 unsafe {
3021 let reader = create_reader("<a><b><c/></b></a>");
3022 assert!(!reader.is_null());
3023
3024 let nodes = collect_nodes(reader);
3025 assert_eq!(nodes.len(), 6);
3028 assert_eq!(nodes[0].2, 0); assert_eq!(nodes[1].2, 1); assert_eq!(nodes[2].2, 2); assert_eq!(nodes[3].2, 2); assert_eq!(nodes[4].2, 1); assert_eq!(nodes[5].2, 0); free_reader(reader);
3036 }
3037 }
3038
3039 #[test]
3040 fn test_multiple_siblings() {
3041 unsafe {
3042 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3043 assert!(!reader.is_null());
3044
3045 let nodes = collect_nodes(reader);
3046 assert_eq!(nodes.len(), 11);
3051
3052 assert_eq!(nodes[1], (ReaderNodeType::ELEMENT, "a".to_string(), 1));
3054 assert_eq!(nodes[4], (ReaderNodeType::ELEMENT, "b".to_string(), 1));
3055 assert_eq!(nodes[7], (ReaderNodeType::ELEMENT, "c".to_string(), 1));
3056
3057 free_reader(reader);
3058 }
3059 }
3060
3061 #[test]
3062 fn test_next_skip_to_sibling() {
3063 unsafe {
3064 let reader = create_reader("<root><a>A</a><b>B</b><c>C</c></root>");
3065 assert!(!reader.is_null());
3066
3067 assert_eq!(xmlTextReaderRead(reader), 1);
3069 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3070
3071 assert_eq!(xmlTextReaderRead(reader), 1);
3073 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3074 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "a");
3075
3076 assert_eq!(xmlTextReaderRead(reader), 1);
3078 assert_eq!((*reader).NodeType(), ReaderNodeType::TEXT);
3079
3080 assert_eq!(xmlTextReaderNext(reader), 1);
3082 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3083 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "b");
3084
3085 assert_eq!(xmlTextReaderNext(reader), 1);
3087 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3088 assert_eq!(xmlstr_to_string((*reader).name as *const xmlChar), "c");
3089
3090 assert_eq!(xmlTextReaderNext(reader), 0);
3092
3093 free_reader(reader);
3094 }
3095 }
3096
3097 #[test]
3098 fn test_comment_and_pi_nodes() {
3099 unsafe {
3100 let xml = b"<?pi target?><root><!-- comment -->text</root>\0";
3101 let reader = xmlReaderForMemory(
3102 xml.as_ptr() as *const c_char,
3103 (xml.len() - 1) as c_int,
3104 ptr::null(),
3105 ptr::null(),
3106 0,
3107 );
3108 assert!(!reader.is_null());
3109
3110 let nodes = collect_nodes(reader);
3111 assert!(!nodes.is_empty(), "no nodes collected: {:?}", nodes);
3114
3115 assert_eq!(
3117 nodes[0].0,
3118 ReaderNodeType::PROCESSING_INSTRUCTION,
3119 "expected PI at nodes[0], got {:?} name={}",
3120 nodes[0].0,
3121 nodes[0].1
3122 );
3123 assert_eq!(
3124 nodes[0].0,
3125 ReaderNodeType::PROCESSING_INSTRUCTION,
3126 "expected PI at nodes[0], got {:?} name={}",
3127 nodes[0].0,
3128 nodes[0].1
3129 );
3130
3131 let root_idx = nodes
3133 .iter()
3134 .position(|(t, n, _)| *t == ReaderNodeType::ELEMENT && n == "root");
3135 assert!(
3136 root_idx.is_some(),
3137 "no ELEMENT root found in nodes: {:?}",
3138 nodes
3139 .iter()
3140 .map(|(t, n, _)| format!("{:?}:{}", t, n))
3141 .collect::<Vec<_>>()
3142 );
3143
3144 let comment_idx = nodes
3146 .iter()
3147 .position(|(t, _, _)| *t == ReaderNodeType::COMMENT);
3148 assert!(comment_idx.is_some(), "no COMMENT found");
3149
3150 let text_idx = nodes
3152 .iter()
3153 .position(|(t, _, _)| *t == ReaderNodeType::TEXT);
3154 assert!(text_idx.is_some(), "no TEXT found");
3155
3156 free_reader(reader);
3157 }
3158 }
3159
3160 #[test]
3161 fn test_local_name() {
3162 unsafe {
3163 let reader = create_reader("<root/>");
3165 assert!(!reader.is_null());
3166
3167 assert_eq!(xmlTextReaderRead(reader), 1);
3168 let local = xmlTextReaderLocalName(reader);
3169 assert!(!local.is_null());
3170 assert_eq!(xmlstr_to_bytes(local), b"root");
3171 xmlFree(local as *mut c_void);
3172
3173 free_reader(reader);
3174 }
3175 }
3176
3177 #[test]
3178 fn test_base_uri() {
3179 unsafe {
3180 let reader = create_reader("<root/>");
3181 assert!(!reader.is_null());
3182
3183 assert_eq!(xmlTextReaderRead(reader), 1);
3184 let uri = xmlTextReaderBaseUri(reader);
3186 assert!(uri.is_null());
3187
3188 free_reader(reader);
3189 }
3190 }
3191
3192 #[test]
3193 fn test_lookup_namespace() {
3194 unsafe {
3195 let reader = create_reader(r#"<root xmlns:ns="http://example.com"><ns:child/></root>"#);
3196 assert!(!reader.is_null());
3197
3198 assert_eq!(xmlTextReaderRead(reader), 1);
3200 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3201
3202 assert_eq!(xmlTextReaderRead(reader), 1);
3204
3205 let uri = xmlTextReaderLookupNamespace(reader, b"ns\0" as *const u8 as *const xmlChar);
3207 assert!(!uri.is_null());
3208 assert_eq!(xmlstr_to_bytes(uri), b"http://example.com");
3209 xmlFree(uri as *mut c_void);
3210
3211 let uri = xmlTextReaderLookupNamespace(reader, ptr::null());
3213 assert!(uri.is_null());
3214
3215 let uri = xmlTextReaderLookupNamespace(
3217 reader,
3218 b"nonexistent\0" as *const u8 as *const xmlChar,
3219 );
3220 assert!(uri.is_null());
3221
3222 free_reader(reader);
3223 }
3224 }
3225
3226 #[test]
3227 fn test_parser_properties() {
3228 unsafe {
3229 let reader = create_reader("<root/>");
3230 assert!(!reader.is_null());
3231
3232 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);
3240 assert_eq!(xmlTextReaderGetParserProp(reader, 1), 1);
3241
3242 assert_eq!(xmlTextReaderSetParserProp(reader, 4, 1), 0);
3243 assert_eq!(xmlTextReaderGetParserProp(reader, 4), 1);
3244
3245 assert_eq!(xmlTextReaderGetParserProp(reader, 99), -1);
3247 assert_eq!(xmlTextReaderSetParserProp(reader, 99, 1), -1);
3248
3249 free_reader(reader);
3250 }
3251 }
3252
3253 #[test]
3254 fn test_current_doc() {
3255 unsafe {
3256 let reader = create_reader("<root/>");
3257 assert!(!reader.is_null());
3258
3259 assert!((*reader).CurrentDoc().is_null());
3261
3262 assert_eq!(xmlTextReaderRead(reader), 1);
3264 let doc = xmlTextReaderCurrentDoc(reader);
3265 assert!(!doc.is_null());
3266
3267 free_reader(reader);
3268 }
3269 }
3270
3271 #[test]
3272 fn test_free_reader_after_read() {
3273 unsafe {
3274 let reader = create_reader("<root><child/></root>");
3275 assert!(!reader.is_null());
3276
3277 while xmlTextReaderRead(reader) > 0 {}
3279 assert_eq!((*reader).ReadState(), ReadState::EOF);
3280
3281 free_reader(reader);
3283 }
3284 }
3285
3286 #[test]
3287 fn test_reader_for_memory_null_buffer() {
3288 unsafe {
3289 let reader = xmlReaderForMemory(ptr::null(), 10, ptr::null(), ptr::null(), 0);
3290 assert!(reader.is_null());
3291 }
3292 }
3293
3294 #[test]
3295 fn test_reader_for_memory_empty_size() {
3296 unsafe {
3297 let data = b"<root/>";
3298 let reader = xmlReaderForMemory(
3299 data.as_ptr() as *const c_char,
3300 0,
3301 ptr::null(),
3302 ptr::null(),
3303 0,
3304 );
3305 assert!(reader.is_null());
3306 }
3307 }
3308
3309 #[test]
3310 fn test_reader_for_file_not_found() {
3311 unsafe {
3312 let filename = b"/nonexistent/file.xml\0" as *const u8 as *const c_char;
3313 let reader = xmlReaderForFile(filename, ptr::null(), 0);
3314 assert!(reader.is_null());
3315 }
3316 }
3317
3318 #[test]
3319 fn test_const_name_and_value() {
3320 unsafe {
3321 let reader = create_reader("<root>text</root>");
3322 assert!(!reader.is_null());
3323
3324 assert_eq!(xmlTextReaderRead(reader), 1);
3326 let cname = xmlTextReaderConstName(reader);
3327 assert!(!cname.is_null());
3328 assert_eq!(xmlstr_to_bytes(cname), b"root");
3329
3330 assert_eq!(xmlTextReaderRead(reader), 1);
3332 let cval = xmlTextReaderConstValue(reader);
3333 assert!(!cval.is_null());
3334 assert_eq!(xmlstr_to_bytes(cval), b"text");
3335
3336 free_reader(reader);
3337 }
3338 }
3339
3340 #[test]
3341 fn test_complex_nested_document() {
3342 unsafe {
3343 let xml = r#"<?xml version="1.0"?>
3344<library>
3345 <book id="1">
3346 <title>XML Fundamentals</title>
3347 <author>John Doe</author>
3348 </book>
3349 <book id="2">
3350 <title>XSLT Recipes</title>
3351 <author>Jane Smith</author>
3352 </book>
3353</library>"#;
3354
3355 let reader = create_reader(xml);
3356 assert!(!reader.is_null());
3357
3358 let mut element_count = 0;
3359 let mut end_element_count = 0;
3360 let mut text_count = 0;
3361 let mut pi_count = 0;
3362
3363 loop {
3364 let ret = xmlTextReaderRead(reader);
3365 if ret <= 0 {
3366 break;
3367 }
3368 match (*reader).NodeType() {
3369 ReaderNodeType::ELEMENT => element_count += 1,
3370 ReaderNodeType::END_ELEMENT => end_element_count += 1,
3371 ReaderNodeType::TEXT => text_count += 1,
3372 ReaderNodeType::PROCESSING_INSTRUCTION => pi_count += 1,
3373 _ => {}
3374 }
3375 }
3376
3377 assert_eq!(element_count, 7);
3379 assert_eq!(end_element_count, 7);
3381 assert_eq!(text_count, 4);
3383 assert_eq!(pi_count, 0);
3388
3389 free_reader(reader);
3390 }
3391 }
3392
3393 #[test]
3394 fn test_setup_reinitialize() {
3395 unsafe {
3396 let reader = create_reader("<root/>");
3397 assert!(!reader.is_null());
3398
3399 assert_eq!(xmlTextReaderRead(reader), 1);
3401 assert_eq!((*reader).ReadState(), ReadState::READING);
3402
3403 assert_eq!(
3407 xmlTextReaderSetup(reader, ptr::null_mut(), ptr::null(), ptr::null(), 0),
3408 0
3409 );
3410 assert_eq!((*reader).ReadState(), ReadState::INITIALIZED);
3411
3412 free_reader(reader);
3413 }
3414 }
3415
3416 #[test]
3417 fn test_has_attributes_on_non_element() {
3418 unsafe {
3419 let reader = create_reader("<root>text</root>");
3420 assert!(!reader.is_null());
3421
3422 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0); assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).HasAttributes(), 0);
3427
3428 free_reader(reader);
3429 }
3430 }
3431
3432 #[test]
3433 fn test_prev_sibling() {
3434 unsafe {
3435 let reader = create_reader("<root><a/><b/><c/></root>");
3436 assert!(!reader.is_null());
3437
3438 while xmlTextReaderRead(reader) > 0 {
3440 }
3442
3443 assert_eq!(xmlTextReaderPrev(reader), -1);
3445
3446 free_reader(reader);
3447 }
3448 }
3449
3450 #[test]
3451 fn test_move_to_attribute_no_not_on_element() {
3452 unsafe {
3453 let reader = create_reader("<root>text</root>");
3454 assert!(!reader.is_null());
3455
3456 assert_eq!(xmlTextReaderRead(reader), 1); assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3458
3459 assert_eq!(xmlTextReaderMoveToAttributeNo(reader, 0), 0);
3461
3462 free_reader(reader);
3463 }
3464 }
3465
3466 #[test]
3467 fn test_get_attribute_ns() {
3468 unsafe {
3469 let reader = create_reader(r#"<root a="1" b="2"/>"#);
3470 assert!(!reader.is_null());
3471
3472 assert_eq!(xmlTextReaderRead(reader), 1);
3473
3474 let val = xmlTextReaderGetAttributeNs(
3476 reader,
3477 b"a\0" as *const u8 as *const xmlChar,
3478 ptr::null(),
3479 );
3480 assert!(!val.is_null());
3481 assert_eq!(xmlstr_to_bytes(val), b"1");
3482 xmlFree(val as *mut c_void);
3483
3484 free_reader(reader);
3485 }
3486 }
3487
3488 #[test]
3489 fn test_mixed_content() {
3490 unsafe {
3491 let reader = create_reader("<root>before<child/>after</root>");
3492 assert!(!reader.is_null());
3493
3494 let nodes = collect_nodes(reader);
3495 assert_eq!(nodes.len(), 6);
3498 assert_eq!(nodes[0], (ReaderNodeType::ELEMENT, "root".to_string(), 0));
3499 assert_eq!(nodes[1].0, ReaderNodeType::TEXT);
3500 assert_eq!(nodes[2], (ReaderNodeType::ELEMENT, "child".to_string(), 1));
3501 assert_eq!(nodes[4].0, ReaderNodeType::TEXT);
3502
3503 free_reader(reader);
3504 }
3505 }
3506
3507 #[test]
3508 fn test_error_handling_invalid_xml() {
3509 unsafe {
3510 let data = b"<root><\0" as *const u8 as *const c_char;
3512 let reader = xmlReaderForMemory(data, 7, ptr::null(), ptr::null(), 0);
3513 assert!(!reader.is_null());
3514
3515 let ret = xmlTextReaderRead(reader);
3517 assert!(ret == -1 || ret == 0);
3518
3519 free_reader(reader);
3520 }
3521 }
3522
3523 #[test]
3524 fn test_reader_with_options() {
3525 unsafe {
3526 let data = b"<root/>\0" as *const u8 as *const c_char;
3527 let reader = xmlReaderForMemory(
3528 data,
3529 7,
3530 ptr::null(),
3531 ptr::null(),
3532 XML_PARSE_NOENT | XML_PARSE_DTDLOAD,
3533 );
3534 assert!(!reader.is_null());
3535
3536 assert_eq!((*reader).options & XML_PARSE_NOENT, XML_PARSE_NOENT);
3538 assert_eq!((*reader).options & XML_PARSE_DTDLOAD, XML_PARSE_DTDLOAD);
3539
3540 assert_eq!(xmlTextReaderRead(reader), 1);
3541 free_reader(reader);
3542 }
3543 }
3544
3545 #[test]
3546 fn test_reader_for_fd() {
3547 unsafe {
3548 let tmp_path = "/tmp/libxml_rs_test_reader_fd.xml";
3550 let tmp_cstr = std::ffi::CString::new(tmp_path).unwrap();
3551 let content = b"<root><data/></root>";
3552 let fd = libc::open(
3553 tmp_cstr.as_ptr(),
3554 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
3555 0o644,
3556 );
3557 assert!(fd >= 0);
3558 libc::write(fd, content.as_ptr() as *const c_void, content.len());
3559 libc::close(fd);
3560
3561 let fd = libc::open(tmp_cstr.as_ptr(), libc::O_RDONLY, 0);
3563 assert!(fd >= 0);
3564
3565 let reader = xmlReaderForFd(fd, ptr::null(), ptr::null(), 0);
3566 assert!(!reader.is_null());
3567
3568 let nodes = collect_nodes(reader);
3569 assert_eq!(nodes.len(), 4); free_reader(reader);
3572 libc::close(fd);
3573 std::fs::remove_file(tmp_path).ok();
3574 }
3575 }
3576
3577 #[test]
3578 fn test_reader_for_io() {
3579 unsafe {
3580 extern "C" fn io_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
3581 if context.is_null() || buffer.is_null() || len <= 0 {
3582 return -1;
3583 }
3584 let ctx = unsafe { &mut *(context as *mut IoCtx) };
3586 if ctx.pos >= ctx.data.len() {
3587 return 0;
3588 }
3589 let remaining = ctx.data.len() - ctx.pos;
3590 let to_copy = if (remaining as c_int) < len {
3591 remaining
3592 } else {
3593 len as usize
3594 };
3595 unsafe {
3597 std::ptr::copy_nonoverlapping(
3598 ctx.data.as_ptr().add(ctx.pos),
3599 buffer as *mut u8,
3600 to_copy,
3601 );
3602 }
3603 ctx.pos += to_copy;
3604 to_copy as c_int
3605 }
3606
3607 extern "C" fn io_close(_context: *mut c_void) -> c_int {
3608 0
3609 }
3610
3611 struct IoCtx {
3612 data: &'static [u8],
3613 pos: usize,
3614 }
3615 let mut ctx = IoCtx {
3616 data: b"<root/>",
3617 pos: 0,
3618 };
3619
3620 let reader = xmlReaderForIO(
3621 Some(io_read),
3622 Some(io_close),
3623 &mut ctx as *mut IoCtx as *mut c_void,
3624 ptr::null(),
3625 ptr::null(),
3626 0,
3627 );
3628 assert!(!reader.is_null());
3629
3630 assert_eq!(xmlTextReaderRead(reader), 1);
3632 assert_eq!((*reader).NodeType(), ReaderNodeType::ELEMENT);
3633 let cname = xmlTextReaderConstName(reader);
3634 assert!(!cname.is_null());
3635 assert_eq!(xmlstr_to_bytes(cname), b"root");
3636
3637 assert_eq!(xmlTextReaderRead(reader), 1);
3638 assert_eq!((*reader).NodeType(), ReaderNodeType::END_ELEMENT);
3639
3640 assert_eq!(xmlTextReaderRead(reader), 0); free_reader(reader);
3643 }
3644 }
3645}