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 local = string::split_qname3(qname, &mut plen);
3808 let mut cur = cont;
3809 if local.is_null() {
3810 while !cur.is_null() {
3811 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3812 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
3813 return 1;
3814 }
3815 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3816 && !(*cur).c1.is_null()
3817 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3818 {
3819 if (*(*cur).c1).prefix.is_null()
3820 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3821 {
3822 return 1;
3823 }
3824 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3825 || (*cur).c1.is_null()
3826 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3827 {
3828 vctxt_error(
3829 ctxt,
3830 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3831 );
3832 break;
3833 }
3834 cur = (*cur).c2;
3835 }
3836 } else {
3837 while !cur.is_null() {
3838 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3839 if !(*cur).prefix.is_null()
3840 && prefix_matches((*cur).prefix, qname, plen)
3841 && string::xml_strcmp((*cur).name, local) == 0
3842 {
3843 return 1;
3844 }
3845 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3846 && !(*cur).c1.is_null()
3847 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3848 {
3849 if !(*(*cur).c1).prefix.is_null()
3850 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3851 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3852 {
3853 return 1;
3854 }
3855 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3856 || (*cur).c1.is_null()
3857 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3858 {
3859 vctxt_error(
3860 ctxt,
3861 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3862 );
3863 break;
3864 }
3865 cur = (*cur).c2;
3866 }
3867 }
3868 0
3869 }
3870}
3871
3872unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
3875 unsafe {
3876 let p = string::xmlstr_to_bytes(prefix);
3877 let q = string::xmlstr_to_bytes(qname);
3878 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
3879 }
3880}
3881
3882#[derive(Debug)]
3891#[repr(C)]
3892pub struct ContentModelNfa {
3893 transitions: Vec<(u32, *const xmlChar, u32)>,
3895 start: u32,
3897 accept: Vec<u32>,
3899}
3900
3901#[derive(Debug)]
3903#[repr(C)]
3904pub struct ContentModelExec {
3905 nfa: *mut ContentModelNfa,
3907 current: Vec<u32>,
3909}
3910
3911struct NfaBuilder {
3913 transitions: Vec<(u32, *const xmlChar, u32)>,
3914 n_states: u32,
3915}
3916
3917impl NfaBuilder {
3918 const fn new() -> Self {
3919 NfaBuilder {
3920 transitions: Vec::new(),
3921 n_states: 0,
3922 }
3923 }
3924 const fn new_state(&mut self) -> u32 {
3925 let s = self.n_states;
3926 self.n_states += 1;
3927 s
3928 }
3929 fn eps(&mut self, from: u32, to: u32) {
3930 self.transitions.push((from, ptr::null(), to));
3931 }
3932 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
3933 self.transitions.push((from, name, to));
3934 }
3935}
3936
3937unsafe fn compile_content_sub(
3942 b: &mut NfaBuilder,
3943 model: *mut _xmlElementContent,
3944) -> (u32, Vec<u32>) {
3945 if model.is_null() {
3946 let s = b.new_state();
3947 return (s, vec![s]);
3948 }
3949 let m = unsafe { &*model };
3950 let (mut in_s, outs) = match m.type_ as u32 {
3951 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
3952 let s = b.new_state();
3953 let to = b.new_state();
3954 b.name_trans(s, m.name, to);
3955 (s, vec![to])
3956 }
3957 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
3958 let (in1, out1) = compile_content_sub(b, m.c1);
3959 let (in2, out2) = compile_content_sub(b, m.c2);
3960 for &o in &out1 {
3961 b.eps(o, in2);
3962 }
3963 (in1, out2)
3964 }
3965 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
3966 let (in1, out1) = compile_content_sub(b, m.c1);
3967 let (in2, out2) = compile_content_sub(b, m.c2);
3968 let s = b.new_state();
3969 b.eps(s, in1);
3970 b.eps(s, in2);
3971 let mut all = out1;
3972 all.extend(out2);
3973 (s, all)
3974 }
3975 _ => {
3980 let s = b.new_state();
3981 (s, vec![s])
3982 }
3983 };
3984 match m.ocur as u32 {
3985 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
3986 let s = b.new_state();
3987 b.eps(s, in_s);
3988 for &o2 in &outs {
3989 b.eps(s, o2);
3990 }
3991 in_s = s;
3992 }
3993 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
3994 let s = b.new_state();
3995 b.eps(s, in_s);
3996 for &o2 in &outs {
3997 b.eps(s, o2);
3998 b.eps(o2, s);
3999 }
4000 in_s = s;
4001 }
4002 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
4003 let s = b.new_state();
4004 b.eps(s, in_s);
4005 for &o2 in &outs {
4006 b.eps(o2, s);
4007 }
4008 in_s = s;
4009 }
4010 _ => {}
4011 }
4012 (in_s, outs)
4013}
4014
4015unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
4017 if model.is_null() {
4018 return false;
4019 }
4020 unsafe {
4021 let m = &*model;
4022 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
4023 return true;
4024 }
4025 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
4026 }
4027}
4028
4029unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
4035 unsafe {
4036 if content.is_null() {
4037 return ptr::null_mut();
4038 }
4039 let mut b = NfaBuilder::new();
4040 let (start, outs) = compile_content_sub(&mut b, content);
4041 let nfa = Box::new(ContentModelNfa {
4042 transitions: b.transitions,
4043 start,
4044 accept: outs,
4045 });
4046 Box::into_raw(nfa)
4047 }
4048}
4049
4050pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
4056 if nfa.is_null() {
4057 return;
4058 }
4059 unsafe {
4060 ptr::drop_in_place(nfa);
4061 allocator::xmlFreeImpl(nfa as *mut c_void);
4062 }
4063}
4064
4065unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4067 let mut out = states.to_vec();
4068 let mut stack = states.to_vec();
4069 while let Some(s) = stack.pop() {
4070 for &(from, name, to) in &nfa.transitions {
4071 if from == s && name.is_null() && !out.contains(&to) {
4072 out.push(to);
4073 stack.push(to);
4074 }
4075 }
4076 }
4077 out.sort_unstable();
4078 out.dedup();
4079 out
4080}
4081
4082unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4084 unsafe {
4085 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4086 if exec.is_null() {
4087 return ptr::null_mut();
4088 }
4089 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4090 ptr::write(&mut (*exec).nfa, nfa);
4091 ptr::write(&mut (*exec).current, cur);
4092 exec
4093 }
4094}
4095
4096unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4098 if exec.is_null() {
4099 return;
4100 }
4101 unsafe {
4102 ptr::drop_in_place(&mut (*exec).current);
4103 allocator::xmlFreeImpl(exec as *mut c_void);
4104 }
4105}
4106
4107unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4112 unsafe {
4113 if exec.is_null() {
4114 return -1;
4115 }
4116 let nfa = &*(*exec).nfa;
4117 if value.is_null() {
4118 let cur = eps_closure(nfa, &(*exec).current);
4119 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4120 1
4121 } else {
4122 0
4123 };
4124 }
4125 let mut next: Vec<u32> = Vec::new();
4126 for &s in &(*exec).current {
4127 for &(from, name, to) in &nfa.transitions {
4128 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4129 next.push(to);
4130 }
4131 }
4132 }
4133 next.sort_unstable();
4134 next.dedup();
4135 if next.is_empty() {
4136 return -1;
4137 }
4138 let closed = eps_closure(nfa, &next);
4139 (*exec).current = closed;
4140 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4141 1
4142 } else {
4143 0
4144 }
4145 }
4146}
4147
4148unsafe fn vstate_vpush(
4150 ctxt: *mut _xmlValidCtxt,
4151 elem_decl: *mut _xmlElement,
4152 node: *mut _xmlNode,
4153) -> c_int {
4154 unsafe {
4155 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4156 let new_max = if (*ctxt).vstateMax == 0 {
4157 10
4158 } else {
4159 (*ctxt).vstateMax * 2
4160 };
4161 let new_tab = allocator::xmlReallocImpl(
4162 (*ctxt).vstateTab,
4163 (new_max as usize) * size_of::<ValidState>(),
4164 ) as *mut ValidState;
4165 if new_tab.is_null() {
4166 vctxt_error(
4167 ctxt,
4168 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4169 );
4170 return -1;
4171 }
4172 (*ctxt).vstateTab = new_tab as *mut c_void;
4173 (*ctxt).vstateMax = new_max;
4174 }
4175 let idx = (*ctxt).vstateNr as usize;
4176 let tab = (*ctxt).vstateTab as *mut ValidState;
4177 (*tab.add(idx)).elem_decl = elem_decl;
4178 (*tab.add(idx)).node = node;
4179 (*tab.add(idx)).exec = ptr::null_mut();
4180 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4181 if (*elem_decl).cont_model.is_null() {
4182 validate_build_content_model(ctxt, elem_decl);
4183 }
4184 if !(*elem_decl).cont_model.is_null() {
4185 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4186 if exec.is_null() {
4187 vctxt_error(
4188 ctxt,
4189 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4190 );
4191 return -1;
4192 }
4193 (*tab.add(idx)).exec = exec;
4194 } else {
4195 let msg = format!(
4196 "Failed to build content model regexp for {}\0",
4197 string::xmlstr_to_string((*elem_decl).name)
4198 );
4199 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4200 }
4201 }
4202 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4203 (*ctxt).vstateNr += 1;
4204 0
4205 }
4206}
4207
4208unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4210 unsafe {
4211 if (*ctxt).vstateNr < 1 {
4212 return -1;
4213 }
4214 (*ctxt).vstateNr -= 1;
4215 let idx = (*ctxt).vstateNr as usize;
4216 let tab = (*ctxt).vstateTab as *mut ValidState;
4217 let elem_decl = (*tab.add(idx)).elem_decl;
4218 (*tab.add(idx)).elem_decl = ptr::null_mut();
4219 (*tab.add(idx)).node = ptr::null_mut();
4220 if !elem_decl.is_null()
4221 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4222 && !(*tab.add(idx)).exec.is_null()
4223 {
4224 free_content_exec((*tab.add(idx)).exec);
4225 }
4226 (*tab.add(idx)).exec = ptr::null_mut();
4227 if (*ctxt).vstateNr >= 1 {
4228 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4229 } else {
4230 (*ctxt).vstate = ptr::null_mut();
4231 }
4232 0
4233 }
4234}
4235
4236pub unsafe fn validate_build_content_model(
4244 ctxt: *mut _xmlValidCtxt,
4245 elem: *mut _xmlElement,
4246) -> c_int {
4247 unsafe {
4248 if ctxt.is_null() {
4249 return 0;
4250 }
4251 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4252 return 0;
4253 }
4254 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4255 return 1;
4256 }
4257 if !(*elem).cont_model.is_null() {
4258 return 1;
4259 }
4260 if (*elem).content.is_null() {
4261 return 1;
4262 }
4263 if content_has_pcdata((*elem).content) {
4264 let msg = format!(
4265 "Found PCDATA in content model of {}\0",
4266 string::xmlstr_to_string((*elem).name)
4267 );
4268 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4269 return 0;
4270 }
4271 let nfa = build_content_nfa((*elem).content);
4272 if nfa.is_null() {
4273 vctxt_error(
4274 ctxt,
4275 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4276 as *const c_char,
4277 );
4278 return 0;
4279 }
4280 (*elem).cont_model = nfa as *mut c_void;
4281 1
4282 }
4283}
4284
4285pub unsafe fn validate_push_element(
4293 ctxt: *mut _xmlValidCtxt,
4294 doc: *mut _xmlDoc,
4295 elem: *mut _xmlNode,
4296 qname: *const xmlChar,
4297) -> c_int {
4298 unsafe {
4299 let mut ret = 1;
4300 if ctxt.is_null() {
4301 return 0;
4302 }
4303 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4304 let state = (*ctxt).vstate as *mut ValidState;
4305 let elem_decl = (*state).elem_decl;
4306 if !elem_decl.is_null() {
4307 match (*elem_decl).etype as u32 {
4308 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4309 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4310 let msg = format!(
4311 "Element {} was declared EMPTY this one has content\0",
4312 string::xmlstr_to_string((*(*state).node).name)
4313 );
4314 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4315 ret = 0;
4316 }
4317 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4318 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4319 if !(*elem_decl).content.is_null()
4320 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4321 {
4322 let msg = format!(
4323 "Element {} was declared #PCDATA but contains non text nodes\0",
4324 string::xmlstr_to_string((*(*state).node).name)
4325 );
4326 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4327 ret = 0;
4328 } else {
4329 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4330 if ret != 1 {
4331 let msg = format!(
4332 "Element {} is not declared in {} list of possible children\0",
4333 string::xmlstr_to_string(qname),
4334 string::xmlstr_to_string((*(*state).node).name)
4335 );
4336 vctxt_error_node(
4337 ctxt,
4338 (*state).node,
4339 msg.as_ptr() as *const c_char,
4340 );
4341 }
4342 }
4343 }
4344 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 && !(*state).exec.is_null() => {
4345 ret = content_exec_push((*state).exec, qname);
4346 if ret < 0 {
4347 let msg = format!(
4348 "Element {} content does not follow the DTD, Misplaced {}\0",
4349 string::xmlstr_to_string((*(*state).node).name),
4350 string::xmlstr_to_string(qname)
4351 );
4352 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4353 ret = 0;
4354 } else {
4355 ret = 1;
4356 }
4357 }
4358 _ => {}
4359 }
4360 }
4361 }
4362 let mut extsubset = 0;
4363 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4364 let _ = vstate_vpush(ctxt, e_decl, elem);
4366 ret
4367 }
4368}
4369
4370pub unsafe fn validate_push_cdata(
4377 ctxt: *mut _xmlValidCtxt,
4378 data: *const xmlChar,
4379 len: c_int,
4380) -> c_int {
4381 unsafe {
4382 let mut ret = 1;
4383 if ctxt.is_null() {
4384 return 0;
4385 }
4386 if len <= 0 {
4387 return 1;
4388 }
4389 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4390 let state = (*ctxt).vstate as *mut ValidState;
4391 let elem_decl = (*state).elem_decl;
4392 if !elem_decl.is_null() {
4393 match (*elem_decl).etype as u32 {
4394 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4395 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4396 let msg = format!(
4397 "Element {} was declared EMPTY this one has content\0",
4398 string::xmlstr_to_string((*(*state).node).name)
4399 );
4400 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4401 ret = 0;
4402 }
4403 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4404 }
4405 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4406 let bytes = core::slice::from_raw_parts(data, len as usize);
4407 for &b in bytes {
4408 if !is_blank_byte(b) {
4409 let msg = format!(
4410 "Element {} content does not follow the DTD, Text not allowed\0",
4411 string::xmlstr_to_string((*(*state).node).name)
4412 );
4413 vctxt_error_node(
4414 ctxt,
4415 (*state).node,
4416 msg.as_ptr() as *const c_char,
4417 );
4418 ret = 0;
4419 break;
4420 }
4421 }
4422 }
4423 _ => {}
4424 }
4425 }
4426 }
4427 ret
4428 }
4429}
4430
4431pub unsafe fn validate_pop_element(
4438 ctxt: *mut _xmlValidCtxt,
4439 _doc: *mut _xmlDoc,
4440 _elem: *mut _xmlNode,
4441 _qname: *const xmlChar,
4442) -> c_int {
4443 unsafe {
4444 let mut ret = 1;
4445 if ctxt.is_null() {
4446 return 0;
4447 }
4448 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4449 let state = (*ctxt).vstate as *mut ValidState;
4450 let elem_decl = (*state).elem_decl;
4451 if !elem_decl.is_null()
4452 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4453 && !(*state).exec.is_null()
4454 {
4455 ret = content_exec_push((*state).exec, ptr::null());
4456 if ret <= 0 {
4457 let msg = format!(
4458 "Element {} content does not follow the DTD, Expecting more children\0",
4459 string::xmlstr_to_string((*(*state).node).name)
4460 );
4461 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4462 ret = 0;
4463 } else {
4464 ret = 1;
4465 }
4466 }
4467 let _ = vstate_vpop(ctxt);
4468 }
4469 ret
4470 }
4471}
4472
4473#[cfg(test)]
4478mod tests {
4479 use super::*;
4480 use crate::abi::allocator;
4481
4482 use crate::xml::dtd;
4483 use crate::xml::tree;
4484
4485 unsafe fn c_str(s: &str) -> *const xmlChar {
4489 let bytes = s.as_bytes();
4490 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4491 assert!(!ptr.is_null());
4492 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4493 *ptr.add(bytes.len()) = 0;
4494 ptr
4495 }
4496
4497 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4499 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4500 assert!(!doc.is_null());
4501
4502 let name = c_str("root");
4503 let ext_id = c_str("--//Test//DTD//EN");
4504 let sys_id = c_str("test.dtd");
4505 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4506 assert!(!dtd.is_null());
4507
4508 (doc, dtd)
4509 }
4510
4511 #[allow(unused)]
4513 unsafe fn add_elem_decl(
4514 dtd: *mut _xmlDtd,
4515 name: *const xmlChar,
4516 elem_type: c_int,
4517 content: *mut _xmlElementContent,
4518 ) -> *mut _xmlElement {
4519 dtd::add_element_decl(dtd, name, elem_type, content)
4520 }
4521
4522 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4524 let node = tree::new_node(ptr::null_mut(), name);
4525 assert!(!node.is_null());
4526 tree::add_child(doc as *mut _xmlNode, node);
4527 node
4528 }
4529
4530 #[allow(unused)]
4532 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4533 let node = tree::new_node(ptr::null_mut(), name);
4534 assert!(!node.is_null());
4535 tree::add_child(parent, node);
4536 node
4537 }
4538
4539 #[test]
4542 fn test_validate_name_null() {
4543 unsafe {
4544 assert_eq!(validate_name(ptr::null()), 0);
4545 }
4546 }
4547
4548 #[test]
4549 fn test_validate_name_empty() {
4550 unsafe {
4551 let s = b"\0" as *const u8 as *const xmlChar;
4552 assert_eq!(validate_name(s), 0);
4553 }
4554 }
4555
4556 #[test]
4557 fn test_validate_name_valid() {
4558 unsafe {
4559 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4560 for t in &tests {
4561 let s = c_str(t);
4562 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4563 allocator::xmlFreeImpl(s as *mut c_void);
4564 }
4565 }
4566 }
4567
4568 #[test]
4569 fn test_validate_name_invalid() {
4570 unsafe {
4571 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4572 for t in &tests {
4573 let s = c_str(t);
4574 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4575 allocator::xmlFreeImpl(s as *mut c_void);
4576 }
4577 }
4578 }
4579
4580 #[test]
4581 fn test_validate_names_valid() {
4582 unsafe {
4583 let s = c_str("foo bar baz");
4584 assert_eq!(validate_names(s), 1);
4585 allocator::xmlFreeImpl(s as *mut c_void);
4586 }
4587 }
4588
4589 #[test]
4590 fn test_validate_names_invalid() {
4591 unsafe {
4592 let s = c_str("foo 123bar baz");
4593 assert_eq!(validate_names(s), 0);
4594 allocator::xmlFreeImpl(s as *mut c_void);
4595 }
4596 }
4597
4598 #[test]
4601 fn test_validate_nmtoken_null() {
4602 unsafe {
4603 assert_eq!(validate_nmtoken(ptr::null()), 0);
4604 }
4605 }
4606
4607 #[test]
4608 fn test_validate_nmtoken_valid() {
4609 unsafe {
4610 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4611 for t in &tests {
4612 let s = c_str(t);
4613 assert_eq!(
4614 validate_nmtoken(s),
4615 1,
4616 "Expected '{}' to be a valid NMTOKEN",
4617 t
4618 );
4619 allocator::xmlFreeImpl(s as *mut c_void);
4620 }
4621 }
4622 }
4623
4624 #[test]
4625 fn test_validate_nmtoken_invalid() {
4626 unsafe {
4627 let s = c_str("foo bar");
4628 assert_eq!(validate_nmtoken(s), 0);
4629 allocator::xmlFreeImpl(s as *mut c_void);
4630 }
4631 }
4632
4633 #[test]
4634 fn test_validate_nmtokens_valid() {
4635 unsafe {
4636 let s = c_str("foo 123bar -baz");
4637 assert_eq!(validate_nmtokens(s), 1);
4638 allocator::xmlFreeImpl(s as *mut c_void);
4639 }
4640 }
4641
4642 #[test]
4645 fn test_validate_attribute_value_cdata() {
4646 unsafe {
4647 let s = c_str("anything goes here!@#$%^&*()");
4648 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4649 allocator::xmlFreeImpl(s as *mut c_void);
4650
4651 let empty = b"\0" as *const u8 as *const xmlChar;
4653 assert_eq!(
4654 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4655 1
4656 );
4657 }
4658 }
4659
4660 #[test]
4661 fn test_validate_attribute_value_id() {
4662 unsafe {
4663 let valid = c_str("myId");
4664 assert_eq!(
4665 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4666 1
4667 );
4668 allocator::xmlFreeImpl(valid as *mut c_void);
4669
4670 let invalid = c_str("123id");
4671 assert_eq!(
4672 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4673 0
4674 );
4675 allocator::xmlFreeImpl(invalid as *mut c_void);
4676 }
4677 }
4678
4679 #[test]
4680 fn test_validate_attribute_value_idref() {
4681 unsafe {
4682 let valid = c_str("someId");
4683 assert_eq!(
4684 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4685 1
4686 );
4687 allocator::xmlFreeImpl(valid as *mut c_void);
4688 }
4689 }
4690
4691 #[test]
4692 fn test_validate_attribute_value_idrefs() {
4693 unsafe {
4694 let valid = c_str("id1 id2 id3");
4695 assert_eq!(
4696 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4697 1
4698 );
4699 allocator::xmlFreeImpl(valid as *mut c_void);
4700
4701 let invalid = c_str("id1 123id");
4702 assert_eq!(
4703 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4704 0
4705 );
4706 allocator::xmlFreeImpl(invalid as *mut c_void);
4707 }
4708 }
4709
4710 #[test]
4711 fn test_validate_attribute_value_entity() {
4712 unsafe {
4713 let valid = c_str("myEntity");
4714 assert_eq!(
4715 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
4716 1
4717 );
4718 allocator::xmlFreeImpl(valid as *mut c_void);
4719 }
4720 }
4721
4722 #[test]
4723 fn test_validate_attribute_value_nmtoken() {
4724 unsafe {
4725 let valid = c_str("123abc");
4726 assert_eq!(
4727 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
4728 1
4729 );
4730 allocator::xmlFreeImpl(valid as *mut c_void);
4731
4732 let invalid = c_str("foo bar");
4733 assert_eq!(
4734 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
4735 0
4736 );
4737 allocator::xmlFreeImpl(invalid as *mut c_void);
4738 }
4739 }
4740
4741 #[test]
4742 fn test_validate_attribute_value_null() {
4743 unsafe {
4744 assert_eq!(
4748 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
4749 1
4750 );
4751 assert_eq!(
4752 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
4753 0
4754 );
4755 }
4756 }
4757
4758 #[test]
4761 fn test_validate_enumeration_valid() {
4762 unsafe {
4763 let ctxt = new_valid_ctxt();
4764 assert!(!ctxt.is_null());
4765
4766 let red = c_str("red");
4767 let green = c_str("green");
4768 let blue = c_str("blue");
4769
4770 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4771 (*e3).name = string::xml_strdup(blue);
4772 (*e3).next = ptr::null_mut();
4773
4774 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4775 (*e2).name = string::xml_strdup(green);
4776 (*e2).next = e3;
4777
4778 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4779 (*e1).name = string::xml_strdup(red);
4780 (*e1).next = e2;
4781
4782 let value = c_str("green");
4783 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
4784 assert_eq!((*ctxt).valid, 1);
4785
4786 allocator::xmlFreeImpl(value as *mut c_void);
4787 allocator::xmlFreeImpl(red as *mut c_void);
4788 allocator::xmlFreeImpl(green as *mut c_void);
4789 allocator::xmlFreeImpl(blue as *mut c_void);
4790 free_valid_ctxt(ctxt);
4791 }
4792 }
4793
4794 #[test]
4795 fn test_validate_enumeration_invalid() {
4796 unsafe {
4797 let ctxt = new_valid_ctxt();
4798 assert!(!ctxt.is_null());
4799
4800 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4801 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
4802 (*e1).next = ptr::null_mut();
4803
4804 let value = c_str("yellow");
4805 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
4806
4807 allocator::xmlFreeImpl(value as *mut c_void);
4808 free_valid_ctxt(ctxt);
4809 }
4810 }
4811
4812 #[test]
4815 fn test_validate_notation_use_valid() {
4816 unsafe {
4817 let (doc, dtd) = make_test_doc();
4818
4819 let notation_name = c_str("GIF");
4820 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
4821
4822 let ctxt = new_valid_ctxt();
4823 assert!(!ctxt.is_null());
4824
4825 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
4826
4827 free_valid_ctxt(ctxt);
4828 tree::free_doc(doc);
4829 }
4830 }
4831
4832 #[test]
4833 fn test_validate_notation_use_invalid() {
4834 unsafe {
4835 let (doc, _dtd) = make_test_doc();
4836
4837 let ctxt = new_valid_ctxt();
4838 assert!(!ctxt.is_null());
4839
4840 let notation_name = c_str("UNDECLARED");
4841 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
4842
4843 free_valid_ctxt(ctxt);
4844 allocator::xmlFreeImpl(notation_name as *mut c_void);
4845 tree::free_doc(doc);
4846 }
4847 }
4848
4849 #[test]
4852 fn test_new_free_valid_ctxt() {
4853 unsafe {
4854 let ctxt = new_valid_ctxt();
4855 assert!(!ctxt.is_null());
4856 assert_eq!((*ctxt).valid, 1);
4857 assert!((*ctxt).node.is_null());
4858 free_valid_ctxt(ctxt);
4859 }
4860 }
4861
4862 #[test]
4863 fn test_free_valid_ctxt_null() {
4864 unsafe {
4865 free_valid_ctxt(ptr::null_mut());
4866 }
4867 }
4868
4869 #[test]
4872 fn test_set_valid_errors_null() {
4873 unsafe {
4874 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
4875 }
4876 }
4877
4878 #[test]
4881 fn test_validate_element_no_dtd() {
4882 unsafe {
4883 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4884 assert!(!doc.is_null());
4885
4886 let root_name = c_str("root");
4887 let root = create_root_elem(doc, root_name);
4888
4889 let ctxt = new_valid_ctxt();
4890 assert!(!ctxt.is_null());
4891
4892 assert_eq!(validate_element(ctxt, doc, root), 1);
4894
4895 free_valid_ctxt(ctxt);
4896 tree::free_doc(doc);
4897 }
4898 }
4899
4900 #[test]
4901 fn test_validate_element_empty_valid() {
4902 unsafe {
4903 let (doc, dtd) = make_test_doc();
4904
4905 let root_name = c_str("root");
4906 add_elem_decl(
4907 dtd,
4908 root_name,
4909 XML_ELEMENT_TYPE_EMPTY as c_int,
4910 ptr::null_mut(),
4911 );
4912
4913 let root = create_root_elem(doc, root_name);
4914
4915 let ctxt = new_valid_ctxt();
4916 assert!(!ctxt.is_null());
4917
4918 assert_eq!(validate_element(ctxt, doc, root), 1);
4919
4920 free_valid_ctxt(ctxt);
4921 tree::free_doc(doc);
4922 }
4923 }
4924
4925 #[test]
4926 fn test_validate_element_undeclared() {
4927 unsafe {
4928 let (doc, _dtd) = make_test_doc();
4929
4930 let root_name = c_str("root");
4931 let root = create_root_elem(doc, root_name);
4932
4933 let ctxt = new_valid_ctxt();
4934 assert!(!ctxt.is_null());
4935
4936 assert_eq!(validate_element(ctxt, doc, root), 0);
4938
4939 free_valid_ctxt(ctxt);
4940 tree::free_doc(doc);
4941 }
4942 }
4943
4944 #[test]
4945 fn test_validate_element_with_content() {
4946 unsafe {
4947 let (doc, dtd) = make_test_doc();
4948
4949 let root_name = c_str("root");
4951 let child_name = c_str("child");
4952
4953 let child_content =
4955 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4956 assert!(!child_content.is_null());
4957 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4958
4959 add_elem_decl(
4960 dtd,
4961 root_name,
4962 XML_ELEMENT_TYPE_ELEMENT as c_int,
4963 child_content,
4964 );
4965 add_elem_decl(
4966 dtd,
4967 child_name,
4968 XML_ELEMENT_TYPE_EMPTY as c_int,
4969 ptr::null_mut(),
4970 );
4971
4972 let root = create_root_elem(doc, root_name);
4973 let _child = create_child_elem(root, child_name);
4974
4975 let ctxt = new_valid_ctxt();
4976 assert!(!ctxt.is_null());
4977
4978 assert_eq!(validate_element(ctxt, doc, root), 1);
4979
4980 free_valid_ctxt(ctxt);
4981 tree::free_doc(doc);
4982 }
4983 }
4984
4985 #[test]
4986 fn test_validate_element_invalid_content() {
4987 unsafe {
4988 let (doc, dtd) = make_test_doc();
4989
4990 let root_name = c_str("root");
4991 let child_name = c_str("child");
4992 let wrong_name = c_str("wrong");
4993
4994 let child_content =
4996 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4997 assert!(!child_content.is_null());
4998 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4999
5000 add_elem_decl(
5001 dtd,
5002 root_name,
5003 XML_ELEMENT_TYPE_ELEMENT as c_int,
5004 child_content,
5005 );
5006 add_elem_decl(
5007 dtd,
5008 child_name,
5009 XML_ELEMENT_TYPE_EMPTY as c_int,
5010 ptr::null_mut(),
5011 );
5012 add_elem_decl(
5013 dtd,
5014 wrong_name,
5015 XML_ELEMENT_TYPE_EMPTY as c_int,
5016 ptr::null_mut(),
5017 );
5018
5019 let root = create_root_elem(doc, root_name);
5020 create_child_elem(root, wrong_name);
5022
5023 let ctxt = new_valid_ctxt();
5024 assert!(!ctxt.is_null());
5025
5026 assert_eq!(validate_element(ctxt, doc, root), 0);
5027
5028 free_valid_ctxt(ctxt);
5029 tree::free_doc(doc);
5030 }
5031 }
5032
5033 #[test]
5036 fn test_validate_root_match() {
5037 unsafe {
5038 let (doc, dtd) = make_test_doc();
5039
5040 let root_name = c_str("root");
5041 add_elem_decl(
5042 dtd,
5043 root_name,
5044 XML_ELEMENT_TYPE_EMPTY as c_int,
5045 ptr::null_mut(),
5046 );
5047 create_root_elem(doc, root_name);
5048
5049 let ctxt = new_valid_ctxt();
5050 assert!(!ctxt.is_null());
5051
5052 assert_eq!(validate_root(ctxt, doc), 1);
5053
5054 free_valid_ctxt(ctxt);
5055 tree::free_doc(doc);
5056 }
5057 }
5058
5059 #[test]
5060 fn test_validate_root_no_dtd() {
5061 unsafe {
5062 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5063 assert!(!doc.is_null());
5064
5065 let root_name = c_str("root");
5066 create_root_elem(doc, root_name);
5067
5068 let ctxt = new_valid_ctxt();
5069 assert!(!ctxt.is_null());
5070
5071 assert_eq!(validate_root(ctxt, doc), 1);
5073
5074 free_valid_ctxt(ctxt);
5075 tree::free_doc(doc);
5076 }
5077 }
5078
5079 #[test]
5082 fn test_validate_document_valid() {
5083 unsafe {
5084 let (doc, dtd) = make_test_doc();
5085
5086 let root_name = c_str("root");
5087 add_elem_decl(
5088 dtd,
5089 root_name,
5090 XML_ELEMENT_TYPE_EMPTY as c_int,
5091 ptr::null_mut(),
5092 );
5093 create_root_elem(doc, root_name);
5094
5095 let ctxt = new_valid_ctxt();
5096 assert!(!ctxt.is_null());
5097
5098 assert_eq!(validate_document(ctxt, doc), 1);
5099
5100 free_valid_ctxt(ctxt);
5101 tree::free_doc(doc);
5102 }
5103 }
5104
5105 #[test]
5106 fn test_validate_document_no_root() {
5107 unsafe {
5108 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5109 assert!(!doc.is_null());
5110
5111 let ctxt = new_valid_ctxt();
5112 assert!(!ctxt.is_null());
5113
5114 assert_eq!(validate_document(ctxt, doc), 0);
5115
5116 free_valid_ctxt(ctxt);
5117 tree::free_doc(doc);
5118 }
5119 }
5120
5121 #[test]
5124 fn test_validate_content_valid() {
5125 unsafe {
5126 let (doc, dtd) = make_test_doc();
5127
5128 let root_name = c_str("root");
5129 let child_name = c_str("child");
5130
5131 let child_content =
5132 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5133 assert!(!child_content.is_null());
5134
5135 add_elem_decl(
5136 dtd,
5137 root_name,
5138 XML_ELEMENT_TYPE_ELEMENT as c_int,
5139 child_content,
5140 );
5141 add_elem_decl(
5142 dtd,
5143 child_name,
5144 XML_ELEMENT_TYPE_EMPTY as c_int,
5145 ptr::null_mut(),
5146 );
5147
5148 let root = create_root_elem(doc, root_name);
5149 create_child_elem(root, child_name);
5150
5151 let ctxt = new_valid_ctxt();
5152 assert!(!ctxt.is_null());
5153
5154 assert_eq!(validate_content(ctxt, root, doc), 1);
5155
5156 free_valid_ctxt(ctxt);
5157 tree::free_doc(doc);
5158 }
5159 }
5160
5161 #[test]
5164 fn test_is_mixed_element() {
5165 unsafe {
5166 let (doc, dtd) = make_test_doc();
5167 let name = c_str("mixedElem");
5168 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5169
5170 assert_eq!(is_mixed_element(doc, name), 1);
5171
5172 let other = c_str("other");
5173 assert_eq!(is_mixed_element(doc, other), 0);
5174
5175 allocator::xmlFreeImpl(other as *mut c_void);
5176 tree::free_doc(doc);
5177 }
5178 }
5179
5180 #[test]
5181 fn test_is_empty_element() {
5182 unsafe {
5183 let (doc, dtd) = make_test_doc();
5184 let name = c_str("emptyElem");
5185 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5186
5187 assert_eq!(is_empty_element(doc, name), 1);
5188
5189 let other = c_str("other");
5190 assert_eq!(is_empty_element(doc, other), 0);
5191
5192 allocator::xmlFreeImpl(other as *mut c_void);
5193 tree::free_doc(doc);
5194 }
5195 }
5196
5197 #[test]
5198 fn test_is_mixed_element_no_dtd() {
5199 unsafe {
5200 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5201 assert!(!doc.is_null());
5202
5203 let name = c_str("foo");
5204 assert_eq!(is_mixed_element(doc, name), 0);
5205
5206 allocator::xmlFreeImpl(name as *mut c_void);
5207 tree::free_doc(doc);
5208 }
5209 }
5210
5211 #[test]
5212 fn test_is_empty_element_no_dtd() {
5213 unsafe {
5214 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5215 assert!(!doc.is_null());
5216
5217 let name = c_str("foo");
5218 assert_eq!(is_empty_element(doc, name), 0);
5219
5220 allocator::xmlFreeImpl(name as *mut c_void);
5221 tree::free_doc(doc);
5222 }
5223 }
5224
5225 #[test]
5228 fn test_validate_dtd_null() {
5229 unsafe {
5230 let ctxt = new_valid_ctxt();
5231 assert!(!ctxt.is_null());
5232 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5233 free_valid_ctxt(ctxt);
5234 }
5235 }
5236
5237 #[test]
5240 fn test_validate_element_null() {
5241 unsafe {
5242 let (doc, _dtd) = make_test_doc();
5243 let ctxt = new_valid_ctxt();
5244 assert!(!ctxt.is_null());
5245
5246 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5247
5248 free_valid_ctxt(ctxt);
5249 tree::free_doc(doc);
5250 }
5251 }
5252
5253 #[test]
5254 fn test_validate_document_null() {
5255 unsafe {
5256 let ctxt = new_valid_ctxt();
5257 assert!(!ctxt.is_null());
5258
5259 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5260 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5261
5262 free_valid_ctxt(ctxt);
5263 }
5264 }
5265
5266 #[test]
5267 fn test_validate_document_final_null() {
5268 unsafe {
5269 let ctxt = new_valid_ctxt();
5270 assert!(!ctxt.is_null());
5271
5272 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5273 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5274
5275 free_valid_ctxt(ctxt);
5276 }
5277 }
5278
5279 #[test]
5280 fn test_validate_attribute_decl_null() {
5281 unsafe {
5282 let ctxt = new_valid_ctxt();
5283 assert!(!ctxt.is_null());
5284
5285 assert_eq!(
5286 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()),
5287 0
5288 );
5289
5290 free_valid_ctxt(ctxt);
5291 }
5292 }
5293
5294 #[test]
5295 fn test_validate_content_null() {
5296 unsafe {
5297 let ctxt = new_valid_ctxt();
5298 assert!(!ctxt.is_null());
5299
5300 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5301
5302 free_valid_ctxt(ctxt);
5303 }
5304 }
5305
5306 #[test]
5307 fn test_validate_root_null() {
5308 unsafe {
5309 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5310 }
5311 }
5312
5313 #[test]
5314 fn test_validate_enumeration_null() {
5315 unsafe {
5316 let ctxt = new_valid_ctxt();
5317 assert!(!ctxt.is_null());
5318
5319 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5320
5321 free_valid_ctxt(ctxt);
5322 }
5323 }
5324
5325 #[test]
5326 fn test_validate_notation_use_null() {
5327 unsafe {
5328 let ctxt = new_valid_ctxt();
5329 assert!(!ctxt.is_null());
5330
5331 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5332
5333 free_valid_ctxt(ctxt);
5334 }
5335 }
5336
5337 #[test]
5338 fn test_validate_name_start_characters() {
5339 unsafe {
5340 let name = c_str("\u{C0}lph\u{E0}");
5342 assert_eq!(validate_name(name), 1);
5343 allocator::xmlFreeImpl(name as *mut c_void);
5344 }
5345 }
5346
5347 #[test]
5348 fn test_validate_names_single() {
5349 unsafe {
5350 let s = c_str("singleName");
5351 assert_eq!(validate_names(s), 1);
5352 allocator::xmlFreeImpl(s as *mut c_void);
5353 }
5354 }
5355
5356 #[test]
5357 fn test_validate_nmtokens_single() {
5358 unsafe {
5359 let s = c_str("123abc");
5360 assert_eq!(validate_nmtokens(s), 1);
5361 allocator::xmlFreeImpl(s as *mut c_void);
5362 }
5363 }
5364
5365 #[test]
5366 fn test_validate_nmtokens_invalid() {
5367 unsafe {
5368 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5371
5372 let s2 = c_str("foo@bar");
5374 assert_eq!(validate_nmtokens(s2), 0);
5375 allocator::xmlFreeImpl(s2 as *mut c_void);
5376 }
5377 }
5378
5379 #[test]
5380 fn test_validate_attribute_value_empty_non_cdata() {
5381 unsafe {
5382 let empty = b"\0" as *const u8 as *const xmlChar;
5383 assert_eq!(
5384 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5385 0
5386 );
5387 assert_eq!(
5388 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5389 0
5390 );
5391 assert_eq!(
5392 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5393 0
5394 );
5395 }
5396 }
5397
5398 #[test]
5399 fn test_validate_attribute_value_unknown_type() {
5400 unsafe {
5401 let s = c_str("test");
5404 assert_eq!(validate_attribute_value(999, s), 1);
5405 allocator::xmlFreeImpl(s as *mut c_void);
5406 }
5407 }
5408
5409 #[test]
5410 fn test_validate_element_any_content() {
5411 unsafe {
5412 let (doc, dtd) = make_test_doc();
5413
5414 let root_name = c_str("root");
5415 add_elem_decl(
5416 dtd,
5417 root_name,
5418 XML_ELEMENT_TYPE_ANY as c_int,
5419 ptr::null_mut(),
5420 );
5421
5422 let child_name = c_str("child");
5423 add_elem_decl(
5424 dtd,
5425 child_name,
5426 XML_ELEMENT_TYPE_EMPTY as c_int,
5427 ptr::null_mut(),
5428 );
5429
5430 let root = create_root_elem(doc, root_name);
5431 create_child_elem(root, child_name);
5432
5433 let ctxt = new_valid_ctxt();
5434 assert!(!ctxt.is_null());
5435
5436 assert_eq!(validate_element(ctxt, doc, root), 1);
5438
5439 free_valid_ctxt(ctxt);
5440 tree::free_doc(doc);
5441 }
5442 }
5443
5444 #[test]
5445 fn test_validate_element_empty_with_child() {
5446 unsafe {
5447 let (doc, dtd) = make_test_doc();
5448
5449 let root_name = c_str("root");
5450 add_elem_decl(
5451 dtd,
5452 root_name,
5453 XML_ELEMENT_TYPE_EMPTY as c_int,
5454 ptr::null_mut(),
5455 );
5456
5457 let child_name = c_str("child");
5458 add_elem_decl(
5459 dtd,
5460 child_name,
5461 XML_ELEMENT_TYPE_EMPTY as c_int,
5462 ptr::null_mut(),
5463 );
5464
5465 let root = create_root_elem(doc, root_name);
5466 create_child_elem(root, child_name);
5467
5468 let ctxt = new_valid_ctxt();
5469 assert!(!ctxt.is_null());
5470
5471 assert_eq!(validate_element(ctxt, doc, root), 0);
5473
5474 free_valid_ctxt(ctxt);
5475 tree::free_doc(doc);
5476 }
5477 }
5478
5479 #[test]
5480 fn test_validate_dtd_final_null() {
5481 unsafe {
5482 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
5483 }
5484 }
5485}