1use core::ffi::c_void;
80use core::ptr;
81use std::os::raw::{c_char, c_int, c_uint};
82
83use crate::abi::allocator;
84use crate::abi::callbacks::xmlGenericErrorFunc;
85use crate::abi::structs::*;
86use crate::abi::types::xmlAttributeDefault::*;
87use crate::abi::types::xmlAttributeType::*;
88use crate::abi::types::xmlElementContentOccur::*;
89use crate::abi::types::xmlElementContentType::*;
90use crate::abi::types::xmlElementType::*;
91use crate::abi::types::xmlElementTypeVal::*;
92use crate::abi::types::xmlEntityType::*;
93use crate::abi::types::*;
94use crate::xml::dtd;
95use crate::xml::hash;
96use crate::xml::string;
97use crate::xml::tree;
98
99#[allow(dead_code)]
105const VALID_CTXT_DEPTH_MAX: c_int = 256;
106
107pub unsafe fn new_valid_ctxt() -> *mut _xmlValidCtxt {
131 let ctxt = allocator::xmlMallocZero(size_of::<_xmlValidCtxt>() as usize) as *mut _xmlValidCtxt;
133 if ctxt.is_null() {
134 return ptr::null_mut();
135 }
136
137 unsafe {
138 (*ctxt).valid = 1;
139 (*ctxt).node = ptr::null_mut();
140 (*ctxt).doc = ptr::null_mut();
141 (*ctxt).nodeNr = 0;
142 (*ctxt).nodeMax = 0;
143 (*ctxt).nodeTab = ptr::null_mut();
144 (*ctxt).flags = 0;
145 (*ctxt).vstate = ptr::null_mut();
146 (*ctxt).vstateNr = 0;
147 (*ctxt).vstateMax = 0;
148 (*ctxt).vstateTab = ptr::null_mut();
149 (*ctxt).am = ptr::null_mut();
150 (*ctxt).state = ptr::null_mut();
151 (*ctxt).error = None;
152 (*ctxt).warning = None;
153 (*ctxt).userData = ptr::null_mut();
154 }
155
156 ctxt
157}
158
159pub unsafe fn free_valid_ctxt(ctxt: *mut _xmlValidCtxt) {
171 if ctxt.is_null() {
172 return;
173 }
174
175 unsafe {
176 let c = &mut *ctxt;
177
178 if !c.nodeTab.is_null() {
180 allocator::xmlFreeImpl(c.nodeTab as *mut c_void);
181 }
182
183 if !c.am.is_null() {
185 }
188
189 if !c.state.is_null() {
191 }
193
194 allocator::xmlFreeImpl(ctxt as *mut c_void);
195 }
196}
197
198pub unsafe fn set_valid_errors(
214 ctxt: *mut _xmlValidCtxt,
215 err: Option<xmlGenericErrorFunc>,
216 warn: Option<xmlGenericErrorFunc>,
217 data: *mut c_void,
218) {
219 if ctxt.is_null() {
220 return;
221 }
222
223 unsafe {
224 (*ctxt).error = err;
227 (*ctxt).warning = warn;
228 (*ctxt).userData = data;
229 }
230}
231
232unsafe fn vctxt_error(ctxt: *mut _xmlValidCtxt, msg: *const c_char) {
243 if ctxt.is_null() {
244 return;
245 }
246 unsafe {
247 let c = &mut *ctxt;
248 c.valid = 0;
249 if let Some(err) = c.error {
250 err(c.userData, msg);
251 }
252 }
253}
254
255unsafe fn vctxt_push_node(ctxt: *mut _xmlValidCtxt, node: *mut _xmlNode) -> c_int {
263 unsafe {
264 let c = &mut *ctxt;
265
266 if c.nodeNr >= c.nodeMax {
267 let new_max = if c.nodeMax == 0 { 4 } else { c.nodeMax * 2 };
268 let new_tab = allocator::xmlReallocImpl(
269 c.nodeTab as *mut c_void,
270 (new_max as usize) * size_of::<*mut _xmlNode>(),
271 ) as *mut *mut _xmlNode;
272 if new_tab.is_null() {
273 return -1;
274 }
275 c.nodeTab = new_tab;
276 c.nodeMax = new_max;
277 }
278
279 *c.nodeTab.add(c.nodeNr as usize) = node;
280 c.nodeNr += 1;
281 c.node = node;
282 }
283 0
284}
285
286unsafe fn vctxt_pop_node(ctxt: *mut _xmlValidCtxt) {
292 unsafe {
293 let c = &mut *ctxt;
294 if c.nodeNr > 0 {
295 c.nodeNr -= 1;
296 }
297 if c.nodeNr > 0 {
298 c.node = *c.nodeTab.add((c.nodeNr - 1) as usize);
299 } else {
300 c.node = ptr::null_mut();
301 }
302 }
303}
304
305unsafe fn get_valid_dtd(doc: *mut _xmlDoc) -> *mut _xmlDtd {
313 if doc.is_null() {
314 return ptr::null_mut();
315 }
316 unsafe {
317 let d = &*doc;
318 if !d.intSubset.is_null() {
319 d.intSubset
320 } else {
321 d.extSubset
322 }
323 }
324}
325
326pub(crate) const fn is_xml_name_start(c: char) -> bool {
340 matches!(c,
341 'a'..='z' | 'A'..='Z' | '_' | ':' |
342 '\u{C0}'..='\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' |
343 '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' |
344 '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' |
345 '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' |
346 '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' |
347 '\u{10000}'..='\u{EFFFF}'
348 )
349}
350
351pub(crate) const fn is_xml_name_char(c: char) -> bool {
358 is_xml_name_start(c)
359 || matches!(c,
360 '-' | '.' | '0'..='9' | '\u{B7}' |
361 '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}'
362 )
363}
364
365pub unsafe fn validate_name(value: *const xmlChar) -> c_int {
383 if value.is_null() {
384 return 0;
385 }
386
387 let s = unsafe { string::xmlstr_to_bytes(value) };
388 let s = core::str::from_utf8(s).unwrap_or("");
389
390 if s.is_empty() {
391 return 0;
392 }
393
394 let mut chars = s.chars();
395
396 match chars.next() {
398 Some(c) if is_xml_name_start(c) => {}
399 _ => return 0,
400 }
401
402 for c in chars {
404 if !is_xml_name_char(c) {
405 return 0;
406 }
407 }
408
409 1
410}
411
412pub unsafe fn validate_names(value: *const xmlChar) -> c_int {
426 if value.is_null() {
427 return 0;
428 }
429
430 let s = unsafe { string::xmlstr_to_bytes(value) };
431 let s = core::str::from_utf8(s).unwrap_or("");
432
433 if s.is_empty() {
434 return 0;
435 }
436
437 for token in s.split_whitespace() {
438 if token.is_empty() {
439 return 0;
440 }
441 let mut chars = token.chars();
442 match chars.next() {
443 Some(c) if is_xml_name_start(c) => {}
444 _ => return 0,
445 }
446 for c in chars {
447 if !is_xml_name_char(c) {
448 return 0;
449 }
450 }
451 }
452
453 1
454}
455
456pub unsafe fn validate_nmtoken(value: *const xmlChar) -> c_int {
475 if value.is_null() {
476 return 0;
477 }
478
479 let s = unsafe { string::xmlstr_to_bytes(value) };
480 let s = core::str::from_utf8(s).unwrap_or("");
481
482 if s.is_empty() {
483 return 0;
484 }
485
486 for c in s.chars() {
487 if !is_xml_name_char(c) {
488 return 0;
489 }
490 }
491
492 1
493}
494
495pub unsafe fn validate_nmtokens(value: *const xmlChar) -> c_int {
509 if value.is_null() {
510 return 0;
511 }
512
513 let s = unsafe { string::xmlstr_to_bytes(value) };
514 let s = core::str::from_utf8(s).unwrap_or("");
515
516 if s.is_empty() {
517 return 0;
518 }
519
520 for token in s.split_whitespace() {
521 if token.is_empty() {
522 return 0;
523 }
524 for c in token.chars() {
525 if !is_xml_name_char(c) {
526 return 0;
527 }
528 }
529 }
530
531 1
532}
533
534pub unsafe fn validate_attribute_value(atype: c_int, value: *const xmlChar) -> c_int {
552 match atype as u32 {
556 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
557 validate_values_internal(value, 0)
558 }
559 t if t == XML_ATTRIBUTE_ENTITY as u32
560 || t == XML_ATTRIBUTE_IDREF as u32
561 || t == XML_ATTRIBUTE_ID as u32
562 || t == XML_ATTRIBUTE_NOTATION as u32 =>
563 {
564 validate_value_internal(value, 0)
565 }
566 t if t == XML_ATTRIBUTE_NMTOKENS as u32 || t == XML_ATTRIBUTE_ENUMERATION as u32 => {
567 validate_values_internal(value, XML_SCAN_NMTOKEN)
568 }
569 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => validate_value_internal(value, XML_SCAN_NMTOKEN),
570 _ => 1, }
572}
573
574pub unsafe fn validate_enumeration(
596 ctxt: *mut _xmlValidCtxt,
597 value: *const xmlChar,
598 tree: *mut _xmlEnumeration,
599) -> c_int {
600 if value.is_null() || tree.is_null() {
601 return 0;
602 }
603
604 let mut cur = tree;
605 while !cur.is_null() {
606 unsafe {
607 if string::xml_strcmp(value, (*cur).name) == 0 {
608 return 1;
609 }
610 cur = (*cur).next;
611 }
612 }
613
614 unsafe {
616 let msg = string::xmlstr_to_string(value);
617 let err_msg = format!("Value '{}' is not a valid enumeration value\0", msg);
618 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
619 }
620 0
621}
622
623pub unsafe fn validate_notation_use(
643 ctxt: *mut _xmlValidCtxt,
644 doc: *mut _xmlDoc,
645 notation_name: *const xmlChar,
646) -> c_int {
647 if notation_name.is_null() {
648 return 0;
649 }
650
651 let dtd = unsafe { get_valid_dtd(doc) };
652 if dtd.is_null() {
653 unsafe {
654 vctxt_error(
655 ctxt,
656 b"No DTD available for notation validation\0" as *const u8 as *const c_char,
657 );
658 }
659 return 0;
660 }
661
662 unsafe {
664 let notations = (*dtd).notations;
665 if notations.is_null() {
666 vctxt_error(
667 ctxt,
668 b"No notations declared in DTD\0" as *const u8 as *const c_char,
669 );
670 return 0;
671 }
672
673 let notation = hash::hash_lookup(notations as *mut hash::HashTable, notation_name);
674 if notation.is_null() {
675 let msg = string::xmlstr_to_string(notation_name);
676 let err_msg = format!("Notation '{}' is not declared\0", msg);
677 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
678 return 0;
679 }
680 }
681
682 1
683}
684
685pub unsafe fn validate_id(
707 ctxt: *mut _xmlValidCtxt,
708 doc: *mut _xmlDoc,
709 node: *mut _xmlNode,
710 value: *const xmlChar,
711) -> c_int {
712 if value.is_null() || doc.is_null() {
713 return 0;
714 }
715
716 if unsafe { validate_name_value(value) } == 0 {
719 unsafe {
720 let msg = string::xmlstr_to_string(value);
721 let err_msg = format!("ID value '{}' is not a valid XML Name\0", msg);
722 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
723 }
724 return 0;
725 }
726
727 unsafe {
729 let doc_ref = &*doc;
730 if !doc_ref.ids.is_null() {
731 let existing = hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value);
732 if !existing.is_null() {
733 let msg = string::xmlstr_to_string(value);
734 let err_msg = format!("Duplicate ID value '{}'\0", msg);
735 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
736 return 0;
737 }
738 }
739 }
740
741 unsafe {
743 if (*doc).ids.is_null() {
744 (*doc).ids = hash::hash_create(16) as *mut c_void;
745 }
746 hash::hash_add_entry(
747 (*doc).ids as *mut hash::HashTable,
748 value,
749 node as *mut c_void,
750 );
751 }
752
753 1
754}
755
756pub unsafe fn validate_id_ref(
773 ctxt: *mut _xmlValidCtxt,
774 doc: *mut _xmlDoc,
775 _node: *mut _xmlNode,
776 value: *const xmlChar,
777) -> c_int {
778 if value.is_null() || doc.is_null() {
779 return 0;
780 }
781
782 if unsafe { validate_name_value(value) } == 0 {
785 unsafe {
786 let msg = string::xmlstr_to_string(value);
787 let err_msg = format!("IDREF value '{}' is not a valid XML Name\0", msg);
788 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
789 }
790 return 0;
791 }
792
793 unsafe {
795 let doc_ref = &*doc;
796 if doc_ref.ids.is_null()
797 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value).is_null()
798 {
799 let msg = string::xmlstr_to_string(value);
803 let err_msg = format!("IDREF '{}' references an unknown ID\0", msg);
804 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
805 return 0;
806 }
807 }
808
809 1
810}
811
812pub unsafe fn validate_id_refs(
829 ctxt: *mut _xmlValidCtxt,
830 doc: *mut _xmlDoc,
831 node: *mut _xmlNode,
832 value: *const xmlChar,
833) -> c_int {
834 if value.is_null() || doc.is_null() {
835 return 0;
836 }
837
838 let s = unsafe { string::xmlstr_to_bytes(value) };
839 let s = core::str::from_utf8(s).unwrap_or("");
840
841 if s.is_empty() {
842 return 0;
843 }
844
845 let mut valid = 1;
846 for token in s.split_whitespace() {
847 if token.is_empty() {
848 continue;
849 }
850 let token_ptr = unsafe { string::bytes_to_xmlstr(token.as_bytes()) };
852 if token_ptr.is_null() {
853 valid = 0;
854 break;
855 }
856 let result = unsafe { validate_id_ref(ctxt, doc, node, token_ptr) };
857 unsafe {
858 allocator::xmlFreeImpl(token_ptr as *mut c_void);
859 }
860 if result == 0 {
861 valid = 0;
862 }
863 }
864
865 valid
866}
867
868pub unsafe fn validate_attribute_decl(
895 ctxt: *mut _xmlValidCtxt,
896 doc: *mut _xmlDoc,
897 _elem: *mut _xmlNode,
898 attr: *mut _xmlAttribute,
899) -> c_int {
900 if attr.is_null() {
901 return 0;
902 }
903
904 unsafe {
905 let a = &*attr;
906 let atype = a.atype as c_int;
907
908 if !a.defaultValue.is_null() && validate_attribute_value(atype, a.defaultValue) == 0 {
910 let name_str = string::xmlstr_to_string(a.name);
911 let val_str = string::xmlstr_to_string(a.defaultValue);
912 let err_msg = format!(
913 "Default value '{}' for attribute '{}' is not valid for its type\0",
914 val_str, name_str
915 );
916 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
917 return 0;
918 }
919
920 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !a.tree.is_null() {
922 let mut cur = a.tree;
924 while !cur.is_null() {
925 if !(*cur).name.is_null() && validate_nmtoken_value((*cur).name) == 0 {
926 let val_str = string::xmlstr_to_string((*cur).name);
927 let err_msg =
928 format!("Enumeration value '{}' is not a valid NMTOKEN\0", val_str);
929 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
930 return 0;
931 }
932 cur = (*cur).next;
933 }
934 }
935
936 if atype == XML_ATTRIBUTE_NOTATION as c_int && !a.tree.is_null() {
938 let mut cur = a.tree;
939 while !cur.is_null() {
940 if !(*cur).name.is_null() && validate_notation_use(ctxt, doc, (*cur).name) == 0 {
941 let val_str = string::xmlstr_to_string((*cur).name);
942 let err_msg = format!(
943 "NOTATION value '{}' references undeclared notation\0",
944 val_str
945 );
946 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
947 return 0;
948 }
949 cur = (*cur).next;
950 }
951 }
952
953 1
954 }
955}
956
957pub unsafe fn validate_element(
986 ctxt: *mut _xmlValidCtxt,
987 doc: *mut _xmlDoc,
988 elem: *mut _xmlNode,
989) -> c_int {
990 if elem.is_null() || doc.is_null() || ctxt.is_null() {
991 return 0;
992 }
993
994 unsafe {
995 let e = &*elem;
996
997 if e.type_ != XML_ELEMENT_NODE as c_int {
999 return 1;
1000 }
1001
1002 if vctxt_push_node(ctxt, elem) != 0 {
1004 return 0;
1005 }
1006
1007 let mut valid = 1;
1008
1009 let dtd = get_valid_dtd(doc);
1011 if dtd.is_null() {
1012 vctxt_pop_node(ctxt);
1015 return 1;
1016 }
1017
1018 let dtd_ref = &*dtd;
1019
1020 let elem_name = e.name;
1022 let elem_decl = if !dtd_ref.elements.is_null() {
1023 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, elem_name)
1024 } else {
1025 ptr::null_mut()
1026 };
1027
1028 if elem_decl.is_null() {
1029 let name_str = string::xmlstr_to_string(elem_name);
1030 let err_msg = format!("No declaration for element {}\0", name_str);
1031 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1032 vctxt_pop_node(ctxt);
1033 return 0;
1034 }
1035
1036 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1037
1038 let elem_type = elem_decl_ref.etype as u32;
1040
1041 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1042 let mut child = e.children;
1044 while !child.is_null() {
1045 let child_type = (*child).type_ as u32;
1046 if child_type != XML_TEXT_NODE as u32 && child_type != XML_CDATA_SECTION_NODE as u32
1047 {
1048 valid = 0;
1049 let name_str = string::xmlstr_to_string(elem_name);
1050 let err_msg = format!(
1051 "Element '{}' is declared EMPTY but has child elements\0",
1052 name_str
1053 );
1054 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1055 break;
1056 }
1057 child = (*child).next;
1058 }
1059 } else if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1060 } else if elem_type == XML_ELEMENT_TYPE_MIXED as u32 {
1062 let mut child = e.children;
1064 while !child.is_null() {
1065 let child_type = (*child).type_ as u32;
1066 if child_type == XML_ELEMENT_NODE as u32 {
1067 let child_name = (*child).name;
1069 let result = dtd::valid_content_model(elem_decl_ref.content, &[child_name]);
1070 if result != dtd::ContentModelResult::Valid {
1071 let cname_str = string::xmlstr_to_string(child_name);
1072 let ename_str = string::xmlstr_to_string(elem_name);
1073 let err_msg = format!(
1074 "Element '{}' is not allowed in mixed content of '{}'\0",
1075 cname_str, ename_str
1076 );
1077 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1078 valid = 0;
1079 }
1080 }
1081 child = (*child).next;
1082 }
1083 } else if elem_type == XML_ELEMENT_TYPE_ELEMENT as u32 {
1084 let mut child_names: Vec<*const xmlChar> = Vec::new();
1086 let mut child = e.children;
1087 while !child.is_null() {
1088 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1089 child_names.push((*child).name);
1090 }
1091 child = (*child).next;
1092 }
1093
1094 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1095 if result != dtd::ContentModelResult::Valid {
1096 let ename_str = string::xmlstr_to_string(elem_name);
1097 let err_msg = format!(
1098 "Content model validation failed for element '{}'\0",
1099 ename_str
1100 );
1101 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1102 valid = 0;
1103 }
1104 }
1105
1106 if !dtd_ref.attributes.is_null() {
1108 let mut attr_prop = e.properties;
1110 while !attr_prop.is_null() {
1111 let attr_ref = &*attr_prop;
1112 let attr_name = attr_ref.name;
1113
1114 let attr_decl = hash::hash_lookup3(
1117 dtd_ref.attributes as *mut hash::HashTable,
1118 attr_name,
1119 ptr::null(),
1120 elem_name,
1121 );
1122
1123 if attr_decl.is_null() {
1124 attr_prop = attr_ref.next;
1129 continue;
1130 }
1131
1132 let attr_decl_ref = &*(attr_decl as *mut _xmlAttribute);
1133 let atype = attr_decl_ref.atype as c_int;
1134
1135 let attr_value = if !attr_ref.children.is_null() {
1137 let text_node = attr_ref.children;
1139 if (*text_node).type_ == XML_TEXT_NODE as c_int
1140 || (*text_node).type_ == XML_CDATA_SECTION_NODE as c_int
1141 {
1142 (*text_node).content
1143 } else {
1144 ptr::null()
1145 }
1146 } else {
1147 ptr::null()
1148 };
1149
1150 if !attr_value.is_null() {
1152 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !attr_decl_ref.tree.is_null()
1153 {
1154 if validate_enumeration(ctxt, attr_value, attr_decl_ref.tree) == 0 {
1155 let aname_str = string::xmlstr_to_string(attr_name);
1156 let aval_str = string::xmlstr_to_string(attr_value);
1157 let err_msg = format!(
1158 "Attribute '{}' has value '{}' not in enumeration\0",
1159 aname_str, aval_str
1160 );
1161 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1162 valid = 0;
1163 }
1164 } else if atype == XML_ATTRIBUTE_NOTATION as c_int {
1165 if validate_notation_use(ctxt, doc, attr_value) == 0 {
1166 let aname_str = string::xmlstr_to_string(attr_name);
1167 let aval_str = string::xmlstr_to_string(attr_value);
1168 let err_msg = format!(
1169 "Attribute '{}' references undeclared notation '{}'\0",
1170 aname_str, aval_str
1171 );
1172 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1173 valid = 0;
1174 }
1175 } else if validate_attribute_value(atype, attr_value) == 0 {
1176 let aname_str = string::xmlstr_to_string(attr_name);
1177 let aval_str = string::xmlstr_to_string(attr_value);
1178 let err_msg = format!(
1179 "Attribute '{}' has invalid value '{}' for its type\0",
1180 aname_str, aval_str
1181 );
1182 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1183 valid = 0;
1184 }
1185
1186 if atype == XML_ATTRIBUTE_ID as c_int {
1188 if validate_id(ctxt, doc, elem, attr_value) == 0 {
1189 valid = 0;
1190 }
1191 } else if atype == XML_ATTRIBUTE_IDREF as c_int {
1192 if validate_id_ref(ctxt, doc, elem, attr_value) == 0 {
1193 valid = 0;
1194 }
1195 } else if atype == XML_ATTRIBUTE_IDREFS as c_int
1196 && validate_id_refs(ctxt, doc, elem, attr_value) == 0
1197 {
1198 valid = 0;
1199 }
1200 }
1201
1202 attr_prop = attr_ref.next;
1203 }
1204
1205 struct RequiredAttrCheck {
1207 ctxt: *mut _xmlValidCtxt,
1208 elem_name: *const xmlChar,
1209 elem_props: *mut _xmlAttr,
1210 valid: *mut c_int,
1211 }
1212
1213 extern "C" fn check_required_attr(
1214 payload: *mut c_void,
1215 data: *mut c_void,
1216 name: *const xmlChar,
1217 name2: *const xmlChar,
1218 _name3: *const xmlChar,
1219 ) {
1220 if payload.is_null() || data.is_null() || name2.is_null() {
1221 return;
1222 }
1223
1224 let check = unsafe { &*(data as *mut RequiredAttrCheck) };
1226 unsafe {
1227 if string::xml_strcmp(name, check.elem_name) != 0 {
1229 return;
1230 }
1231
1232 let attr_decl = &*(payload as *mut _xmlAttribute);
1233
1234 if attr_decl.def == XML_ATTRIBUTE_REQUIRED as c_int {
1236 let mut found = 0;
1238 let mut prop = check.elem_props;
1239 while !prop.is_null() {
1240 if string::xml_strcmp((*prop).name, name2) == 0 {
1241 found = 1;
1242 break;
1243 }
1244 prop = (*prop).next;
1245 }
1246
1247 if found == 0 {
1248 let aname_str = string::xmlstr_to_string(name2);
1249 let ename_str = string::xmlstr_to_string(check.elem_name);
1250 let err_msg = format!(
1251 "Required attribute '{}' missing on element '{}'\0",
1252 aname_str, ename_str
1253 );
1254 vctxt_error(check.ctxt, err_msg.as_ptr() as *const c_char);
1255 *(check.valid) = 0;
1256 }
1257 }
1258 }
1259 }
1260
1261 let mut required_valid = valid;
1262 let check = RequiredAttrCheck {
1263 ctxt,
1264 elem_name,
1265 elem_props: e.properties,
1266 valid: &mut required_valid,
1267 };
1268
1269 hash::hash_scan_full(
1270 dtd_ref.attributes as *mut hash::HashTable,
1271 Some(check_required_attr),
1272 &check as *const RequiredAttrCheck as *mut c_void,
1273 );
1274
1275 valid = required_valid;
1276 }
1277
1278 let mut child = e.children;
1280 while !child.is_null() {
1281 if (*child).type_ == XML_ELEMENT_NODE as c_int
1282 && validate_element(ctxt, doc, child) == 0
1283 {
1284 valid = 0;
1285 }
1286 child = (*child).next;
1287 }
1288
1289 vctxt_pop_node(ctxt);
1290 valid
1291 }
1292}
1293
1294pub unsafe fn validate_document(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1314 if ctxt.is_null() || doc.is_null() {
1315 return 0;
1316 }
1317
1318 unsafe {
1319 let c = &mut *ctxt;
1320 c.doc = doc;
1321 c.valid = 1;
1322
1323 let d = &*doc;
1324
1325 if d.intSubset.is_null() && d.extSubset.is_null() {
1335 vctxt_error(ctxt, b"no DTD found!\0" as *const u8 as *const c_char);
1336 return 0;
1337 }
1338
1339 let mut root = d.children;
1341 while !root.is_null() {
1342 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1343 break;
1344 }
1345 root = (*root).next;
1346 }
1347
1348 if root.is_null() {
1349 vctxt_error(
1350 ctxt,
1351 b"No root element found in document\0" as *const u8 as *const c_char,
1352 );
1353 return 0;
1354 }
1355
1356 if validate_element(ctxt, doc, root) == 0 {
1358 return 0;
1359 }
1360
1361 c.valid
1362 }
1363}
1364
1365pub unsafe fn validate_document_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1387 if ctxt.is_null() || doc.is_null() {
1388 return 0;
1389 }
1390
1391 unsafe {
1392 let c = &mut *ctxt;
1393 c.doc = doc;
1394
1395 let d = &*doc;
1396
1397 if d.refs.is_null() {
1399 return c.valid;
1400 }
1401
1402 struct IdRefCheckContext {
1404 ctxt: *mut _xmlValidCtxt,
1405 doc: *mut _xmlDoc,
1406 }
1407
1408 extern "C" fn check_idref(
1409 _payload: *mut c_void,
1410 data: *mut c_void,
1411 _name: *const xmlChar,
1412 name2: *const xmlChar,
1413 _name3: *const xmlChar,
1414 ) {
1415 if data.is_null() || name2.is_null() {
1416 return;
1417 }
1418
1419 let cx = unsafe { &*(data as *mut IdRefCheckContext) };
1421 unsafe {
1422 let doc_ref = &*cx.doc;
1423
1424 if doc_ref.ids.is_null()
1426 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, name2).is_null()
1427 {
1428 let ref_str = string::xmlstr_to_string(name2);
1429 let err_msg = format!("IDREF '{}' does not reference a declared ID\0", ref_str);
1430 vctxt_error(cx.ctxt, err_msg.as_ptr() as *const c_char);
1431 }
1432 }
1433 }
1434
1435 let ctx = IdRefCheckContext { ctxt, doc };
1436 hash::hash_scan_full(
1437 d.refs as *mut hash::HashTable,
1438 Some(check_idref),
1439 &ctx as *const IdRefCheckContext as *mut c_void,
1440 );
1441
1442 c.valid
1443 }
1444}
1445
1446pub unsafe fn validate_root(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1464 if ctxt.is_null() || doc.is_null() {
1465 return 0;
1466 }
1467
1468 unsafe {
1469 let c = &mut *ctxt;
1470 c.doc = doc;
1471 c.valid = 1;
1472
1473 let d = &*doc;
1474
1475 let mut root = d.children;
1477 while !root.is_null() {
1478 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1479 break;
1480 }
1481 root = (*root).next;
1482 }
1483
1484 if root.is_null() {
1485 vctxt_error(
1486 ctxt,
1487 b"No root element found\0" as *const u8 as *const c_char,
1488 );
1489 return 0;
1490 }
1491
1492 let dtd = get_valid_dtd(doc);
1494 if dtd.is_null() {
1495 return 1;
1497 }
1498
1499 let dtd_ref = &*dtd;
1502 if !dtd_ref.name.is_null() && string::xml_strcmp((*root).name, dtd_ref.name) != 0 {
1503 let root_str = string::xmlstr_to_string((*root).name);
1504 let dtd_str = string::xmlstr_to_string(dtd_ref.name);
1505 let err_msg = format!(
1506 "Root element '{}' does not match DTD root '{}'\0",
1507 root_str, dtd_str
1508 );
1509 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1510 return 0;
1511 }
1512
1513 c.valid
1514 }
1515}
1516
1517pub unsafe fn validate_content(
1537 ctxt: *mut _xmlValidCtxt,
1538 node: *mut _xmlNode,
1539 doc: *mut _xmlDoc,
1540) -> c_int {
1541 if node.is_null() || doc.is_null() || ctxt.is_null() {
1542 return 0;
1543 }
1544
1545 unsafe {
1546 let n = &*node;
1547 if n.type_ != XML_ELEMENT_NODE as c_int {
1548 return 1;
1549 }
1550
1551 let dtd = get_valid_dtd(doc);
1552 if dtd.is_null() {
1553 return 1;
1554 }
1555
1556 let dtd_ref = &*dtd;
1557 if dtd_ref.elements.is_null() {
1558 return 1;
1559 }
1560
1561 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, n.name);
1562 if elem_decl.is_null() {
1563 return 1;
1564 }
1565
1566 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1567 if elem_decl_ref.content.is_null() {
1568 return 1;
1569 }
1570
1571 let elem_type = elem_decl_ref.etype as u32;
1572 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1573 let mut child = n.children;
1575 while !child.is_null() {
1576 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1577 let name_str = string::xmlstr_to_string(n.name);
1578 let err_msg =
1579 format!("Element '{}' is EMPTY but has child elements\0", name_str);
1580 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1581 return 0;
1582 }
1583 child = (*child).next;
1584 }
1585 return 1;
1586 }
1587
1588 if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1589 return 1;
1590 }
1591
1592 let mut child_names: Vec<*const xmlChar> = Vec::new();
1594 let mut child = n.children;
1595 while !child.is_null() {
1596 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1597 child_names.push((*child).name);
1598 }
1599 child = (*child).next;
1600 }
1601
1602 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1603 if result != dtd::ContentModelResult::Valid {
1604 let name_str = string::xmlstr_to_string(n.name);
1605 let err_msg = format!(
1606 "Content model validation failed for element '{}'\0",
1607 name_str
1608 );
1609 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1610 0
1611 } else {
1612 1
1613 }
1614 }
1615}
1616
1617pub unsafe fn is_mixed_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1635 if doc.is_null() || name.is_null() {
1636 return 0;
1637 }
1638
1639 let dtd = unsafe { get_valid_dtd(doc) };
1640 if dtd.is_null() {
1641 return 0;
1642 }
1643
1644 unsafe {
1645 let dtd_ref = &*dtd;
1646 if dtd_ref.elements.is_null() {
1647 return 0;
1648 }
1649
1650 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1651 if elem_decl.is_null() {
1652 return 0;
1653 }
1654
1655 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1656 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_MIXED as u32) as c_int
1657 }
1658}
1659
1660pub unsafe fn is_empty_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1674 if doc.is_null() || name.is_null() {
1675 return 0;
1676 }
1677
1678 let dtd = unsafe { get_valid_dtd(doc) };
1679 if dtd.is_null() {
1680 return 0;
1681 }
1682
1683 unsafe {
1684 let dtd_ref = &*dtd;
1685 if dtd_ref.elements.is_null() {
1686 return 0;
1687 }
1688
1689 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1690 if elem_decl.is_null() {
1691 return 0;
1692 }
1693
1694 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1695 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_EMPTY as u32) as c_int
1696 }
1697}
1698
1699pub unsafe fn validate_dtd(
1723 ctxt: *mut _xmlValidCtxt,
1724 doc: *mut _xmlDoc,
1725 dtd: *mut _xmlDtd,
1726) -> c_int {
1727 if ctxt.is_null() || dtd.is_null() {
1728 return 0;
1729 }
1730
1731 let c = unsafe { &mut *ctxt };
1732 c.doc = doc;
1733 c.valid = 1;
1734
1735 struct ValidateDtdCtx {
1736 ctxt: *mut _xmlValidCtxt,
1737 doc: *mut _xmlDoc,
1738 }
1739
1740 extern "C" fn validate_attr_decl_cb(
1741 payload: *mut c_void,
1742 data: *mut c_void,
1743 _name: *const xmlChar,
1744 _name2: *const xmlChar,
1745 _name3: *const xmlChar,
1746 ) {
1747 if payload.is_null() || data.is_null() {
1748 return;
1749 }
1750
1751 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1753 unsafe {
1754 let attr = payload as *mut _xmlAttribute;
1755 validate_attribute_decl(ctx.ctxt, ctx.doc, ptr::null_mut(), attr);
1756 }
1757 }
1758
1759 extern "C" fn validate_elem_content_cb(
1760 payload: *mut c_void,
1761 data: *mut c_void,
1762 _name: *const xmlChar,
1763 _name2: *const xmlChar,
1764 _name3: *const xmlChar,
1765 ) {
1766 if payload.is_null() || data.is_null() {
1767 return;
1768 }
1769
1770 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1772 unsafe {
1773 let elem = &*(payload as *mut _xmlElement);
1774 if !elem.content.is_null() {
1775 validate_content_model_refs(ctx.ctxt, ctx.doc, elem.content);
1776 }
1777 }
1778 }
1779
1780 unsafe {
1781 let dtd_ref = &*dtd;
1782
1783 if !dtd_ref.attributes.is_null() {
1785 let ctx = ValidateDtdCtx { ctxt, doc };
1786 hash::hash_scan_full(
1787 dtd_ref.attributes as *mut hash::HashTable,
1788 Some(validate_attr_decl_cb),
1789 &ctx as *const ValidateDtdCtx as *mut c_void,
1790 );
1791 }
1792
1793 if !dtd_ref.elements.is_null() {
1795 let ctx = ValidateDtdCtx { ctxt, doc };
1796 hash::hash_scan_full(
1797 dtd_ref.elements as *mut hash::HashTable,
1798 Some(validate_elem_content_cb),
1799 &ctx as *const ValidateDtdCtx as *mut c_void,
1800 );
1801 }
1802
1803 c.valid
1804 }
1805}
1806
1807unsafe fn validate_content_model_refs(
1814 ctxt: *mut _xmlValidCtxt,
1815 doc: *mut _xmlDoc,
1816 content: *mut _xmlElementContent,
1817) {
1818 if content.is_null() {
1819 return;
1820 }
1821
1822 unsafe {
1823 let c = &*content;
1824
1825 match c.type_ as u32 {
1826 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
1827 if !c.name.is_null() {
1829 let dtd = get_valid_dtd(doc);
1830 if !dtd.is_null() {
1831 let dtd_ref = &*dtd;
1832 if !dtd_ref.elements.is_null() {
1833 let decl =
1834 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, c.name);
1835 if decl.is_null() {
1836 let name_str = string::xmlstr_to_string(c.name);
1837 let err_msg = format!(
1838 "Element '{}' referenced in content model is not declared\0",
1839 name_str
1840 );
1841 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1842 }
1843 }
1844 }
1845 }
1846 }
1847 t if t == XML_ELEMENT_CONTENT_SEQ as u32 || t == XML_ELEMENT_CONTENT_OR as u32 => {
1848 validate_content_model_refs(ctxt, doc, c.c1);
1849 validate_content_model_refs(ctxt, doc, c.c2);
1850 }
1851 _ => {}
1852 }
1853 }
1854}
1855
1856pub unsafe fn validate_dtd_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1877 unsafe { validate_document_final(ctxt, doc) }
1878}
1879
1880const XML_SCAN_NC: u32 = 1; const XML_SCAN_NMTOKEN: u32 = 2; const fn is_blank_byte(b: u8) -> bool {
1908 b == b' ' || b == b'\t' || b == b'\n' || b == b'\r'
1909}
1910
1911const fn utf8_char_len(lead: u8) -> usize {
1913 if lead < 0x80 {
1914 1
1915 } else if lead >= 0xC0 && lead <= 0xDF {
1916 2
1917 } else if lead >= 0xE0 && lead <= 0xEF {
1918 3
1919 } else if lead >= 0xF0 && lead <= 0xF7 {
1920 4
1921 } else {
1922 0
1923 }
1924}
1925
1926unsafe fn scan_name_offsets(bytes: &[u8], start: usize, flags: u32) -> usize {
1939 let stop = if flags & XML_SCAN_NC != 0 {
1940 Some(b':')
1941 } else {
1942 None
1943 };
1944 let mut i = start;
1945 let mut is_nmtoken = flags & XML_SCAN_NMTOKEN != 0;
1946 while i < bytes.len() {
1947 let b = bytes[i];
1948 if b < 0x80 {
1949 if stop == Some(b) {
1950 break;
1951 }
1952 let c = b as char;
1953 let ok = if is_nmtoken {
1954 is_xml_name_char(c)
1955 } else {
1956 is_xml_name_start(c)
1957 };
1958 if !ok {
1959 break;
1960 }
1961 i += 1;
1962 } else {
1963 let len = utf8_char_len(b);
1964 if len == 0 || i + len > bytes.len() {
1965 break;
1966 }
1967 let ch = match core::str::from_utf8(&bytes[i..i + len])
1968 .ok()
1969 .and_then(|s| s.chars().next())
1970 {
1971 Some(c) => c,
1972 None => break,
1973 };
1974 let ok = if is_nmtoken {
1975 is_xml_name_char(ch)
1976 } else {
1977 is_xml_name_start(ch)
1978 };
1979 if !ok {
1980 break;
1981 }
1982 i += len;
1983 }
1984 is_nmtoken = true;
1986 }
1987 i
1988}
1989
1990pub unsafe fn validate_ncname(value: *const xmlChar, space: c_int) -> c_int {
1996 if value.is_null() {
1997 return -1;
1998 }
1999 let bytes = string::xmlstr_to_bytes(value);
2000 let mut start = 0usize;
2001 if space != 0 {
2002 while start < bytes.len() && is_blank_byte(bytes[start]) {
2003 start += 1;
2004 }
2005 }
2006 let end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2007 if end == start {
2008 return 1;
2009 }
2010 let mut end2 = end;
2011 if space != 0 {
2012 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2013 end2 += 1;
2014 }
2015 }
2016 if end2 == bytes.len() {
2017 0
2018 } else {
2019 1
2020 }
2021}
2022
2023pub unsafe fn validate_qname(value: *const xmlChar, space: c_int) -> c_int {
2029 if value.is_null() {
2030 return -1;
2031 }
2032 let bytes = string::xmlstr_to_bytes(value);
2033 let mut start = 0usize;
2034 if space != 0 {
2035 while start < bytes.len() && is_blank_byte(bytes[start]) {
2036 start += 1;
2037 }
2038 }
2039 let mut end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2040 if end == start {
2041 return 1;
2042 }
2043 if end < bytes.len() && bytes[end] == b':' {
2044 end += 1;
2045 let end2 = scan_name_offsets(bytes, end, XML_SCAN_NC);
2046 if end2 == end {
2047 return 1;
2048 }
2049 end = end2;
2050 }
2051 if space != 0 {
2052 while end < bytes.len() && is_blank_byte(bytes[end]) {
2053 end += 1;
2054 }
2055 }
2056 if end == bytes.len() {
2057 0
2058 } else {
2059 1
2060 }
2061}
2062
2063pub unsafe fn validate_name_space(value: *const xmlChar, space: c_int) -> c_int {
2074 if value.is_null() {
2075 return -1;
2076 }
2077 let bytes = string::xmlstr_to_bytes(value);
2078 let mut start = 0usize;
2079 if space != 0 {
2080 while start < bytes.len() && is_blank_byte(bytes[start]) {
2081 start += 1;
2082 }
2083 }
2084 let end = scan_name_offsets(bytes, start, 0);
2085 if end == start {
2086 return 1;
2087 }
2088 let mut end2 = end;
2089 if space != 0 {
2090 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2091 end2 += 1;
2092 }
2093 }
2094 if end2 == bytes.len() {
2095 0
2096 } else {
2097 1
2098 }
2099}
2100
2101pub unsafe fn validate_nmtoken_space(value: *const xmlChar, space: c_int) -> c_int {
2107 if value.is_null() {
2108 return -1;
2109 }
2110 let bytes = string::xmlstr_to_bytes(value);
2111 let mut start = 0usize;
2112 if space != 0 {
2113 while start < bytes.len() && is_blank_byte(bytes[start]) {
2114 start += 1;
2115 }
2116 }
2117 let end = scan_name_offsets(bytes, start, XML_SCAN_NMTOKEN);
2118 if end == start {
2119 return 1;
2120 }
2121 let mut end2 = end;
2122 if space != 0 {
2123 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2124 end2 += 1;
2125 }
2126 }
2127 if end2 == bytes.len() {
2128 0
2129 } else {
2130 1
2131 }
2132}
2133
2134unsafe fn validate_value_internal(value: *const xmlChar, flags: u32) -> c_int {
2137 if value.is_null() {
2138 return 0;
2139 }
2140 let bytes = string::xmlstr_to_bytes(value);
2141 if bytes.is_empty() {
2142 return 0;
2143 }
2144 let end = scan_name_offsets(bytes, 0, flags);
2145 if end == 0 {
2146 return 0;
2147 }
2148 if end == bytes.len() {
2149 1
2150 } else {
2151 0
2152 }
2153}
2154
2155unsafe fn validate_values_internal(value: *const xmlChar, flags: u32) -> c_int {
2158 if value.is_null() {
2159 return 0;
2160 }
2161 let bytes = string::xmlstr_to_bytes(value);
2162 let mut cur = scan_name_offsets(bytes, 0, flags);
2163 if cur == 0 {
2164 return 0;
2165 }
2166 while cur < bytes.len() && bytes[cur] == b' ' {
2167 while cur < bytes.len() && bytes[cur] == b' ' {
2168 cur += 1;
2169 }
2170 let end = scan_name_offsets(bytes, cur, flags);
2171 if end == cur {
2172 return 0;
2173 }
2174 cur = end;
2175 }
2176 if cur == bytes.len() {
2177 1
2178 } else {
2179 0
2180 }
2181}
2182
2183pub unsafe fn validate_name_value(value: *const xmlChar) -> c_int {
2189 validate_value_internal(value, 0)
2190}
2191
2192pub unsafe fn validate_names_value(value: *const xmlChar) -> c_int {
2198 validate_values_internal(value, 0)
2199}
2200
2201pub unsafe fn validate_nmtoken_value(value: *const xmlChar) -> c_int {
2207 validate_value_internal(value, XML_SCAN_NMTOKEN)
2208}
2209
2210pub unsafe fn validate_nmtokens_value(value: *const xmlChar) -> c_int {
2216 validate_values_internal(value, XML_SCAN_NMTOKEN)
2217}
2218
2219pub unsafe fn get_dtd_qelement_desc(
2230 dtd: *mut _xmlDtd,
2231 name: *const xmlChar,
2232 prefix: *const xmlChar,
2233) -> *mut _xmlElement {
2234 if dtd.is_null() {
2235 return ptr::null_mut();
2236 }
2237 unsafe {
2238 let elements = (*dtd).elements;
2239 if elements.is_null() {
2240 return ptr::null_mut();
2241 }
2242 hash::hash_lookup2(elements as *mut hash::HashTable, name, prefix) as *mut _xmlElement
2243 }
2244}
2245
2246pub unsafe fn get_dtd_qattr_desc(
2254 dtd: *mut _xmlDtd,
2255 elem: *const xmlChar,
2256 name: *const xmlChar,
2257 prefix: *const xmlChar,
2258) -> *mut _xmlAttribute {
2259 if dtd.is_null() || elem.is_null() || name.is_null() {
2260 return ptr::null_mut();
2261 }
2262 unsafe {
2263 let attrs = (*dtd).attributes;
2264 if attrs.is_null() {
2265 return ptr::null_mut();
2266 }
2267 hash::hash_lookup3(attrs as *mut hash::HashTable, name, prefix, elem) as *mut _xmlAttribute
2268 }
2269}
2270
2271pub unsafe fn get_dtd_notation_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlNotation {
2277 if dtd.is_null() || name.is_null() {
2278 return ptr::null_mut();
2279 }
2280 unsafe {
2281 let notations = (*dtd).notations;
2282 if notations.is_null() {
2283 return ptr::null_mut();
2284 }
2285 hash::hash_lookup(notations as *mut hash::HashTable, name) as *mut _xmlNotation
2286 }
2287}
2288
2289unsafe fn split_qname4(name: *const xmlChar, prefix: *mut *mut xmlChar) -> *const xmlChar {
2298 if prefix.is_null() {
2299 return name;
2300 }
2301 unsafe {
2302 *prefix = ptr::null_mut();
2303 if name.is_null() {
2304 return ptr::null();
2305 }
2306 let bytes = string::xmlstr_to_bytes(name);
2307 match bytes.iter().position(|&b| b == b':') {
2308 None => name,
2309 Some(pos) => {
2310 let p = string::bytes_to_xmlstr(&bytes[..pos]);
2311 *prefix = p;
2312 name.add(pos + 1)
2313 }
2314 }
2315 }
2316}
2317
2318unsafe fn free_id(id: *mut _xmlID) {
2325 if id.is_null() {
2326 return;
2327 }
2328 unsafe {
2329 if !(*id).value.is_null() {
2330 allocator::xmlFreeImpl((*id).value as *mut c_void);
2331 }
2332 if !(*id).name.is_null() {
2333 allocator::xmlFreeImpl((*id).name as *mut c_void);
2334 }
2335 if !(*id).attr.is_null() {
2336 (*(*id).attr).id = ptr::null_mut();
2337 (*(*id).attr).atype = 0;
2338 }
2339 allocator::xmlFreeImpl(id as *mut c_void);
2340 }
2341}
2342
2343unsafe extern "C" fn free_id_entry(payload: *mut c_void, _name: *mut xmlChar) {
2346 free_id(payload as *mut _xmlID);
2347}
2348
2349unsafe fn add_id_internal(
2352 attr: *mut _xmlAttr,
2353 value: *const xmlChar,
2354 id_ptr: *mut *mut _xmlID,
2355) -> c_int {
2356 unsafe {
2357 if !id_ptr.is_null() {
2358 *id_ptr = ptr::null_mut();
2359 }
2360 if value.is_null() || *value == 0 {
2361 return 0;
2362 }
2363 if attr.is_null() {
2364 return 0;
2365 }
2366 let doc = (*attr).doc;
2367 if doc.is_null() {
2368 return 0;
2369 }
2370
2371 let mut table = (*doc).ids as *mut hash::HashTable;
2372 if table.is_null() {
2373 (*doc).ids = hash::hash_create(0) as *mut c_void;
2374 table = (*doc).ids as *mut hash::HashTable;
2375 if table.is_null() {
2376 return -1;
2377 }
2378 } else if !hash::hash_lookup(table, value).is_null() {
2379 return 0;
2380 }
2381
2382 let id = allocator::xmlMallocZero(size_of::<_xmlID>() as usize) as *mut _xmlID;
2383 if id.is_null() {
2384 return -1;
2385 }
2386 (*id).doc = doc;
2387 (*id).value = string::xml_strdup(value);
2388 if (*id).value.is_null() {
2389 free_id(id);
2390 return -1;
2391 }
2392 if !(*attr).id.is_null() {
2394 remove_id(doc, attr);
2395 }
2396 if hash::hash_add_entry(table, value, id as *mut c_void) != 0 {
2397 free_id(id);
2398 return -1;
2399 }
2400 if !id_ptr.is_null() {
2401 *id_ptr = id;
2402 }
2403 (*id).attr = attr;
2404 (*id).lineno = tree::get_line_no((*attr).parent) as c_int;
2405 (*attr).atype = XML_ATTRIBUTE_ID as c_int;
2406 (*attr).id = id as *mut c_void;
2407 1
2408 }
2409}
2410
2411pub unsafe fn add_id(
2419 ctxt: *mut _xmlValidCtxt,
2420 doc: *mut _xmlDoc,
2421 value: *const xmlChar,
2422 attr: *mut _xmlAttr,
2423) -> *mut _xmlID {
2424 unsafe {
2425 if attr.is_null() || doc != (*attr).doc {
2426 return ptr::null_mut();
2427 }
2428 let mut id = ptr::null_mut();
2429 let res = add_id_internal(attr, value, &mut id);
2430 if res < 0 {
2431 vctxt_error(
2432 ctxt,
2433 b"Memory allocation failed : xmlAddID\0" as *const u8 as *const c_char,
2434 );
2435 } else if res == 0 && !ctxt.is_null() {
2436 let msg = format!("ID {} already defined\0", string::xmlstr_to_string(value));
2437 vctxt_error(ctxt, msg.as_ptr() as *const c_char);
2438 }
2439 id
2440 }
2441}
2442
2443pub unsafe fn remove_id(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2450 unsafe {
2451 if doc.is_null() {
2452 return -1;
2453 }
2454 if attr.is_null() || (*attr).id.is_null() {
2455 return -1;
2456 }
2457 let table = (*doc).ids as *mut hash::HashTable;
2458 if table.is_null() {
2459 return -1;
2460 }
2461 let value = (*((*attr).id as *mut _xmlID)).value;
2462 if hash::hash_remove_entry(table, value, Some(free_id_entry)) < 0 {
2463 return -1;
2464 }
2465 0
2466 }
2467}
2468
2469unsafe fn free_ref(r: *mut _xmlRef) {
2471 if r.is_null() {
2472 return;
2473 }
2474 unsafe {
2475 if !(*r).value.is_null() {
2476 allocator::xmlFreeImpl((*r).value as *mut c_void);
2477 }
2478 if !(*r).name.is_null() {
2479 allocator::xmlFreeImpl((*r).name as *mut c_void);
2480 }
2481 allocator::xmlFreeImpl(r as *mut c_void);
2482 }
2483}
2484
2485unsafe extern "C" fn free_ref_list_entry(data: *mut c_void) {
2487 free_ref(data as *mut _xmlRef);
2488}
2489
2490const unsafe extern "C" fn dummy_compare(_a: *const c_void, _b: *const c_void) -> c_int {
2492 1
2493}
2494
2495unsafe extern "C" fn free_ref_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
2497 crate::xml::list::list_delete(payload as *mut crate::xml::list::List);
2498}
2499
2500pub unsafe fn add_ref(
2507 ctxt: *mut _xmlValidCtxt,
2508 doc: *mut _xmlDoc,
2509 value: *const xmlChar,
2510 attr: *mut _xmlAttr,
2511) -> *mut _xmlRef {
2512 unsafe {
2513 if doc.is_null() || value.is_null() || attr.is_null() {
2514 return ptr::null_mut();
2515 }
2516
2517 let mut table = (*doc).refs as *mut hash::HashTable;
2518 if table.is_null() {
2519 (*doc).refs = hash::hash_create(0) as *mut c_void;
2520 table = (*doc).refs as *mut hash::HashTable;
2521 if table.is_null() {
2522 vctxt_error(
2523 ctxt,
2524 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2525 );
2526 return ptr::null_mut();
2527 }
2528 }
2529
2530 let ret = allocator::xmlMallocZero(size_of::<_xmlRef>() as usize) as *mut _xmlRef;
2531 if ret.is_null() {
2532 vctxt_error(
2533 ctxt,
2534 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2535 );
2536 return ptr::null_mut();
2537 }
2538 (*ret).value = string::xml_strdup(value);
2539 if (*ret).value.is_null() {
2540 free_ref(ret);
2541 vctxt_error(
2542 ctxt,
2543 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2544 );
2545 return ptr::null_mut();
2546 }
2547 let streaming = !ctxt.is_null()
2551 && !(*ctxt).userData.is_null()
2552 && (*((*ctxt).userData as *mut _xmlParserCtxt)).parseMode
2553 == crate::abi::types::xmlParserMode::XML_PARSE_READER as c_int;
2554 if streaming {
2555 (*ret).name = string::xml_strdup((*attr).name);
2556 (*ret).attr = ptr::null_mut();
2557 } else {
2558 (*ret).name = ptr::null();
2559 (*ret).attr = attr;
2560 }
2561 (*ret).lineno = tree::get_line_no((*attr).parent) as c_int;
2562
2563 let ref_list = hash::hash_lookup(table, value) as *mut crate::xml::list::List;
2565 if ref_list.is_null() {
2566 let l = crate::xml::list::list_create(Some(free_ref_list_entry), Some(dummy_compare));
2567 if l.is_null() {
2568 free_ref(ret);
2569 vctxt_error(
2570 ctxt,
2571 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2572 );
2573 return ptr::null_mut();
2574 }
2575 if hash::hash_add_entry(table, value, l as *mut c_void) != 0 {
2576 crate::xml::list::list_delete(l);
2577 free_ref(ret);
2578 vctxt_error(
2579 ctxt,
2580 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2581 );
2582 return ptr::null_mut();
2583 }
2584 crate::xml::list::list_append(l, ret as *mut c_void);
2585 } else {
2586 if crate::xml::list::list_append(ref_list, ret as *mut c_void) != 0 {
2587 free_ref(ret);
2588 vctxt_error(
2589 ctxt,
2590 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2591 );
2592 return ptr::null_mut();
2593 }
2594 }
2595 ret
2596 }
2597}
2598
2599pub unsafe fn remove_ref(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2606 if doc.is_null() || attr.is_null() {
2610 return -1;
2611 }
2612 unsafe {
2613 let table = (*doc).refs as *mut hash::HashTable;
2614 if table.is_null() {
2615 return -1;
2616 }
2617 let mut removed = -1;
2618 struct ScanCtx {
2620 table: *mut hash::HashTable,
2621 attr: *mut _xmlAttr,
2622 removed: c_int,
2623 }
2624 extern "C" fn scan_remove(payload: *mut c_void, data: *mut c_void, name: *const xmlChar) {
2625 let ctx = unsafe { &mut *(data as *mut ScanCtx) };
2626 let l = payload as *mut crate::xml::list::List;
2627 let mut cur: *mut c_void = crate::xml::list::list_front(l);
2629 while !cur.is_null() {
2630 let next: *mut c_void = unsafe { (*(cur as *mut _xmlRef)).next as *mut c_void };
2631 let r = cur as *mut _xmlRef;
2632 if unsafe { (*r).attr } == ctx.attr {
2633 unsafe {
2634 crate::xml::list::list_remove_first(l, cur);
2635 }
2636 ctx.removed = 0;
2637 }
2638 cur = next;
2639 }
2640 if crate::xml::list::list_empty(l) != 0 {
2641 unsafe {
2642 hash::hash_remove_entry(ctx.table, name, Some(free_ref_table_entry));
2643 }
2644 }
2645 let _ = name;
2646 }
2647 let mut ctx = ScanCtx {
2648 table,
2649 attr,
2650 removed: -1,
2651 };
2652 hash::hash_scan(
2653 table,
2654 Some(scan_remove),
2655 &mut ctx as *mut ScanCtx as *mut c_void,
2656 );
2657 removed = ctx.removed;
2658 removed
2659 }
2660}
2661
2662pub unsafe fn add_id_safe(attr: *mut _xmlAttr, value: *const xmlChar) -> c_int {
2670 add_id_internal(attr, value, ptr::null_mut())
2671}
2672
2673pub unsafe fn free_id_table(table: *mut hash::HashTable) {
2679 hash::hash_free(table, Some(free_id_entry));
2680}
2681
2682pub unsafe fn free_ref_table(table: *mut hash::HashTable) {
2688 hash::hash_free(table, Some(free_ref_table_entry));
2689}
2690
2691pub unsafe fn get_id(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut _xmlAttr {
2699 unsafe {
2700 if doc.is_null() || id.is_null() {
2701 return ptr::null_mut();
2702 }
2703 let table = (*doc).ids as *mut hash::HashTable;
2704 if table.is_null() {
2705 return ptr::null_mut();
2706 }
2707 let id_entry = hash::hash_lookup(table, id) as *mut _xmlID;
2708 if id_entry.is_null() {
2709 return ptr::null_mut();
2710 }
2711 if (*id_entry).attr.is_null() {
2712 doc as *mut _xmlAttr
2714 } else {
2715 (*id_entry).attr
2716 }
2717 }
2718}
2719
2720pub unsafe fn get_refs(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut crate::xml::list::List {
2726 unsafe {
2727 if doc.is_null() || id.is_null() {
2728 return ptr::null_mut();
2729 }
2730 let table = (*doc).refs as *mut hash::HashTable;
2731 if table.is_null() {
2732 return ptr::null_mut();
2733 }
2734 hash::hash_lookup(table, id) as *mut crate::xml::list::List
2735 }
2736}
2737
2738pub unsafe fn is_id(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2746 unsafe {
2747 if attr.is_null() || (*attr).name.is_null() {
2748 return 0;
2749 }
2750 if !doc.is_null() && (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2751 if string::xml_strcmp(b"id\0" as *const u8 as *const xmlChar, (*attr).name) == 0 {
2752 return 1;
2753 }
2754 if elem.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
2755 return 0;
2756 }
2757 if string::xml_strcmp(b"name\0" as *const u8 as *const xmlChar, (*attr).name) == 0
2758 && string::xml_strcmp(b"a\0" as *const u8 as *const xmlChar, (*elem).name) == 0
2759 {
2760 return 1;
2761 }
2762 } else {
2763 if !(*attr).ns.is_null()
2765 && !(*(*attr).ns).prefix.is_null()
2766 && string::xml_strcmp(
2767 (*(*attr).ns).prefix,
2768 b"xml\0" as *const u8 as *const xmlChar,
2769 ) == 0
2770 && string::xml_strcmp((*attr).name, b"id\0" as *const u8 as *const xmlChar) == 0
2771 {
2772 return 1;
2773 }
2774 if doc.is_null() || ((*doc).intSubset.is_null() && (*doc).extSubset.is_null()) {
2775 return 0;
2776 }
2777 if elem.is_null()
2778 || (*elem).type_ != XML_ELEMENT_NODE as c_int
2779 || (*elem).name.is_null()
2780 {
2781 return 0;
2782 }
2783 let mut fullname = (*elem).name;
2784 let mut owned = false;
2785 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
2786 let f = string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
2787 if f.is_null() {
2788 return -1;
2789 }
2790 fullname = f;
2791 owned = true;
2792 }
2793 let aprefix = if !(*attr).ns.is_null() {
2794 (*(*attr).ns).prefix
2795 } else {
2796 ptr::null()
2797 };
2798 let mut attr_decl =
2799 get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
2800 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2801 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
2802 }
2803 if owned {
2804 allocator::xmlFreeImpl(fullname as *mut c_void);
2805 }
2806 if !attr_decl.is_null() && (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int {
2807 return 1;
2808 }
2809 }
2810 0
2811 }
2812}
2813
2814pub unsafe fn is_ref(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2820 unsafe {
2821 if attr.is_null() {
2822 return 0;
2823 }
2824 let doc = if doc.is_null() { (*attr).doc } else { doc };
2825 if doc.is_null() {
2826 return 0;
2827 }
2828 if (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2829 return 0;
2830 }
2831 if (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2832 return 0;
2833 }
2834 if elem.is_null() {
2835 return 0;
2836 }
2837 let aprefix = if !(*attr).ns.is_null() {
2838 (*(*attr).ns).prefix
2839 } else {
2840 ptr::null()
2841 };
2842 let mut attr_decl =
2843 get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
2844 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2845 attr_decl = get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
2846 }
2847 if !attr_decl.is_null()
2848 && ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
2849 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
2850 {
2851 return 1;
2852 }
2853 0
2854 }
2855}
2856
2857pub unsafe fn get_dtd_element_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlElement {
2864 unsafe {
2865 if dtd.is_null() || name.is_null() {
2866 return ptr::null_mut();
2867 }
2868 let elements = (*dtd).elements;
2869 if elements.is_null() {
2870 return ptr::null_mut();
2871 }
2872 let mut prefix = ptr::null_mut();
2873 let local = split_qname4(name, &mut prefix);
2874 if local.is_null() {
2875 if !prefix.is_null() {
2876 allocator::xmlFreeImpl(prefix as *mut c_void);
2877 }
2878 return ptr::null_mut();
2879 }
2880 let cur =
2881 hash::hash_lookup2(elements as *mut hash::HashTable, local, prefix) as *mut _xmlElement;
2882 if !prefix.is_null() {
2883 allocator::xmlFreeImpl(prefix as *mut c_void);
2884 }
2885 cur
2886 }
2887}
2888
2889pub unsafe fn get_dtd_attr_desc(
2897 dtd: *mut _xmlDtd,
2898 elem: *const xmlChar,
2899 name: *const xmlChar,
2900) -> *mut _xmlAttribute {
2901 unsafe {
2902 if dtd.is_null() || elem.is_null() || name.is_null() {
2903 return ptr::null_mut();
2904 }
2905 let attrs = (*dtd).attributes;
2906 if attrs.is_null() {
2907 return ptr::null_mut();
2908 }
2909 let mut prefix = ptr::null_mut();
2910 let local = split_qname4(name, &mut prefix);
2911 if local.is_null() {
2912 if !prefix.is_null() {
2913 allocator::xmlFreeImpl(prefix as *mut c_void);
2914 }
2915 return ptr::null_mut();
2916 }
2917 let cur = hash::hash_lookup3(attrs as *mut hash::HashTable, local, prefix, elem)
2918 as *mut _xmlAttribute;
2919 if !prefix.is_null() {
2920 allocator::xmlFreeImpl(prefix as *mut c_void);
2921 }
2922 cur
2923 }
2924}
2925
2926unsafe fn vctxt_error_node(ctxt: *mut _xmlValidCtxt, _node: *mut _xmlNode, msg: *const c_char) {
2936 vctxt_error(ctxt, msg);
2937}
2938
2939pub unsafe fn validate_element_decl(
2947 ctxt: *mut _xmlValidCtxt,
2948 doc: *mut _xmlDoc,
2949 elem: *mut _xmlElement,
2950) -> c_int {
2951 unsafe {
2952 if doc.is_null() || (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2953 return 1;
2954 }
2955 if elem.is_null() {
2956 return 1;
2957 }
2958 let mut ret = 1;
2959
2960 if (*elem).etype == XML_ELEMENT_TYPE_MIXED as c_int {
2963 let mut cur = (*elem).content;
2964 while !cur.is_null() {
2965 if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int {
2966 break;
2967 }
2968 if (*cur).c1.is_null() {
2969 break;
2970 }
2971 if (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2972 let name = (*(*cur).c1).name;
2973 let mut next = (*cur).c2;
2974 while !next.is_null() {
2975 if (*next).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2976 if string::xml_strcmp((*next).name, name) == 0
2977 && string::xml_strcmp((*next).prefix, (*(*cur).c1).prefix) == 0
2978 {
2979 if (*(*cur).c1).prefix.is_null() {
2980 let msg = format!(
2981 "Definition of {} has duplicate references of {}\0",
2982 string::xmlstr_to_string((*elem).name),
2983 string::xmlstr_to_string(name)
2984 );
2985 vctxt_error_node(
2986 ctxt,
2987 elem as *mut _xmlNode,
2988 msg.as_ptr() as *const c_char,
2989 );
2990 } else {
2991 let msg = format!(
2992 "Definition of {} has duplicate references of {}:{}\0",
2993 string::xmlstr_to_string((*elem).name),
2994 string::xmlstr_to_string((*(*cur).c1).prefix),
2995 string::xmlstr_to_string(name)
2996 );
2997 vctxt_error_node(
2998 ctxt,
2999 elem as *mut _xmlNode,
3000 msg.as_ptr() as *const c_char,
3001 );
3002 }
3003 ret = 0;
3004 }
3005 break;
3006 }
3007 if (*next).c1.is_null() {
3008 break;
3009 }
3010 if (*(*next).c1).type_ != XML_ELEMENT_CONTENT_ELEMENT as c_int {
3011 break;
3012 }
3013 if string::xml_strcmp((*(*next).c1).name, name) == 0
3014 && string::xml_strcmp((*(*next).c1).prefix, (*(*cur).c1).prefix) == 0
3015 {
3016 if (*(*cur).c1).prefix.is_null() {
3017 let msg = format!(
3018 "Definition of {} has duplicate references to {}\0",
3019 string::xmlstr_to_string((*elem).name),
3020 string::xmlstr_to_string(name)
3021 );
3022 vctxt_error_node(
3023 ctxt,
3024 elem as *mut _xmlNode,
3025 msg.as_ptr() as *const c_char,
3026 );
3027 } else {
3028 let msg = format!(
3029 "Definition of {} has duplicate references to {}:{}\0",
3030 string::xmlstr_to_string((*elem).name),
3031 string::xmlstr_to_string((*(*cur).c1).prefix),
3032 string::xmlstr_to_string(name)
3033 );
3034 vctxt_error_node(
3035 ctxt,
3036 elem as *mut _xmlNode,
3037 msg.as_ptr() as *const c_char,
3038 );
3039 }
3040 ret = 0;
3041 }
3042 next = (*next).c2;
3043 }
3044 }
3045 cur = (*cur).c2;
3046 }
3047 }
3048
3049 let mut prefix = ptr::null_mut();
3052 let local_name = split_qname4((*elem).name, &mut prefix);
3053 if local_name.is_null() {
3054 vctxt_error(
3055 ctxt,
3056 b"Memory allocation failed : xmlValidateElementDecl\0" as *const u8
3057 as *const c_char,
3058 );
3059 if !prefix.is_null() {
3060 allocator::xmlFreeImpl(prefix as *mut c_void);
3061 }
3062 return 0;
3063 }
3064
3065 for subset in [(*doc).intSubset, (*doc).extSubset] {
3066 if subset.is_null() {
3067 continue;
3068 }
3069 let tst = get_dtd_qelement_desc(subset, local_name, prefix);
3070 if !tst.is_null()
3071 && tst != elem
3072 && ((*tst).prefix == (*elem).prefix
3073 || string::xml_strcmp((*tst).prefix, (*elem).prefix) == 0)
3074 && (*tst).etype != XML_ELEMENT_TYPE_UNDEFINED as c_int
3075 {
3076 let msg = format!(
3077 "Redefinition of element {}\0",
3078 string::xmlstr_to_string((*elem).name)
3079 );
3080 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
3081 ret = 0;
3082 }
3083 }
3084 if !prefix.is_null() {
3085 allocator::xmlFreeImpl(prefix as *mut c_void);
3086 }
3087 ret
3088 }
3089}
3090
3091pub const unsafe fn validate_notation_decl(
3110 _ctxt: *mut _xmlValidCtxt,
3111 _doc: *mut _xmlDoc,
3112 _nota: *mut _xmlNotation,
3113) -> c_int {
3114 1
3115}
3116
3117pub unsafe fn validate_one_attribute(
3127 ctxt: *mut _xmlValidCtxt,
3128 doc: *mut _xmlDoc,
3129 elem: *mut _xmlNode,
3130 attr: *mut _xmlAttr,
3131 value: *const xmlChar,
3132) -> c_int {
3133 unsafe {
3134 if doc.is_null() {
3135 return 0;
3136 }
3137 if elem.is_null() || (*elem).name.is_null() {
3138 return 0;
3139 }
3140 if attr.is_null() || (*attr).name.is_null() {
3141 return 0;
3142 }
3143 let mut ret = 1;
3144
3145 let aprefix = if !(*attr).ns.is_null() {
3146 (*(*attr).ns).prefix
3147 } else {
3148 ptr::null()
3149 };
3150
3151 let mut attr_decl = ptr::null_mut();
3152 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3153 let fullname =
3154 string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
3155 if fullname.is_null() {
3156 vctxt_error(
3157 ctxt,
3158 b"Memory allocation failed : xmlValidateOneAttribute\0" as *const u8
3159 as *const c_char,
3160 );
3161 return 0;
3162 }
3163 attr_decl = get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
3164 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3165 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
3166 }
3167 if !std::ptr::eq(fullname, (*elem).name) {
3168 allocator::xmlFreeImpl(fullname as *mut c_void);
3169 }
3170 }
3171 if attr_decl.is_null() {
3172 attr_decl = get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
3173 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3174 attr_decl =
3175 get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
3176 }
3177 }
3178
3179 if attr_decl.is_null() {
3181 let msg = format!(
3182 "No declaration for attribute {} of element {}\0",
3183 string::xmlstr_to_string((*attr).name),
3184 string::xmlstr_to_string((*elem).name)
3185 );
3186 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3187 return 0;
3188 }
3189 if !(*attr).id.is_null() {
3190 remove_id(doc, attr);
3191 }
3192 (*attr).atype = (*attr_decl).atype;
3193
3194 let val = if (*doc).properties & crate::abi::types::xmlDocProperties::XML_DOC_OLD10 as c_int
3196 != 0
3197 {
3198 match (*attr_decl).atype as u32 {
3201 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
3202 validate_values_internal(value, 0)
3203 }
3204 t if t == XML_ATTRIBUTE_ENTITY as u32
3205 || t == XML_ATTRIBUTE_IDREF as u32
3206 || t == XML_ATTRIBUTE_ID as u32
3207 || t == XML_ATTRIBUTE_NOTATION as u32 =>
3208 {
3209 validate_value_internal(value, 0)
3210 }
3211 t if t == XML_ATTRIBUTE_NMTOKENS as u32
3212 || t == XML_ATTRIBUTE_ENUMERATION as u32 =>
3213 {
3214 validate_values_internal(value, XML_SCAN_NMTOKEN)
3215 }
3216 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => {
3217 validate_value_internal(value, XML_SCAN_NMTOKEN)
3218 }
3219 _ => 1,
3220 }
3221 } else {
3222 validate_attribute_value((*attr_decl).atype, value)
3223 };
3224 if val == 0 {
3225 let msg = format!(
3226 "Syntax of value for attribute {} of {} is not valid\0",
3227 string::xmlstr_to_string((*attr).name),
3228 string::xmlstr_to_string((*elem).name)
3229 );
3230 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3231 ret = 0;
3232 }
3233
3234 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3236 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3237 {
3238 let _msg = format!(
3239 "Value for attribute {} of {} is different from default \"{}\n\0",
3240 string::xmlstr_to_string((*attr).name),
3241 string::xmlstr_to_string((*elem).name),
3242 string::xmlstr_to_string((*attr_decl).defaultValue)
3243 );
3244 let msg = format!(
3246 "Value for attribute {} of {} is different from default \"{}\"\0",
3247 string::xmlstr_to_string((*attr).name),
3248 string::xmlstr_to_string((*elem).name),
3249 string::xmlstr_to_string((*attr_decl).defaultValue)
3250 );
3251 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3252 ret = 0;
3253 }
3254
3255 const XML_VCTXT_IN_ENTITY: c_uint = 4; if (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int
3258 && (ctxt.is_null() || (*ctxt).flags & XML_VCTXT_IN_ENTITY == 0)
3259 && add_id(ctxt, doc, value, attr).is_null()
3260 {
3261 ret = 0;
3262 }
3263 if ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
3264 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
3265 && add_ref(ctxt, doc, value, attr).is_null()
3266 {
3267 ret = 0;
3268 }
3269
3270 if (*attr_decl).atype == XML_ATTRIBUTE_NOTATION as c_int {
3272 let mut nota = get_dtd_notation_desc((*doc).intSubset, value);
3273 if nota.is_null() {
3274 nota = get_dtd_notation_desc((*doc).extSubset, value);
3275 }
3276 if nota.is_null() {
3277 let msg = format!(
3278 "Value \"{}\" for attribute {} of {} is not a declared Notation\0",
3279 string::xmlstr_to_string(value),
3280 string::xmlstr_to_string((*attr).name),
3281 string::xmlstr_to_string((*elem).name)
3282 );
3283 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3284 ret = 0;
3285 }
3286 let mut tree = (*attr_decl).tree;
3287 while !tree.is_null() {
3288 if string::xml_strcmp((*tree).name, value) == 0 {
3289 break;
3290 }
3291 tree = (*tree).next;
3292 }
3293 if tree.is_null() {
3294 let msg = format!(
3295 "Value \"{}\" for attribute {} of {} is not among the enumerated notations\0",
3296 string::xmlstr_to_string(value),
3297 string::xmlstr_to_string((*attr).name),
3298 string::xmlstr_to_string((*elem).name)
3299 );
3300 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3301 ret = 0;
3302 }
3303 }
3304
3305 if (*attr_decl).atype == XML_ATTRIBUTE_ENUMERATION as c_int {
3307 let mut tree = (*attr_decl).tree;
3308 while !tree.is_null() {
3309 if string::xml_strcmp((*tree).name, value) == 0 {
3310 break;
3311 }
3312 tree = (*tree).next;
3313 }
3314 if tree.is_null() {
3315 let msg = format!(
3316 "Value \"{}\" for attribute {} of {} is not among the enumerated set\0",
3317 string::xmlstr_to_string(value),
3318 string::xmlstr_to_string((*attr).name),
3319 string::xmlstr_to_string((*elem).name)
3320 );
3321 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3322 ret = 0;
3323 }
3324 }
3325
3326 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3328 && string::xml_strcmp((*attr_decl).defaultValue, value) != 0
3329 {
3330 let msg = format!(
3331 "Value for attribute {} of {} must be \"{}\"\0",
3332 string::xmlstr_to_string((*attr).name),
3333 string::xmlstr_to_string((*elem).name),
3334 string::xmlstr_to_string((*attr_decl).defaultValue)
3335 );
3336 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3337 ret = 0;
3338 }
3339
3340 if (*attr_decl).atype == XML_ATTRIBUTE_ENTITY as c_int {
3342 let ent = tree::get_doc_entity(doc, value);
3343 if ent.is_null() {
3344 let msg = format!(
3345 "ENTITY attribute {} reference an unknown entity \"{}\"\0",
3346 string::xmlstr_to_string((*attr).name),
3347 string::xmlstr_to_string(value)
3348 );
3349 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3350 ret = 0;
3351 } else if (*ent).etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3352 let msg = format!(
3353 "ENTITY attribute {} reference an entity \"{}\" of wrong type\0",
3354 string::xmlstr_to_string((*attr).name),
3355 string::xmlstr_to_string(value)
3356 );
3357 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3358 ret = 0;
3359 }
3360 }
3361 ret
3362 }
3363}
3364
3365pub unsafe fn validate_one_namespace(
3372 ctxt: *mut _xmlValidCtxt,
3373 doc: *mut _xmlDoc,
3374 elem: *mut _xmlNode,
3375 prefix: *const xmlChar,
3376 ns: *mut _xmlNs,
3377 value: *const xmlChar,
3378) -> c_int {
3379 unsafe {
3380 if doc.is_null() {
3381 return 0;
3382 }
3383 if elem.is_null() || (*elem).name.is_null() {
3384 return 0;
3385 }
3386 if ns.is_null() || (*ns).href.is_null() {
3387 return 0;
3388 }
3389 let mut ret = 1;
3390
3391 let mut attr_decl = ptr::null_mut();
3392 if !prefix.is_null() {
3393 let fullname = string::build_qname((*elem).name, prefix, ptr::null_mut(), 0);
3394 if fullname.is_null() {
3395 vctxt_error(
3396 ctxt,
3397 b"Memory allocation failed : xmlValidateOneNamespace\0" as *const u8
3398 as *const c_char,
3399 );
3400 return 0;
3401 }
3402 if !(*ns).prefix.is_null() {
3403 attr_decl = get_dtd_qattr_desc(
3404 (*doc).intSubset,
3405 fullname,
3406 (*ns).prefix,
3407 b"xmlns\0" as *const u8 as *const xmlChar,
3408 );
3409 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3410 attr_decl = get_dtd_qattr_desc(
3411 (*doc).extSubset,
3412 fullname,
3413 (*ns).prefix,
3414 b"xmlns\0" as *const u8 as *const xmlChar,
3415 );
3416 }
3417 } else {
3418 attr_decl = get_dtd_qattr_desc(
3419 (*doc).intSubset,
3420 fullname,
3421 b"xmlns\0" as *const u8 as *const xmlChar,
3422 ptr::null(),
3423 );
3424 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3425 attr_decl = get_dtd_qattr_desc(
3426 (*doc).extSubset,
3427 fullname,
3428 b"xmlns\0" as *const u8 as *const xmlChar,
3429 ptr::null(),
3430 );
3431 }
3432 }
3433 if !std::ptr::eq(fullname, (*elem).name) {
3434 allocator::xmlFreeImpl(fullname as *mut c_void);
3435 }
3436 }
3437 if attr_decl.is_null() {
3438 if !(*ns).prefix.is_null() {
3439 attr_decl = get_dtd_qattr_desc(
3440 (*doc).intSubset,
3441 (*elem).name,
3442 (*ns).prefix,
3443 b"xmlns\0" as *const u8 as *const xmlChar,
3444 );
3445 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3446 attr_decl = get_dtd_qattr_desc(
3447 (*doc).extSubset,
3448 (*elem).name,
3449 (*ns).prefix,
3450 b"xmlns\0" as *const u8 as *const xmlChar,
3451 );
3452 }
3453 } else {
3454 attr_decl = get_dtd_qattr_desc(
3455 (*doc).intSubset,
3456 (*elem).name,
3457 b"xmlns\0" as *const u8 as *const xmlChar,
3458 ptr::null(),
3459 );
3460 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3461 attr_decl = get_dtd_qattr_desc(
3462 (*doc).extSubset,
3463 (*elem).name,
3464 b"xmlns\0" as *const u8 as *const xmlChar,
3465 ptr::null(),
3466 );
3467 }
3468 }
3469 }
3470
3471 if attr_decl.is_null() {
3473 let msg = if !(*ns).prefix.is_null() {
3474 format!(
3475 "No declaration for attribute xmlns:{} of element {}\0",
3476 string::xmlstr_to_string((*ns).prefix),
3477 string::xmlstr_to_string((*elem).name)
3478 )
3479 } else {
3480 format!(
3481 "No declaration for attribute xmlns of element {}\0",
3482 string::xmlstr_to_string((*elem).name)
3483 )
3484 };
3485 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3486 return 0;
3487 }
3488
3489 let val = validate_attribute_value((*attr_decl).atype, value);
3490 if val == 0 {
3491 let msg = if !(*ns).prefix.is_null() {
3492 format!(
3493 "Syntax of value for attribute xmlns:{} of {} is not valid\0",
3494 string::xmlstr_to_string((*ns).prefix),
3495 string::xmlstr_to_string((*elem).name)
3496 )
3497 } else {
3498 format!(
3499 "Syntax of value for attribute xmlns of {} is not valid\0",
3500 string::xmlstr_to_string((*elem).name)
3501 )
3502 };
3503 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3504 ret = 0;
3505 }
3506
3507 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3509 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3510 {
3511 let msg = if !(*ns).prefix.is_null() {
3512 format!(
3513 "Value for attribute xmlns:{} of {} is different from default \"{}\"\0",
3514 string::xmlstr_to_string((*ns).prefix),
3515 string::xmlstr_to_string((*elem).name),
3516 string::xmlstr_to_string((*attr_decl).defaultValue)
3517 )
3518 } else {
3519 format!(
3520 "Value for attribute xmlns of {} is different from default \"{}\"\0",
3521 string::xmlstr_to_string((*elem).name),
3522 string::xmlstr_to_string((*attr_decl).defaultValue)
3523 )
3524 };
3525 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3526 ret = 0;
3527 }
3528 ret
3529 }
3530}
3531
3532pub unsafe fn validate_one_element(
3540 ctxt: *mut _xmlValidCtxt,
3541 doc: *mut _xmlDoc,
3542 elem: *mut _xmlNode,
3543) -> c_int {
3544 unsafe {
3545 if doc.is_null() {
3546 return 0;
3547 }
3548 if elem.is_null() {
3549 return 0;
3550 }
3551 match (*elem).type_ {
3552 t if t == XML_TEXT_NODE as c_int
3553 || t == XML_CDATA_SECTION_NODE as c_int
3554 || t == XML_ENTITY_REF_NODE as c_int
3555 || t == XML_PI_NODE as c_int
3556 || t == XML_COMMENT_NODE as c_int
3557 || t == XML_XINCLUDE_START as c_int
3558 || t == XML_XINCLUDE_END as c_int =>
3559 {
3560 return 1;
3561 }
3562 t if t == XML_ELEMENT_NODE as c_int => {}
3563 _ => {
3564 vctxt_error_node(
3565 ctxt,
3566 elem,
3567 b"unexpected element type\0" as *const u8 as *const c_char,
3568 );
3569 return 0;
3570 }
3571 }
3572
3573 let mut ret = 1;
3574 let mut extsubset = 0;
3575 let elem_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
3576 if elem_decl.is_null() {
3577 return 0;
3578 }
3579
3580 if (*ctxt).vstateNr == 0 {
3583 match (*elem_decl).etype as u32 {
3584 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => {
3585 let msg = format!(
3586 "No declaration for element {}\0",
3587 string::xmlstr_to_string((*elem).name)
3588 );
3589 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3590 return 0;
3591 }
3592 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
3593 if !(*elem).children.is_null() {
3594 let msg = format!(
3595 "Element {} was declared EMPTY this one has content\0",
3596 string::xmlstr_to_string((*elem).name)
3597 );
3598 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3599 ret = 0;
3600 }
3601 }
3602 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
3603 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
3604 if !(*elem_decl).content.is_null()
3605 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
3606 {
3607 let mut child = (*elem).children;
3609 while !child.is_null() {
3610 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3611 let msg = format!(
3612 "Element {} was declared #PCDATA but contains non text nodes\0",
3613 string::xmlstr_to_string((*elem).name)
3614 );
3615 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3616 ret = 0;
3617 break;
3618 }
3619 child = (*child).next;
3620 }
3621 } else {
3622 let mut child = (*elem).children;
3624 while !child.is_null() {
3625 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3626 let mut fullname = (*child).name;
3627 let mut own = false;
3628 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3629 let fnp = string::build_qname(
3630 (*child).name,
3631 (*(*child).ns).prefix,
3632 ptr::null_mut(),
3633 0,
3634 );
3635 if fnp.is_null() {
3636 vctxt_error(
3637 ctxt,
3638 b"Memory allocation failed : xmlValidateOneElement\0"
3639 as *const u8
3640 as *const c_char,
3641 );
3642 return 0;
3643 }
3644 fullname = fnp;
3645 own = true;
3646 }
3647 if validate_check_mixed(ctxt, (*elem_decl).content, fullname) != 1 {
3648 let msg = format!(
3649 "Element {} is not declared in {} list of possible children\0",
3650 string::xmlstr_to_string(fullname),
3651 string::xmlstr_to_string((*elem).name)
3652 );
3653 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3654 ret = 0;
3655 }
3656 if own {
3657 allocator::xmlFreeImpl(fullname as *mut c_void);
3658 }
3659 }
3660 child = (*child).next;
3661 }
3662 }
3663 }
3664 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
3665 let mut names: Vec<*const xmlChar> = Vec::new();
3668 let mut owned: Vec<*mut xmlChar> = Vec::new();
3669 let mut child = (*elem).children;
3670 while !child.is_null() {
3671 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3672 let mut fullname = (*child).name;
3673 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3674 let fnp = string::build_qname(
3675 (*child).name,
3676 (*(*child).ns).prefix,
3677 ptr::null_mut(),
3678 0,
3679 );
3680 if !fnp.is_null() {
3681 fullname = fnp;
3682 owned.push(fnp);
3683 }
3684 }
3685 names.push(fullname);
3686 }
3687 child = (*child).next;
3688 }
3689 let result = dtd::valid_content_model((*elem_decl).content, &names);
3690 for n in owned {
3691 allocator::xmlFreeImpl(n as *mut c_void);
3692 }
3693 if result != dtd::ContentModelResult::Valid {
3694 let msg = format!(
3695 "Element {} content does not follow the DTD\0",
3696 string::xmlstr_to_string((*elem).name)
3697 );
3698 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3699 ret = 0;
3700 }
3701 }
3702 _ => {}
3703 }
3704
3705 let mut attr = (*elem).properties;
3707 while !attr.is_null() {
3708 let aval = if !(*attr).children.is_null() {
3709 (*(*attr).children).content
3710 } else {
3711 ptr::null()
3712 };
3713 if validate_one_attribute(ctxt, doc, elem, attr, aval) == 0 {
3714 ret = 0;
3715 }
3716 attr = (*attr).next;
3717 }
3718 }
3719 ret
3720 }
3721}
3722
3723#[repr(C)]
3738struct ValidState {
3739 elem_decl: *mut _xmlElement,
3740 node: *mut _xmlNode,
3741 exec: *mut ContentModelExec,
3742}
3743
3744unsafe fn valid_get_elem_decl(
3747 ctxt: *mut _xmlValidCtxt,
3748 doc: *mut _xmlDoc,
3749 elem: *mut _xmlNode,
3750 extsubset: *mut c_int,
3751) -> *mut _xmlElement {
3752 unsafe {
3753 if ctxt.is_null() || doc.is_null() || elem.is_null() || (*elem).name.is_null() {
3754 return ptr::null_mut();
3755 }
3756 if !extsubset.is_null() {
3757 *extsubset = 0;
3758 }
3759 let mut elem_decl = ptr::null_mut();
3760
3761 let prefix = if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3762 (*(*elem).ns).prefix
3763 } else {
3764 ptr::null()
3765 };
3766 if !prefix.is_null() {
3767 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, prefix);
3768 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3769 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, prefix);
3770 if !elem_decl.is_null() && !extsubset.is_null() {
3771 *extsubset = 1;
3772 }
3773 }
3774 }
3775 if elem_decl.is_null() {
3776 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, ptr::null());
3778 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3779 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, ptr::null());
3780 if !elem_decl.is_null() && !extsubset.is_null() {
3781 *extsubset = 1;
3782 }
3783 }
3784 }
3785 if elem_decl.is_null() {
3786 let msg = format!(
3787 "No declaration for element {}\0",
3788 string::xmlstr_to_string((*elem).name)
3789 );
3790 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3791 }
3792 elem_decl
3793 }
3794}
3795
3796unsafe fn validate_check_mixed(
3798 ctxt: *mut _xmlValidCtxt,
3799 cont: *mut _xmlElementContent,
3800 qname: *const xmlChar,
3801) -> c_int {
3802 unsafe {
3803 let mut plen: c_int = 0;
3804 let has_colon = string::split_qname3(qname, &mut plen) != 0;
3805 let local = if has_colon {
3809 qname.add(plen as usize + 1)
3810 } else {
3811 ptr::null()
3812 };
3813 let mut cur = cont;
3814 if local.is_null() {
3815 while !cur.is_null() {
3816 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3817 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
3818 return 1;
3819 }
3820 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3821 && !(*cur).c1.is_null()
3822 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3823 {
3824 if (*(*cur).c1).prefix.is_null()
3825 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3826 {
3827 return 1;
3828 }
3829 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3830 || (*cur).c1.is_null()
3831 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3832 {
3833 vctxt_error(
3834 ctxt,
3835 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3836 );
3837 break;
3838 }
3839 cur = (*cur).c2;
3840 }
3841 } else {
3842 while !cur.is_null() {
3843 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3844 if !(*cur).prefix.is_null()
3845 && prefix_matches((*cur).prefix, qname, plen)
3846 && string::xml_strcmp((*cur).name, local) == 0
3847 {
3848 return 1;
3849 }
3850 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3851 && !(*cur).c1.is_null()
3852 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3853 {
3854 if !(*(*cur).c1).prefix.is_null()
3855 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3856 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3857 {
3858 return 1;
3859 }
3860 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3861 || (*cur).c1.is_null()
3862 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3863 {
3864 vctxt_error(
3865 ctxt,
3866 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3867 );
3868 break;
3869 }
3870 cur = (*cur).c2;
3871 }
3872 }
3873 0
3874 }
3875}
3876
3877unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
3880 unsafe {
3881 let p = string::xmlstr_to_bytes(prefix);
3882 let q = string::xmlstr_to_bytes(qname);
3883 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
3884 }
3885}
3886
3887#[derive(Debug)]
3896#[repr(C)]
3897pub struct ContentModelNfa {
3898 transitions: Vec<(u32, *const xmlChar, u32)>,
3900 start: u32,
3902 accept: Vec<u32>,
3904}
3905
3906#[derive(Debug)]
3908#[repr(C)]
3909pub struct ContentModelExec {
3910 nfa: *mut ContentModelNfa,
3912 current: Vec<u32>,
3914}
3915
3916struct NfaBuilder {
3918 transitions: Vec<(u32, *const xmlChar, u32)>,
3919 n_states: u32,
3920}
3921
3922impl NfaBuilder {
3923 const fn new() -> Self {
3924 NfaBuilder {
3925 transitions: Vec::new(),
3926 n_states: 0,
3927 }
3928 }
3929 const fn new_state(&mut self) -> u32 {
3930 let s = self.n_states;
3931 self.n_states += 1;
3932 s
3933 }
3934 fn eps(&mut self, from: u32, to: u32) {
3935 self.transitions.push((from, ptr::null(), to));
3936 }
3937 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
3938 self.transitions.push((from, name, to));
3939 }
3940}
3941
3942unsafe fn compile_content_sub(
3947 b: &mut NfaBuilder,
3948 model: *mut _xmlElementContent,
3949) -> (u32, Vec<u32>) {
3950 if model.is_null() {
3951 let s = b.new_state();
3952 return (s, vec![s]);
3953 }
3954 let m = unsafe { &*model };
3955 let (mut in_s, outs) = match m.type_ as u32 {
3956 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
3957 let s = b.new_state();
3958 let to = b.new_state();
3959 b.name_trans(s, m.name, to);
3960 (s, vec![to])
3961 }
3962 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
3963 let (in1, out1) = compile_content_sub(b, m.c1);
3964 let (in2, out2) = compile_content_sub(b, m.c2);
3965 for &o in &out1 {
3966 b.eps(o, in2);
3967 }
3968 (in1, out2)
3969 }
3970 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
3971 let (in1, out1) = compile_content_sub(b, m.c1);
3972 let (in2, out2) = compile_content_sub(b, m.c2);
3973 let s = b.new_state();
3974 b.eps(s, in1);
3975 b.eps(s, in2);
3976 let mut all = out1;
3977 all.extend(out2);
3978 (s, all)
3979 }
3980 _ => {
3985 let s = b.new_state();
3986 (s, vec![s])
3987 }
3988 };
3989 match m.ocur as u32 {
3990 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
3991 let s = b.new_state();
3992 b.eps(s, in_s);
3993 for &o2 in &outs {
3994 b.eps(s, o2);
3995 }
3996 in_s = s;
3997 }
3998 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
3999 let s = b.new_state();
4000 b.eps(s, in_s);
4001 for &o2 in &outs {
4002 b.eps(s, o2);
4003 b.eps(o2, s);
4004 }
4005 in_s = s;
4006 }
4007 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
4008 let s = b.new_state();
4009 b.eps(s, in_s);
4010 for &o2 in &outs {
4011 b.eps(o2, s);
4012 }
4013 in_s = s;
4014 }
4015 _ => {}
4016 }
4017 (in_s, outs)
4018}
4019
4020unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
4022 if model.is_null() {
4023 return false;
4024 }
4025 unsafe {
4026 let m = &*model;
4027 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
4028 return true;
4029 }
4030 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
4031 }
4032}
4033
4034unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
4040 unsafe {
4041 if content.is_null() {
4042 return ptr::null_mut();
4043 }
4044 let mut b = NfaBuilder::new();
4045 let (start, outs) = compile_content_sub(&mut b, content);
4046 let nfa = Box::new(ContentModelNfa {
4047 transitions: b.transitions,
4048 start,
4049 accept: outs,
4050 });
4051 Box::into_raw(nfa)
4052 }
4053}
4054
4055pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
4061 if nfa.is_null() {
4062 return;
4063 }
4064 unsafe {
4065 ptr::drop_in_place(nfa);
4066 allocator::xmlFreeImpl(nfa as *mut c_void);
4067 }
4068}
4069
4070unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4072 let mut out = states.to_vec();
4073 let mut stack = states.to_vec();
4074 while let Some(s) = stack.pop() {
4075 for &(from, name, to) in &nfa.transitions {
4076 if from == s && name.is_null() && !out.contains(&to) {
4077 out.push(to);
4078 stack.push(to);
4079 }
4080 }
4081 }
4082 out.sort_unstable();
4083 out.dedup();
4084 out
4085}
4086
4087unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4089 unsafe {
4090 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4091 if exec.is_null() {
4092 return ptr::null_mut();
4093 }
4094 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4095 ptr::write(&mut (*exec).nfa, nfa);
4096 ptr::write(&mut (*exec).current, cur);
4097 exec
4098 }
4099}
4100
4101unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4103 if exec.is_null() {
4104 return;
4105 }
4106 unsafe {
4107 ptr::drop_in_place(&mut (*exec).current);
4108 allocator::xmlFreeImpl(exec as *mut c_void);
4109 }
4110}
4111
4112unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4117 unsafe {
4118 if exec.is_null() {
4119 return -1;
4120 }
4121 let nfa = &*(*exec).nfa;
4122 if value.is_null() {
4123 let cur = eps_closure(nfa, &(*exec).current);
4124 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4125 1
4126 } else {
4127 0
4128 };
4129 }
4130 let mut next: Vec<u32> = Vec::new();
4131 for &s in &(*exec).current {
4132 for &(from, name, to) in &nfa.transitions {
4133 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4134 next.push(to);
4135 }
4136 }
4137 }
4138 next.sort_unstable();
4139 next.dedup();
4140 if next.is_empty() {
4141 return -1;
4142 }
4143 let closed = eps_closure(nfa, &next);
4144 (*exec).current = closed;
4145 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4146 1
4147 } else {
4148 0
4149 }
4150 }
4151}
4152
4153unsafe fn vstate_vpush(
4155 ctxt: *mut _xmlValidCtxt,
4156 elem_decl: *mut _xmlElement,
4157 node: *mut _xmlNode,
4158) -> c_int {
4159 unsafe {
4160 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4161 let new_max = if (*ctxt).vstateMax == 0 {
4162 10
4163 } else {
4164 (*ctxt).vstateMax * 2
4165 };
4166 let new_tab = allocator::xmlReallocImpl(
4167 (*ctxt).vstateTab,
4168 (new_max as usize) * size_of::<ValidState>(),
4169 ) as *mut ValidState;
4170 if new_tab.is_null() {
4171 vctxt_error(
4172 ctxt,
4173 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4174 );
4175 return -1;
4176 }
4177 (*ctxt).vstateTab = new_tab as *mut c_void;
4178 (*ctxt).vstateMax = new_max;
4179 }
4180 let idx = (*ctxt).vstateNr as usize;
4181 let tab = (*ctxt).vstateTab as *mut ValidState;
4182 (*tab.add(idx)).elem_decl = elem_decl;
4183 (*tab.add(idx)).node = node;
4184 (*tab.add(idx)).exec = ptr::null_mut();
4185 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4186 if (*elem_decl).cont_model.is_null() {
4187 validate_build_content_model(ctxt, elem_decl);
4188 }
4189 if !(*elem_decl).cont_model.is_null() {
4190 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4191 if exec.is_null() {
4192 vctxt_error(
4193 ctxt,
4194 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4195 );
4196 return -1;
4197 }
4198 (*tab.add(idx)).exec = exec;
4199 } else {
4200 let msg = format!(
4201 "Failed to build content model regexp for {}\0",
4202 string::xmlstr_to_string((*elem_decl).name)
4203 );
4204 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4205 }
4206 }
4207 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4208 (*ctxt).vstateNr += 1;
4209 0
4210 }
4211}
4212
4213unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4215 unsafe {
4216 if (*ctxt).vstateNr < 1 {
4217 return -1;
4218 }
4219 (*ctxt).vstateNr -= 1;
4220 let idx = (*ctxt).vstateNr as usize;
4221 let tab = (*ctxt).vstateTab as *mut ValidState;
4222 let elem_decl = (*tab.add(idx)).elem_decl;
4223 (*tab.add(idx)).elem_decl = ptr::null_mut();
4224 (*tab.add(idx)).node = ptr::null_mut();
4225 if !elem_decl.is_null()
4226 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4227 && !(*tab.add(idx)).exec.is_null()
4228 {
4229 free_content_exec((*tab.add(idx)).exec);
4230 }
4231 (*tab.add(idx)).exec = ptr::null_mut();
4232 if (*ctxt).vstateNr >= 1 {
4233 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4234 } else {
4235 (*ctxt).vstate = ptr::null_mut();
4236 }
4237 0
4238 }
4239}
4240
4241pub unsafe fn validate_build_content_model(
4249 ctxt: *mut _xmlValidCtxt,
4250 elem: *mut _xmlElement,
4251) -> c_int {
4252 unsafe {
4253 if ctxt.is_null() {
4254 return 0;
4255 }
4256 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4257 return 0;
4258 }
4259 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4260 return 1;
4261 }
4262 if !(*elem).cont_model.is_null() {
4263 return 1;
4264 }
4265 if (*elem).content.is_null() {
4266 return 1;
4267 }
4268 if content_has_pcdata((*elem).content) {
4269 let msg = format!(
4270 "Found PCDATA in content model of {}\0",
4271 string::xmlstr_to_string((*elem).name)
4272 );
4273 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4274 return 0;
4275 }
4276 let nfa = build_content_nfa((*elem).content);
4277 if nfa.is_null() {
4278 vctxt_error(
4279 ctxt,
4280 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4281 as *const c_char,
4282 );
4283 return 0;
4284 }
4285 (*elem).cont_model = nfa as *mut c_void;
4286 1
4287 }
4288}
4289
4290pub unsafe fn validate_push_element(
4298 ctxt: *mut _xmlValidCtxt,
4299 doc: *mut _xmlDoc,
4300 elem: *mut _xmlNode,
4301 qname: *const xmlChar,
4302) -> c_int {
4303 unsafe {
4304 let mut ret = 1;
4305 if ctxt.is_null() {
4306 return 0;
4307 }
4308 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4309 let state = (*ctxt).vstate as *mut ValidState;
4310 let elem_decl = (*state).elem_decl;
4311 if !elem_decl.is_null() {
4312 match (*elem_decl).etype as u32 {
4313 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4314 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4315 let msg = format!(
4316 "Element {} was declared EMPTY this one has content\0",
4317 string::xmlstr_to_string((*(*state).node).name)
4318 );
4319 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4320 ret = 0;
4321 }
4322 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4323 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4324 if !(*elem_decl).content.is_null()
4325 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4326 {
4327 let msg = format!(
4328 "Element {} was declared #PCDATA but contains non text nodes\0",
4329 string::xmlstr_to_string((*(*state).node).name)
4330 );
4331 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4332 ret = 0;
4333 } else {
4334 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4335 if ret != 1 {
4336 let msg = format!(
4337 "Element {} is not declared in {} list of possible children\0",
4338 string::xmlstr_to_string(qname),
4339 string::xmlstr_to_string((*(*state).node).name)
4340 );
4341 vctxt_error_node(
4342 ctxt,
4343 (*state).node,
4344 msg.as_ptr() as *const c_char,
4345 );
4346 }
4347 }
4348 }
4349 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 && !(*state).exec.is_null() => {
4350 ret = content_exec_push((*state).exec, qname);
4351 if ret < 0 {
4352 let msg = format!(
4353 "Element {} content does not follow the DTD, Misplaced {}\0",
4354 string::xmlstr_to_string((*(*state).node).name),
4355 string::xmlstr_to_string(qname)
4356 );
4357 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4358 ret = 0;
4359 } else {
4360 ret = 1;
4361 }
4362 }
4363 _ => {}
4364 }
4365 }
4366 }
4367 let mut extsubset = 0;
4368 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4369 let _ = vstate_vpush(ctxt, e_decl, elem);
4371 ret
4372 }
4373}
4374
4375pub unsafe fn validate_push_cdata(
4382 ctxt: *mut _xmlValidCtxt,
4383 data: *const xmlChar,
4384 len: c_int,
4385) -> c_int {
4386 unsafe {
4387 let mut ret = 1;
4388 if ctxt.is_null() {
4389 return 0;
4390 }
4391 if len <= 0 {
4392 return 1;
4393 }
4394 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4395 let state = (*ctxt).vstate as *mut ValidState;
4396 let elem_decl = (*state).elem_decl;
4397 if !elem_decl.is_null() {
4398 match (*elem_decl).etype as u32 {
4399 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4400 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4401 let msg = format!(
4402 "Element {} was declared EMPTY this one has content\0",
4403 string::xmlstr_to_string((*(*state).node).name)
4404 );
4405 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4406 ret = 0;
4407 }
4408 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4409 }
4410 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4411 let bytes = core::slice::from_raw_parts(data, len as usize);
4412 for &b in bytes {
4413 if !is_blank_byte(b) {
4414 let msg = format!(
4415 "Element {} content does not follow the DTD, Text not allowed\0",
4416 string::xmlstr_to_string((*(*state).node).name)
4417 );
4418 vctxt_error_node(
4419 ctxt,
4420 (*state).node,
4421 msg.as_ptr() as *const c_char,
4422 );
4423 ret = 0;
4424 break;
4425 }
4426 }
4427 }
4428 _ => {}
4429 }
4430 }
4431 }
4432 ret
4433 }
4434}
4435
4436pub unsafe fn validate_pop_element(
4443 ctxt: *mut _xmlValidCtxt,
4444 _doc: *mut _xmlDoc,
4445 _elem: *mut _xmlNode,
4446 _qname: *const xmlChar,
4447) -> c_int {
4448 unsafe {
4449 let mut ret = 1;
4450 if ctxt.is_null() {
4451 return 0;
4452 }
4453 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4454 let state = (*ctxt).vstate as *mut ValidState;
4455 let elem_decl = (*state).elem_decl;
4456 if !elem_decl.is_null()
4457 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4458 && !(*state).exec.is_null()
4459 {
4460 ret = content_exec_push((*state).exec, ptr::null());
4461 if ret <= 0 {
4462 let msg = format!(
4463 "Element {} content does not follow the DTD, Expecting more children\0",
4464 string::xmlstr_to_string((*(*state).node).name)
4465 );
4466 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4467 ret = 0;
4468 } else {
4469 ret = 1;
4470 }
4471 }
4472 let _ = vstate_vpop(ctxt);
4473 }
4474 ret
4475 }
4476}
4477
4478#[cfg(test)]
4483mod tests {
4484 use super::*;
4485 use crate::abi::allocator;
4486
4487 use crate::xml::dtd;
4488 use crate::xml::tree;
4489
4490 unsafe fn c_str(s: &str) -> *const xmlChar {
4494 let bytes = s.as_bytes();
4495 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4496 assert!(!ptr.is_null());
4497 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4498 *ptr.add(bytes.len()) = 0;
4499 ptr
4500 }
4501
4502 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4504 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4505 assert!(!doc.is_null());
4506
4507 let name = c_str("root");
4508 let ext_id = c_str("--//Test//DTD//EN");
4509 let sys_id = c_str("test.dtd");
4510 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4511 assert!(!dtd.is_null());
4512
4513 (doc, dtd)
4514 }
4515
4516 #[allow(unused)]
4518 unsafe fn add_elem_decl(
4519 dtd: *mut _xmlDtd,
4520 name: *const xmlChar,
4521 elem_type: c_int,
4522 content: *mut _xmlElementContent,
4523 ) -> *mut _xmlElement {
4524 dtd::add_element_decl(dtd, name, elem_type, content)
4525 }
4526
4527 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4529 let node = tree::new_node(ptr::null_mut(), name);
4530 assert!(!node.is_null());
4531 tree::add_child(doc as *mut _xmlNode, node);
4532 node
4533 }
4534
4535 #[allow(unused)]
4537 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4538 let node = tree::new_node(ptr::null_mut(), name);
4539 assert!(!node.is_null());
4540 tree::add_child(parent, node);
4541 node
4542 }
4543
4544 #[test]
4547 fn test_validate_name_null() {
4548 unsafe {
4549 assert_eq!(validate_name(ptr::null()), 0);
4550 }
4551 }
4552
4553 #[test]
4554 fn test_validate_name_empty() {
4555 unsafe {
4556 let s = b"\0" as *const u8 as *const xmlChar;
4557 assert_eq!(validate_name(s), 0);
4558 }
4559 }
4560
4561 #[test]
4562 fn test_validate_name_valid() {
4563 unsafe {
4564 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4565 for t in &tests {
4566 let s = c_str(t);
4567 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4568 allocator::xmlFreeImpl(s as *mut c_void);
4569 }
4570 }
4571 }
4572
4573 #[test]
4574 fn test_validate_name_invalid() {
4575 unsafe {
4576 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4577 for t in &tests {
4578 let s = c_str(t);
4579 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4580 allocator::xmlFreeImpl(s as *mut c_void);
4581 }
4582 }
4583 }
4584
4585 #[test]
4586 fn test_validate_names_valid() {
4587 unsafe {
4588 let s = c_str("foo bar baz");
4589 assert_eq!(validate_names(s), 1);
4590 allocator::xmlFreeImpl(s as *mut c_void);
4591 }
4592 }
4593
4594 #[test]
4595 fn test_validate_names_invalid() {
4596 unsafe {
4597 let s = c_str("foo 123bar baz");
4598 assert_eq!(validate_names(s), 0);
4599 allocator::xmlFreeImpl(s as *mut c_void);
4600 }
4601 }
4602
4603 #[test]
4606 fn test_validate_nmtoken_null() {
4607 unsafe {
4608 assert_eq!(validate_nmtoken(ptr::null()), 0);
4609 }
4610 }
4611
4612 #[test]
4613 fn test_validate_nmtoken_valid() {
4614 unsafe {
4615 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4616 for t in &tests {
4617 let s = c_str(t);
4618 assert_eq!(
4619 validate_nmtoken(s),
4620 1,
4621 "Expected '{}' to be a valid NMTOKEN",
4622 t
4623 );
4624 allocator::xmlFreeImpl(s as *mut c_void);
4625 }
4626 }
4627 }
4628
4629 #[test]
4630 fn test_validate_nmtoken_invalid() {
4631 unsafe {
4632 let s = c_str("foo bar");
4633 assert_eq!(validate_nmtoken(s), 0);
4634 allocator::xmlFreeImpl(s as *mut c_void);
4635 }
4636 }
4637
4638 #[test]
4639 fn test_validate_nmtokens_valid() {
4640 unsafe {
4641 let s = c_str("foo 123bar -baz");
4642 assert_eq!(validate_nmtokens(s), 1);
4643 allocator::xmlFreeImpl(s as *mut c_void);
4644 }
4645 }
4646
4647 #[test]
4650 fn test_validate_attribute_value_cdata() {
4651 unsafe {
4652 let s = c_str("anything goes here!@#$%^&*()");
4653 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4654 allocator::xmlFreeImpl(s as *mut c_void);
4655
4656 let empty = b"\0" as *const u8 as *const xmlChar;
4658 assert_eq!(
4659 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4660 1
4661 );
4662 }
4663 }
4664
4665 #[test]
4666 fn test_validate_attribute_value_id() {
4667 unsafe {
4668 let valid = c_str("myId");
4669 assert_eq!(
4670 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4671 1
4672 );
4673 allocator::xmlFreeImpl(valid as *mut c_void);
4674
4675 let invalid = c_str("123id");
4676 assert_eq!(
4677 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4678 0
4679 );
4680 allocator::xmlFreeImpl(invalid as *mut c_void);
4681 }
4682 }
4683
4684 #[test]
4685 fn test_validate_attribute_value_idref() {
4686 unsafe {
4687 let valid = c_str("someId");
4688 assert_eq!(
4689 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4690 1
4691 );
4692 allocator::xmlFreeImpl(valid as *mut c_void);
4693 }
4694 }
4695
4696 #[test]
4697 fn test_validate_attribute_value_idrefs() {
4698 unsafe {
4699 let valid = c_str("id1 id2 id3");
4700 assert_eq!(
4701 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4702 1
4703 );
4704 allocator::xmlFreeImpl(valid as *mut c_void);
4705
4706 let invalid = c_str("id1 123id");
4707 assert_eq!(
4708 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4709 0
4710 );
4711 allocator::xmlFreeImpl(invalid as *mut c_void);
4712 }
4713 }
4714
4715 #[test]
4716 fn test_validate_attribute_value_entity() {
4717 unsafe {
4718 let valid = c_str("myEntity");
4719 assert_eq!(
4720 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
4721 1
4722 );
4723 allocator::xmlFreeImpl(valid as *mut c_void);
4724 }
4725 }
4726
4727 #[test]
4728 fn test_validate_attribute_value_nmtoken() {
4729 unsafe {
4730 let valid = c_str("123abc");
4731 assert_eq!(
4732 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
4733 1
4734 );
4735 allocator::xmlFreeImpl(valid as *mut c_void);
4736
4737 let invalid = c_str("foo bar");
4738 assert_eq!(
4739 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
4740 0
4741 );
4742 allocator::xmlFreeImpl(invalid as *mut c_void);
4743 }
4744 }
4745
4746 #[test]
4747 fn test_validate_attribute_value_null() {
4748 unsafe {
4749 assert_eq!(
4753 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
4754 1
4755 );
4756 assert_eq!(
4757 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
4758 0
4759 );
4760 }
4761 }
4762
4763 #[test]
4766 fn test_validate_enumeration_valid() {
4767 unsafe {
4768 let ctxt = new_valid_ctxt();
4769 assert!(!ctxt.is_null());
4770
4771 let red = c_str("red");
4772 let green = c_str("green");
4773 let blue = c_str("blue");
4774
4775 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4776 (*e3).name = string::xml_strdup(blue);
4777 (*e3).next = ptr::null_mut();
4778
4779 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4780 (*e2).name = string::xml_strdup(green);
4781 (*e2).next = e3;
4782
4783 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4784 (*e1).name = string::xml_strdup(red);
4785 (*e1).next = e2;
4786
4787 let value = c_str("green");
4788 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
4789 assert_eq!((*ctxt).valid, 1);
4790
4791 allocator::xmlFreeImpl(value as *mut c_void);
4792 allocator::xmlFreeImpl(red as *mut c_void);
4793 allocator::xmlFreeImpl(green as *mut c_void);
4794 allocator::xmlFreeImpl(blue as *mut c_void);
4795 free_valid_ctxt(ctxt);
4796 }
4797 }
4798
4799 #[test]
4800 fn test_validate_enumeration_invalid() {
4801 unsafe {
4802 let ctxt = new_valid_ctxt();
4803 assert!(!ctxt.is_null());
4804
4805 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4806 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
4807 (*e1).next = ptr::null_mut();
4808
4809 let value = c_str("yellow");
4810 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
4811
4812 allocator::xmlFreeImpl(value as *mut c_void);
4813 free_valid_ctxt(ctxt);
4814 }
4815 }
4816
4817 #[test]
4820 fn test_validate_notation_use_valid() {
4821 unsafe {
4822 let (doc, dtd) = make_test_doc();
4823
4824 let notation_name = c_str("GIF");
4825 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
4826
4827 let ctxt = new_valid_ctxt();
4828 assert!(!ctxt.is_null());
4829
4830 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
4831
4832 free_valid_ctxt(ctxt);
4833 tree::free_doc(doc);
4834 }
4835 }
4836
4837 #[test]
4838 fn test_validate_notation_use_invalid() {
4839 unsafe {
4840 let (doc, _dtd) = make_test_doc();
4841
4842 let ctxt = new_valid_ctxt();
4843 assert!(!ctxt.is_null());
4844
4845 let notation_name = c_str("UNDECLARED");
4846 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
4847
4848 free_valid_ctxt(ctxt);
4849 allocator::xmlFreeImpl(notation_name as *mut c_void);
4850 tree::free_doc(doc);
4851 }
4852 }
4853
4854 #[test]
4857 fn test_new_free_valid_ctxt() {
4858 unsafe {
4859 let ctxt = new_valid_ctxt();
4860 assert!(!ctxt.is_null());
4861 assert_eq!((*ctxt).valid, 1);
4862 assert!((*ctxt).node.is_null());
4863 free_valid_ctxt(ctxt);
4864 }
4865 }
4866
4867 #[test]
4868 fn test_free_valid_ctxt_null() {
4869 unsafe {
4870 free_valid_ctxt(ptr::null_mut());
4871 }
4872 }
4873
4874 #[test]
4877 fn test_set_valid_errors_null() {
4878 unsafe {
4879 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
4880 }
4881 }
4882
4883 #[test]
4886 fn test_validate_element_no_dtd() {
4887 unsafe {
4888 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4889 assert!(!doc.is_null());
4890
4891 let root_name = c_str("root");
4892 let root = create_root_elem(doc, root_name);
4893
4894 let ctxt = new_valid_ctxt();
4895 assert!(!ctxt.is_null());
4896
4897 assert_eq!(validate_element(ctxt, doc, root), 1);
4899
4900 free_valid_ctxt(ctxt);
4901 tree::free_doc(doc);
4902 }
4903 }
4904
4905 #[test]
4906 fn test_validate_element_empty_valid() {
4907 unsafe {
4908 let (doc, dtd) = make_test_doc();
4909
4910 let root_name = c_str("root");
4911 add_elem_decl(
4912 dtd,
4913 root_name,
4914 XML_ELEMENT_TYPE_EMPTY as c_int,
4915 ptr::null_mut(),
4916 );
4917
4918 let root = create_root_elem(doc, root_name);
4919
4920 let ctxt = new_valid_ctxt();
4921 assert!(!ctxt.is_null());
4922
4923 assert_eq!(validate_element(ctxt, doc, root), 1);
4924
4925 free_valid_ctxt(ctxt);
4926 tree::free_doc(doc);
4927 }
4928 }
4929
4930 #[test]
4931 fn test_validate_element_undeclared() {
4932 unsafe {
4933 let (doc, _dtd) = make_test_doc();
4934
4935 let root_name = c_str("root");
4936 let root = create_root_elem(doc, root_name);
4937
4938 let ctxt = new_valid_ctxt();
4939 assert!(!ctxt.is_null());
4940
4941 assert_eq!(validate_element(ctxt, doc, root), 0);
4943
4944 free_valid_ctxt(ctxt);
4945 tree::free_doc(doc);
4946 }
4947 }
4948
4949 #[test]
4950 fn test_validate_element_with_content() {
4951 unsafe {
4952 let (doc, dtd) = make_test_doc();
4953
4954 let root_name = c_str("root");
4956 let child_name = c_str("child");
4957
4958 let child_content =
4960 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4961 assert!(!child_content.is_null());
4962 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4963
4964 add_elem_decl(
4965 dtd,
4966 root_name,
4967 XML_ELEMENT_TYPE_ELEMENT as c_int,
4968 child_content,
4969 );
4970 add_elem_decl(
4971 dtd,
4972 child_name,
4973 XML_ELEMENT_TYPE_EMPTY as c_int,
4974 ptr::null_mut(),
4975 );
4976
4977 let root = create_root_elem(doc, root_name);
4978 let _child = create_child_elem(root, child_name);
4979
4980 let ctxt = new_valid_ctxt();
4981 assert!(!ctxt.is_null());
4982
4983 assert_eq!(validate_element(ctxt, doc, root), 1);
4984
4985 free_valid_ctxt(ctxt);
4986 tree::free_doc(doc);
4987 }
4988 }
4989
4990 #[test]
4991 fn test_validate_element_invalid_content() {
4992 unsafe {
4993 let (doc, dtd) = make_test_doc();
4994
4995 let root_name = c_str("root");
4996 let child_name = c_str("child");
4997 let wrong_name = c_str("wrong");
4998
4999 let child_content =
5001 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5002 assert!(!child_content.is_null());
5003 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
5004
5005 add_elem_decl(
5006 dtd,
5007 root_name,
5008 XML_ELEMENT_TYPE_ELEMENT as c_int,
5009 child_content,
5010 );
5011 add_elem_decl(
5012 dtd,
5013 child_name,
5014 XML_ELEMENT_TYPE_EMPTY as c_int,
5015 ptr::null_mut(),
5016 );
5017 add_elem_decl(
5018 dtd,
5019 wrong_name,
5020 XML_ELEMENT_TYPE_EMPTY as c_int,
5021 ptr::null_mut(),
5022 );
5023
5024 let root = create_root_elem(doc, root_name);
5025 create_child_elem(root, wrong_name);
5027
5028 let ctxt = new_valid_ctxt();
5029 assert!(!ctxt.is_null());
5030
5031 assert_eq!(validate_element(ctxt, doc, root), 0);
5032
5033 free_valid_ctxt(ctxt);
5034 tree::free_doc(doc);
5035 }
5036 }
5037
5038 #[test]
5041 fn test_validate_root_match() {
5042 unsafe {
5043 let (doc, dtd) = make_test_doc();
5044
5045 let root_name = c_str("root");
5046 add_elem_decl(
5047 dtd,
5048 root_name,
5049 XML_ELEMENT_TYPE_EMPTY as c_int,
5050 ptr::null_mut(),
5051 );
5052 create_root_elem(doc, root_name);
5053
5054 let ctxt = new_valid_ctxt();
5055 assert!(!ctxt.is_null());
5056
5057 assert_eq!(validate_root(ctxt, doc), 1);
5058
5059 free_valid_ctxt(ctxt);
5060 tree::free_doc(doc);
5061 }
5062 }
5063
5064 #[test]
5065 fn test_validate_root_no_dtd() {
5066 unsafe {
5067 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5068 assert!(!doc.is_null());
5069
5070 let root_name = c_str("root");
5071 create_root_elem(doc, root_name);
5072
5073 let ctxt = new_valid_ctxt();
5074 assert!(!ctxt.is_null());
5075
5076 assert_eq!(validate_root(ctxt, doc), 1);
5078
5079 free_valid_ctxt(ctxt);
5080 tree::free_doc(doc);
5081 }
5082 }
5083
5084 #[test]
5087 fn test_validate_document_valid() {
5088 unsafe {
5089 let (doc, dtd) = make_test_doc();
5090
5091 let root_name = c_str("root");
5092 add_elem_decl(
5093 dtd,
5094 root_name,
5095 XML_ELEMENT_TYPE_EMPTY as c_int,
5096 ptr::null_mut(),
5097 );
5098 create_root_elem(doc, root_name);
5099
5100 let ctxt = new_valid_ctxt();
5101 assert!(!ctxt.is_null());
5102
5103 assert_eq!(validate_document(ctxt, doc), 1);
5104
5105 free_valid_ctxt(ctxt);
5106 tree::free_doc(doc);
5107 }
5108 }
5109
5110 #[test]
5111 fn test_validate_document_no_root() {
5112 unsafe {
5113 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5114 assert!(!doc.is_null());
5115
5116 let ctxt = new_valid_ctxt();
5117 assert!(!ctxt.is_null());
5118
5119 assert_eq!(validate_document(ctxt, doc), 0);
5120
5121 free_valid_ctxt(ctxt);
5122 tree::free_doc(doc);
5123 }
5124 }
5125
5126 #[test]
5129 fn test_validate_content_valid() {
5130 unsafe {
5131 let (doc, dtd) = make_test_doc();
5132
5133 let root_name = c_str("root");
5134 let child_name = c_str("child");
5135
5136 let child_content =
5137 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5138 assert!(!child_content.is_null());
5139
5140 add_elem_decl(
5141 dtd,
5142 root_name,
5143 XML_ELEMENT_TYPE_ELEMENT as c_int,
5144 child_content,
5145 );
5146 add_elem_decl(
5147 dtd,
5148 child_name,
5149 XML_ELEMENT_TYPE_EMPTY as c_int,
5150 ptr::null_mut(),
5151 );
5152
5153 let root = create_root_elem(doc, root_name);
5154 create_child_elem(root, child_name);
5155
5156 let ctxt = new_valid_ctxt();
5157 assert!(!ctxt.is_null());
5158
5159 assert_eq!(validate_content(ctxt, root, doc), 1);
5160
5161 free_valid_ctxt(ctxt);
5162 tree::free_doc(doc);
5163 }
5164 }
5165
5166 #[test]
5169 fn test_is_mixed_element() {
5170 unsafe {
5171 let (doc, dtd) = make_test_doc();
5172 let name = c_str("mixedElem");
5173 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5174
5175 assert_eq!(is_mixed_element(doc, name), 1);
5176
5177 let other = c_str("other");
5178 assert_eq!(is_mixed_element(doc, other), 0);
5179
5180 allocator::xmlFreeImpl(other as *mut c_void);
5181 tree::free_doc(doc);
5182 }
5183 }
5184
5185 #[test]
5186 fn test_is_empty_element() {
5187 unsafe {
5188 let (doc, dtd) = make_test_doc();
5189 let name = c_str("emptyElem");
5190 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5191
5192 assert_eq!(is_empty_element(doc, name), 1);
5193
5194 let other = c_str("other");
5195 assert_eq!(is_empty_element(doc, other), 0);
5196
5197 allocator::xmlFreeImpl(other as *mut c_void);
5198 tree::free_doc(doc);
5199 }
5200 }
5201
5202 #[test]
5203 fn test_is_mixed_element_no_dtd() {
5204 unsafe {
5205 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5206 assert!(!doc.is_null());
5207
5208 let name = c_str("foo");
5209 assert_eq!(is_mixed_element(doc, name), 0);
5210
5211 allocator::xmlFreeImpl(name as *mut c_void);
5212 tree::free_doc(doc);
5213 }
5214 }
5215
5216 #[test]
5217 fn test_is_empty_element_no_dtd() {
5218 unsafe {
5219 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5220 assert!(!doc.is_null());
5221
5222 let name = c_str("foo");
5223 assert_eq!(is_empty_element(doc, name), 0);
5224
5225 allocator::xmlFreeImpl(name as *mut c_void);
5226 tree::free_doc(doc);
5227 }
5228 }
5229
5230 #[test]
5233 fn test_validate_dtd_null() {
5234 unsafe {
5235 let ctxt = new_valid_ctxt();
5236 assert!(!ctxt.is_null());
5237 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5238 free_valid_ctxt(ctxt);
5239 }
5240 }
5241
5242 #[test]
5245 fn test_validate_element_null() {
5246 unsafe {
5247 let (doc, _dtd) = make_test_doc();
5248 let ctxt = new_valid_ctxt();
5249 assert!(!ctxt.is_null());
5250
5251 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5252
5253 free_valid_ctxt(ctxt);
5254 tree::free_doc(doc);
5255 }
5256 }
5257
5258 #[test]
5259 fn test_validate_document_null() {
5260 unsafe {
5261 let ctxt = new_valid_ctxt();
5262 assert!(!ctxt.is_null());
5263
5264 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5265 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5266
5267 free_valid_ctxt(ctxt);
5268 }
5269 }
5270
5271 #[test]
5272 fn test_validate_document_final_null() {
5273 unsafe {
5274 let ctxt = new_valid_ctxt();
5275 assert!(!ctxt.is_null());
5276
5277 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5278 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5279
5280 free_valid_ctxt(ctxt);
5281 }
5282 }
5283
5284 #[test]
5285 fn test_validate_attribute_decl_null() {
5286 unsafe {
5287 let ctxt = new_valid_ctxt();
5288 assert!(!ctxt.is_null());
5289
5290 assert_eq!(
5291 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()),
5292 0
5293 );
5294
5295 free_valid_ctxt(ctxt);
5296 }
5297 }
5298
5299 #[test]
5300 fn test_validate_content_null() {
5301 unsafe {
5302 let ctxt = new_valid_ctxt();
5303 assert!(!ctxt.is_null());
5304
5305 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5306
5307 free_valid_ctxt(ctxt);
5308 }
5309 }
5310
5311 #[test]
5312 fn test_validate_root_null() {
5313 unsafe {
5314 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5315 }
5316 }
5317
5318 #[test]
5319 fn test_validate_enumeration_null() {
5320 unsafe {
5321 let ctxt = new_valid_ctxt();
5322 assert!(!ctxt.is_null());
5323
5324 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5325
5326 free_valid_ctxt(ctxt);
5327 }
5328 }
5329
5330 #[test]
5331 fn test_validate_notation_use_null() {
5332 unsafe {
5333 let ctxt = new_valid_ctxt();
5334 assert!(!ctxt.is_null());
5335
5336 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5337
5338 free_valid_ctxt(ctxt);
5339 }
5340 }
5341
5342 #[test]
5343 fn test_validate_name_start_characters() {
5344 unsafe {
5345 let name = c_str("\u{C0}lph\u{E0}");
5347 assert_eq!(validate_name(name), 1);
5348 allocator::xmlFreeImpl(name as *mut c_void);
5349 }
5350 }
5351
5352 #[test]
5353 fn test_validate_names_single() {
5354 unsafe {
5355 let s = c_str("singleName");
5356 assert_eq!(validate_names(s), 1);
5357 allocator::xmlFreeImpl(s as *mut c_void);
5358 }
5359 }
5360
5361 #[test]
5362 fn test_validate_nmtokens_single() {
5363 unsafe {
5364 let s = c_str("123abc");
5365 assert_eq!(validate_nmtokens(s), 1);
5366 allocator::xmlFreeImpl(s as *mut c_void);
5367 }
5368 }
5369
5370 #[test]
5371 fn test_validate_nmtokens_invalid() {
5372 unsafe {
5373 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5376
5377 let s2 = c_str("foo@bar");
5379 assert_eq!(validate_nmtokens(s2), 0);
5380 allocator::xmlFreeImpl(s2 as *mut c_void);
5381 }
5382 }
5383
5384 #[test]
5385 fn test_validate_attribute_value_empty_non_cdata() {
5386 unsafe {
5387 let empty = b"\0" as *const u8 as *const xmlChar;
5388 assert_eq!(
5389 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5390 0
5391 );
5392 assert_eq!(
5393 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5394 0
5395 );
5396 assert_eq!(
5397 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5398 0
5399 );
5400 }
5401 }
5402
5403 #[test]
5404 fn test_validate_attribute_value_unknown_type() {
5405 unsafe {
5406 let s = c_str("test");
5409 assert_eq!(validate_attribute_value(999, s), 1);
5410 allocator::xmlFreeImpl(s as *mut c_void);
5411 }
5412 }
5413
5414 #[test]
5415 fn test_validate_element_any_content() {
5416 unsafe {
5417 let (doc, dtd) = make_test_doc();
5418
5419 let root_name = c_str("root");
5420 add_elem_decl(
5421 dtd,
5422 root_name,
5423 XML_ELEMENT_TYPE_ANY as c_int,
5424 ptr::null_mut(),
5425 );
5426
5427 let child_name = c_str("child");
5428 add_elem_decl(
5429 dtd,
5430 child_name,
5431 XML_ELEMENT_TYPE_EMPTY as c_int,
5432 ptr::null_mut(),
5433 );
5434
5435 let root = create_root_elem(doc, root_name);
5436 create_child_elem(root, child_name);
5437
5438 let ctxt = new_valid_ctxt();
5439 assert!(!ctxt.is_null());
5440
5441 assert_eq!(validate_element(ctxt, doc, root), 1);
5443
5444 free_valid_ctxt(ctxt);
5445 tree::free_doc(doc);
5446 }
5447 }
5448
5449 #[test]
5450 fn test_validate_element_empty_with_child() {
5451 unsafe {
5452 let (doc, dtd) = make_test_doc();
5453
5454 let root_name = c_str("root");
5455 add_elem_decl(
5456 dtd,
5457 root_name,
5458 XML_ELEMENT_TYPE_EMPTY as c_int,
5459 ptr::null_mut(),
5460 );
5461
5462 let child_name = c_str("child");
5463 add_elem_decl(
5464 dtd,
5465 child_name,
5466 XML_ELEMENT_TYPE_EMPTY as c_int,
5467 ptr::null_mut(),
5468 );
5469
5470 let root = create_root_elem(doc, root_name);
5471 create_child_elem(root, child_name);
5472
5473 let ctxt = new_valid_ctxt();
5474 assert!(!ctxt.is_null());
5475
5476 assert_eq!(validate_element(ctxt, doc, root), 0);
5478
5479 free_valid_ctxt(ctxt);
5480 tree::free_doc(doc);
5481 }
5482 }
5483
5484 #[test]
5485 fn test_validate_dtd_final_null() {
5486 unsafe {
5487 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
5488 }
5489 }
5490}