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 attr: *mut _xmlAttribute,
898) -> c_int {
899 if attr.is_null() {
900 return 0;
901 }
902
903 unsafe {
904 let a = &*attr;
905 let atype = a.atype as c_int;
906
907 if !a.defaultValue.is_null() && validate_attribute_value(atype, a.defaultValue) == 0 {
909 let name_str = string::xmlstr_to_string(a.name);
910 let val_str = string::xmlstr_to_string(a.defaultValue);
911 let err_msg = format!(
912 "Default value '{}' for attribute '{}' is not valid for its type\0",
913 val_str, name_str
914 );
915 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
916 return 0;
917 }
918
919 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !a.tree.is_null() {
921 let mut cur = a.tree;
923 while !cur.is_null() {
924 if !(*cur).name.is_null() && validate_nmtoken_value((*cur).name) == 0 {
925 let val_str = string::xmlstr_to_string((*cur).name);
926 let err_msg =
927 format!("Enumeration value '{}' is not a valid NMTOKEN\0", val_str);
928 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
929 return 0;
930 }
931 cur = (*cur).next;
932 }
933 }
934
935 if atype == XML_ATTRIBUTE_NOTATION as c_int && !a.tree.is_null() {
937 let mut cur = a.tree;
938 while !cur.is_null() {
939 if !(*cur).name.is_null() && validate_notation_use(ctxt, doc, (*cur).name) == 0 {
940 let val_str = string::xmlstr_to_string((*cur).name);
941 let err_msg = format!(
942 "NOTATION value '{}' references undeclared notation\0",
943 val_str
944 );
945 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
946 return 0;
947 }
948 cur = (*cur).next;
949 }
950 }
951
952 1
953 }
954}
955
956pub unsafe fn validate_element(
985 ctxt: *mut _xmlValidCtxt,
986 doc: *mut _xmlDoc,
987 elem: *mut _xmlNode,
988) -> c_int {
989 if elem.is_null() || doc.is_null() || ctxt.is_null() {
990 return 0;
991 }
992
993 unsafe {
994 let e = &*elem;
995
996 if e.type_ != XML_ELEMENT_NODE as c_int {
998 return 1;
999 }
1000
1001 if vctxt_push_node(ctxt, elem) != 0 {
1003 return 0;
1004 }
1005
1006 let mut valid = 1;
1007
1008 let dtd = get_valid_dtd(doc);
1010 if dtd.is_null() {
1011 vctxt_pop_node(ctxt);
1014 return 1;
1015 }
1016
1017 let dtd_ref = &*dtd;
1018
1019 let elem_name = e.name;
1021 let elem_decl = if !dtd_ref.elements.is_null() {
1022 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, elem_name)
1023 } else {
1024 ptr::null_mut()
1025 };
1026
1027 if elem_decl.is_null() {
1028 let name_str = string::xmlstr_to_string(elem_name);
1029 let err_msg = format!("No declaration for element {}\0", name_str);
1030 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1031 vctxt_pop_node(ctxt);
1032 return 0;
1033 }
1034
1035 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1036
1037 let elem_type = elem_decl_ref.etype as u32;
1039
1040 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1041 let mut child = e.children;
1043 while !child.is_null() {
1044 let child_type = (*child).type_ as u32;
1045 if child_type != XML_TEXT_NODE as u32 && child_type != XML_CDATA_SECTION_NODE as u32
1046 {
1047 valid = 0;
1048 let name_str = string::xmlstr_to_string(elem_name);
1049 let err_msg = format!(
1050 "Element '{}' is declared EMPTY but has child elements\0",
1051 name_str
1052 );
1053 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1054 break;
1055 }
1056 child = (*child).next;
1057 }
1058 } else if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1059 } else if elem_type == XML_ELEMENT_TYPE_MIXED as u32 {
1061 let mut child = e.children;
1063 while !child.is_null() {
1064 let child_type = (*child).type_ as u32;
1065 if child_type == XML_ELEMENT_NODE as u32 {
1066 let child_name = (*child).name;
1068 let result = dtd::valid_content_model(elem_decl_ref.content, &[child_name]);
1069 if result != dtd::ContentModelResult::Valid {
1070 let cname_str = string::xmlstr_to_string(child_name);
1071 let ename_str = string::xmlstr_to_string(elem_name);
1072 let err_msg = format!(
1073 "Element '{}' is not allowed in mixed content of '{}'\0",
1074 cname_str, ename_str
1075 );
1076 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1077 valid = 0;
1078 }
1079 }
1080 child = (*child).next;
1081 }
1082 } else if elem_type == XML_ELEMENT_TYPE_ELEMENT as u32 {
1083 let mut child_names: Vec<*const xmlChar> = Vec::new();
1085 let mut child = e.children;
1086 while !child.is_null() {
1087 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1088 child_names.push((*child).name);
1089 }
1090 child = (*child).next;
1091 }
1092
1093 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1094 if result != dtd::ContentModelResult::Valid {
1095 let ename_str = string::xmlstr_to_string(elem_name);
1096 let err_msg = format!(
1097 "Content model validation failed for element '{}'\0",
1098 ename_str
1099 );
1100 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1101 valid = 0;
1102 }
1103 }
1104
1105 if !dtd_ref.attributes.is_null() {
1107 let mut attr_prop = e.properties;
1109 while !attr_prop.is_null() {
1110 let attr_ref = &*attr_prop;
1111 let attr_name = attr_ref.name;
1112
1113 let attr_decl = hash::hash_lookup3(
1116 dtd_ref.attributes as *mut hash::HashTable,
1117 attr_name,
1118 ptr::null(),
1119 elem_name,
1120 );
1121
1122 if attr_decl.is_null() {
1123 attr_prop = attr_ref.next;
1128 continue;
1129 }
1130
1131 let attr_decl_ref = &*(attr_decl as *mut _xmlAttribute);
1132 let atype = attr_decl_ref.atype as c_int;
1133
1134 let attr_value = if !attr_ref.children.is_null() {
1136 let text_node = attr_ref.children;
1138 if (*text_node).type_ == XML_TEXT_NODE as c_int
1139 || (*text_node).type_ == XML_CDATA_SECTION_NODE as c_int
1140 {
1141 (*text_node).content
1142 } else {
1143 ptr::null()
1144 }
1145 } else {
1146 ptr::null()
1147 };
1148
1149 if !attr_value.is_null() {
1151 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !attr_decl_ref.tree.is_null()
1152 {
1153 if validate_enumeration(ctxt, attr_value, attr_decl_ref.tree) == 0 {
1154 let aname_str = string::xmlstr_to_string(attr_name);
1155 let aval_str = string::xmlstr_to_string(attr_value);
1156 let err_msg = format!(
1157 "Attribute '{}' has value '{}' not in enumeration\0",
1158 aname_str, aval_str
1159 );
1160 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1161 valid = 0;
1162 }
1163 } else if atype == XML_ATTRIBUTE_NOTATION as c_int {
1164 if validate_notation_use(ctxt, doc, attr_value) == 0 {
1165 let aname_str = string::xmlstr_to_string(attr_name);
1166 let aval_str = string::xmlstr_to_string(attr_value);
1167 let err_msg = format!(
1168 "Attribute '{}' references undeclared notation '{}'\0",
1169 aname_str, aval_str
1170 );
1171 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1172 valid = 0;
1173 }
1174 } else if validate_attribute_value(atype, attr_value) == 0 {
1175 let aname_str = string::xmlstr_to_string(attr_name);
1176 let aval_str = string::xmlstr_to_string(attr_value);
1177 let err_msg = format!(
1178 "Attribute '{}' has invalid value '{}' for its type\0",
1179 aname_str, aval_str
1180 );
1181 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1182 valid = 0;
1183 }
1184
1185 if atype == XML_ATTRIBUTE_ID as c_int {
1187 if validate_id(ctxt, doc, elem, attr_value) == 0 {
1188 valid = 0;
1189 }
1190 } else if atype == XML_ATTRIBUTE_IDREF as c_int {
1191 if validate_id_ref(ctxt, doc, elem, attr_value) == 0 {
1192 valid = 0;
1193 }
1194 } else if atype == XML_ATTRIBUTE_IDREFS as c_int
1195 && validate_id_refs(ctxt, doc, elem, attr_value) == 0
1196 {
1197 valid = 0;
1198 }
1199 }
1200
1201 attr_prop = attr_ref.next;
1202 }
1203
1204 struct RequiredAttrCheck {
1206 ctxt: *mut _xmlValidCtxt,
1207 elem_name: *const xmlChar,
1208 elem_props: *mut _xmlAttr,
1209 valid: *mut c_int,
1210 }
1211
1212 extern "C" fn check_required_attr(
1213 payload: *mut c_void,
1214 data: *mut c_void,
1215 name: *const xmlChar,
1216 name2: *const xmlChar,
1217 _name3: *const xmlChar,
1218 ) {
1219 if payload.is_null() || data.is_null() || name2.is_null() {
1220 return;
1221 }
1222
1223 let check = unsafe { &*(data as *mut RequiredAttrCheck) };
1225 unsafe {
1226 if string::xml_strcmp(name, check.elem_name) != 0 {
1228 return;
1229 }
1230
1231 let attr_decl = &*(payload as *mut _xmlAttribute);
1232
1233 if attr_decl.def == XML_ATTRIBUTE_REQUIRED as c_int {
1235 let mut found = 0;
1237 let mut prop = check.elem_props;
1238 while !prop.is_null() {
1239 if string::xml_strcmp((*prop).name, name2) == 0 {
1240 found = 1;
1241 break;
1242 }
1243 prop = (*prop).next;
1244 }
1245
1246 if found == 0 {
1247 let aname_str = string::xmlstr_to_string(name2);
1248 let ename_str = string::xmlstr_to_string(check.elem_name);
1249 let err_msg = format!(
1250 "Required attribute '{}' missing on element '{}'\0",
1251 aname_str, ename_str
1252 );
1253 vctxt_error(check.ctxt, err_msg.as_ptr() as *const c_char);
1254 *(check.valid) = 0;
1255 }
1256 }
1257 }
1258 }
1259
1260 let mut required_valid = valid;
1261 let check = RequiredAttrCheck {
1262 ctxt,
1263 elem_name,
1264 elem_props: e.properties,
1265 valid: &mut required_valid,
1266 };
1267
1268 hash::hash_scan_full(
1269 dtd_ref.attributes as *mut hash::HashTable,
1270 Some(check_required_attr),
1271 &check as *const RequiredAttrCheck as *mut c_void,
1272 );
1273
1274 valid = required_valid;
1275 }
1276
1277 let mut child = e.children;
1279 while !child.is_null() {
1280 if (*child).type_ == XML_ELEMENT_NODE as c_int
1281 && validate_element(ctxt, doc, child) == 0
1282 {
1283 valid = 0;
1284 }
1285 child = (*child).next;
1286 }
1287
1288 vctxt_pop_node(ctxt);
1289 valid
1290 }
1291}
1292
1293pub unsafe fn validate_document(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1313 if ctxt.is_null() || doc.is_null() {
1314 return 0;
1315 }
1316
1317 unsafe {
1318 let c = &mut *ctxt;
1319 c.doc = doc;
1320 c.valid = 1;
1321
1322 let d = &*doc;
1323
1324 if d.intSubset.is_null() && d.extSubset.is_null() {
1334 vctxt_error(ctxt, b"no DTD found!\0" as *const u8 as *const c_char);
1335 return 0;
1336 }
1337
1338 let mut root = d.children;
1340 while !root.is_null() {
1341 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1342 break;
1343 }
1344 root = (*root).next;
1345 }
1346
1347 if root.is_null() {
1348 vctxt_error(
1349 ctxt,
1350 b"No root element found in document\0" as *const u8 as *const c_char,
1351 );
1352 return 0;
1353 }
1354
1355 if validate_element(ctxt, doc, root) == 0 {
1357 return 0;
1358 }
1359
1360 c.valid
1361 }
1362}
1363
1364pub unsafe fn validate_document_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1386 if ctxt.is_null() || doc.is_null() {
1387 return 0;
1388 }
1389
1390 unsafe {
1391 let c = &mut *ctxt;
1392 c.doc = doc;
1393
1394 let d = &*doc;
1395
1396 if d.refs.is_null() {
1398 return c.valid;
1399 }
1400
1401 struct IdRefCheckContext {
1403 ctxt: *mut _xmlValidCtxt,
1404 doc: *mut _xmlDoc,
1405 }
1406
1407 extern "C" fn check_idref(
1408 _payload: *mut c_void,
1409 data: *mut c_void,
1410 _name: *const xmlChar,
1411 name2: *const xmlChar,
1412 _name3: *const xmlChar,
1413 ) {
1414 if data.is_null() || name2.is_null() {
1415 return;
1416 }
1417
1418 let cx = unsafe { &*(data as *mut IdRefCheckContext) };
1420 unsafe {
1421 let doc_ref = &*cx.doc;
1422
1423 if doc_ref.ids.is_null()
1425 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, name2).is_null()
1426 {
1427 let ref_str = string::xmlstr_to_string(name2);
1428 let err_msg = format!("IDREF '{}' does not reference a declared ID\0", ref_str);
1429 vctxt_error(cx.ctxt, err_msg.as_ptr() as *const c_char);
1430 }
1431 }
1432 }
1433
1434 let ctx = IdRefCheckContext { ctxt, doc };
1435 hash::hash_scan_full(
1436 d.refs as *mut hash::HashTable,
1437 Some(check_idref),
1438 &ctx as *const IdRefCheckContext as *mut c_void,
1439 );
1440
1441 c.valid
1442 }
1443}
1444
1445pub unsafe fn validate_root(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1463 if ctxt.is_null() || doc.is_null() {
1464 return 0;
1465 }
1466
1467 unsafe {
1468 let c = &mut *ctxt;
1469 c.doc = doc;
1470 c.valid = 1;
1471
1472 let d = &*doc;
1473
1474 let mut root = d.children;
1476 while !root.is_null() {
1477 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1478 break;
1479 }
1480 root = (*root).next;
1481 }
1482
1483 if root.is_null() {
1484 vctxt_error(
1485 ctxt,
1486 b"No root element found\0" as *const u8 as *const c_char,
1487 );
1488 return 0;
1489 }
1490
1491 let dtd = get_valid_dtd(doc);
1493 if dtd.is_null() {
1494 return 1;
1496 }
1497
1498 let dtd_ref = &*dtd;
1501 if !dtd_ref.name.is_null() && string::xml_strcmp((*root).name, dtd_ref.name) != 0 {
1502 let root_str = string::xmlstr_to_string((*root).name);
1503 let dtd_str = string::xmlstr_to_string(dtd_ref.name);
1504 let err_msg = format!(
1505 "Root element '{}' does not match DTD root '{}'\0",
1506 root_str, dtd_str
1507 );
1508 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1509 return 0;
1510 }
1511
1512 c.valid
1513 }
1514}
1515
1516pub unsafe fn validate_content(
1536 ctxt: *mut _xmlValidCtxt,
1537 node: *mut _xmlNode,
1538 doc: *mut _xmlDoc,
1539) -> c_int {
1540 if node.is_null() || doc.is_null() || ctxt.is_null() {
1541 return 0;
1542 }
1543
1544 unsafe {
1545 let n = &*node;
1546 if n.type_ != XML_ELEMENT_NODE as c_int {
1547 return 1;
1548 }
1549
1550 let dtd = get_valid_dtd(doc);
1551 if dtd.is_null() {
1552 return 1;
1553 }
1554
1555 let dtd_ref = &*dtd;
1556 if dtd_ref.elements.is_null() {
1557 return 1;
1558 }
1559
1560 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, n.name);
1561 if elem_decl.is_null() {
1562 return 1;
1563 }
1564
1565 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1566 if elem_decl_ref.content.is_null() {
1567 return 1;
1568 }
1569
1570 let elem_type = elem_decl_ref.etype as u32;
1571 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1572 let mut child = n.children;
1574 while !child.is_null() {
1575 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1576 let name_str = string::xmlstr_to_string(n.name);
1577 let err_msg =
1578 format!("Element '{}' is EMPTY but has child elements\0", name_str);
1579 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1580 return 0;
1581 }
1582 child = (*child).next;
1583 }
1584 return 1;
1585 }
1586
1587 if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1588 return 1;
1589 }
1590
1591 let mut child_names: Vec<*const xmlChar> = Vec::new();
1593 let mut child = n.children;
1594 while !child.is_null() {
1595 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1596 child_names.push((*child).name);
1597 }
1598 child = (*child).next;
1599 }
1600
1601 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1602 if result != dtd::ContentModelResult::Valid {
1603 let name_str = string::xmlstr_to_string(n.name);
1604 let err_msg = format!(
1605 "Content model validation failed for element '{}'\0",
1606 name_str
1607 );
1608 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1609 0
1610 } else {
1611 1
1612 }
1613 }
1614}
1615
1616pub unsafe fn is_mixed_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1634 if doc.is_null() || name.is_null() {
1635 return 0;
1636 }
1637
1638 let dtd = unsafe { get_valid_dtd(doc) };
1639 if dtd.is_null() {
1640 return 0;
1641 }
1642
1643 unsafe {
1644 let dtd_ref = &*dtd;
1645 if dtd_ref.elements.is_null() {
1646 return 0;
1647 }
1648
1649 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1650 if elem_decl.is_null() {
1651 return 0;
1652 }
1653
1654 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1655 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_MIXED as u32) as c_int
1656 }
1657}
1658
1659pub unsafe fn is_empty_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1673 if doc.is_null() || name.is_null() {
1674 return 0;
1675 }
1676
1677 let dtd = unsafe { get_valid_dtd(doc) };
1678 if dtd.is_null() {
1679 return 0;
1680 }
1681
1682 unsafe {
1683 let dtd_ref = &*dtd;
1684 if dtd_ref.elements.is_null() {
1685 return 0;
1686 }
1687
1688 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1689 if elem_decl.is_null() {
1690 return 0;
1691 }
1692
1693 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1694 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_EMPTY as u32) as c_int
1695 }
1696}
1697
1698pub unsafe fn validate_dtd(
1722 ctxt: *mut _xmlValidCtxt,
1723 doc: *mut _xmlDoc,
1724 dtd: *mut _xmlDtd,
1725) -> c_int {
1726 if ctxt.is_null() || dtd.is_null() {
1727 return 0;
1728 }
1729
1730 let c = unsafe { &mut *ctxt };
1731 c.doc = doc;
1732 c.valid = 1;
1733
1734 struct ValidateDtdCtx {
1735 ctxt: *mut _xmlValidCtxt,
1736 doc: *mut _xmlDoc,
1737 }
1738
1739 extern "C" fn validate_attr_decl_cb(
1740 payload: *mut c_void,
1741 data: *mut c_void,
1742 _name: *const xmlChar,
1743 _name2: *const xmlChar,
1744 _name3: *const xmlChar,
1745 ) {
1746 if payload.is_null() || data.is_null() {
1747 return;
1748 }
1749
1750 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1752 unsafe {
1753 let attr = payload as *mut _xmlAttribute;
1754 validate_attribute_decl(ctx.ctxt, ctx.doc, attr);
1755 }
1756 }
1757
1758 extern "C" fn validate_elem_content_cb(
1759 payload: *mut c_void,
1760 data: *mut c_void,
1761 _name: *const xmlChar,
1762 _name2: *const xmlChar,
1763 _name3: *const xmlChar,
1764 ) {
1765 if payload.is_null() || data.is_null() {
1766 return;
1767 }
1768
1769 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1771 unsafe {
1772 let elem = &*(payload as *mut _xmlElement);
1773 if !elem.content.is_null() {
1774 validate_content_model_refs(ctx.ctxt, ctx.doc, elem.content);
1775 }
1776 }
1777 }
1778
1779 unsafe {
1780 let dtd_ref = &*dtd;
1781
1782 if !dtd_ref.attributes.is_null() {
1784 let ctx = ValidateDtdCtx { ctxt, doc };
1785 hash::hash_scan_full(
1786 dtd_ref.attributes as *mut hash::HashTable,
1787 Some(validate_attr_decl_cb),
1788 &ctx as *const ValidateDtdCtx as *mut c_void,
1789 );
1790 }
1791
1792 if !dtd_ref.elements.is_null() {
1794 let ctx = ValidateDtdCtx { ctxt, doc };
1795 hash::hash_scan_full(
1796 dtd_ref.elements as *mut hash::HashTable,
1797 Some(validate_elem_content_cb),
1798 &ctx as *const ValidateDtdCtx as *mut c_void,
1799 );
1800 }
1801
1802 c.valid
1803 }
1804}
1805
1806unsafe fn validate_content_model_refs(
1813 ctxt: *mut _xmlValidCtxt,
1814 doc: *mut _xmlDoc,
1815 content: *mut _xmlElementContent,
1816) {
1817 if content.is_null() {
1818 return;
1819 }
1820
1821 unsafe {
1822 let c = &*content;
1823
1824 match c.type_ as u32 {
1825 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
1826 if !c.name.is_null() {
1828 let dtd = get_valid_dtd(doc);
1829 if !dtd.is_null() {
1830 let dtd_ref = &*dtd;
1831 if !dtd_ref.elements.is_null() {
1832 let decl =
1833 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, c.name);
1834 if decl.is_null() {
1835 let name_str = string::xmlstr_to_string(c.name);
1836 let err_msg = format!(
1837 "Element '{}' referenced in content model is not declared\0",
1838 name_str
1839 );
1840 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1841 }
1842 }
1843 }
1844 }
1845 }
1846 t if t == XML_ELEMENT_CONTENT_SEQ as u32 || t == XML_ELEMENT_CONTENT_OR as u32 => {
1847 validate_content_model_refs(ctxt, doc, c.c1);
1848 validate_content_model_refs(ctxt, doc, c.c2);
1849 }
1850 _ => {}
1851 }
1852 }
1853}
1854
1855pub unsafe fn validate_dtd_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1876 unsafe { validate_document_final(ctxt, doc) }
1877}
1878
1879const XML_SCAN_NC: u32 = 1; const XML_SCAN_NMTOKEN: u32 = 2; const fn is_blank_byte(b: u8) -> bool {
1907 b == b' ' || b == b'\t' || b == b'\n' || b == b'\r'
1908}
1909
1910const fn utf8_char_len(lead: u8) -> usize {
1912 if lead < 0x80 {
1913 1
1914 } else if lead >= 0xC0 && lead <= 0xDF {
1915 2
1916 } else if lead >= 0xE0 && lead <= 0xEF {
1917 3
1918 } else if lead >= 0xF0 && lead <= 0xF7 {
1919 4
1920 } else {
1921 0
1922 }
1923}
1924
1925unsafe fn scan_name_offsets(bytes: &[u8], start: usize, flags: u32) -> usize {
1938 let stop = if flags & XML_SCAN_NC != 0 {
1939 Some(b':')
1940 } else {
1941 None
1942 };
1943 let mut i = start;
1944 let mut is_nmtoken = flags & XML_SCAN_NMTOKEN != 0;
1945 while i < bytes.len() {
1946 let b = bytes[i];
1947 if b < 0x80 {
1948 if stop == Some(b) {
1949 break;
1950 }
1951 let c = b as char;
1952 let ok = if is_nmtoken {
1953 is_xml_name_char(c)
1954 } else {
1955 is_xml_name_start(c)
1956 };
1957 if !ok {
1958 break;
1959 }
1960 i += 1;
1961 } else {
1962 let len = utf8_char_len(b);
1963 if len == 0 || i + len > bytes.len() {
1964 break;
1965 }
1966 let ch = match core::str::from_utf8(&bytes[i..i + len])
1967 .ok()
1968 .and_then(|s| s.chars().next())
1969 {
1970 Some(c) => c,
1971 None => break,
1972 };
1973 let ok = if is_nmtoken {
1974 is_xml_name_char(ch)
1975 } else {
1976 is_xml_name_start(ch)
1977 };
1978 if !ok {
1979 break;
1980 }
1981 i += len;
1982 }
1983 is_nmtoken = true;
1985 }
1986 i
1987}
1988
1989pub unsafe fn validate_ncname(value: *const xmlChar, space: c_int) -> c_int {
1995 if value.is_null() {
1996 return -1;
1997 }
1998 let bytes = string::xmlstr_to_bytes(value);
1999 let mut start = 0usize;
2000 if space != 0 {
2001 while start < bytes.len() && is_blank_byte(bytes[start]) {
2002 start += 1;
2003 }
2004 }
2005 let end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2006 if end == start {
2007 return 1;
2008 }
2009 let mut end2 = end;
2010 if space != 0 {
2011 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2012 end2 += 1;
2013 }
2014 }
2015 if end2 == bytes.len() {
2016 0
2017 } else {
2018 1
2019 }
2020}
2021
2022pub unsafe fn validate_qname(value: *const xmlChar, space: c_int) -> c_int {
2028 if value.is_null() {
2029 return -1;
2030 }
2031 let bytes = string::xmlstr_to_bytes(value);
2032 let mut start = 0usize;
2033 if space != 0 {
2034 while start < bytes.len() && is_blank_byte(bytes[start]) {
2035 start += 1;
2036 }
2037 }
2038 let mut end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2039 if end == start {
2040 return 1;
2041 }
2042 if end < bytes.len() && bytes[end] == b':' {
2043 end += 1;
2044 let end2 = scan_name_offsets(bytes, end, XML_SCAN_NC);
2045 if end2 == end {
2046 return 1;
2047 }
2048 end = end2;
2049 }
2050 if space != 0 {
2051 while end < bytes.len() && is_blank_byte(bytes[end]) {
2052 end += 1;
2053 }
2054 }
2055 if end == bytes.len() {
2056 0
2057 } else {
2058 1
2059 }
2060}
2061
2062pub unsafe fn validate_name_space(value: *const xmlChar, space: c_int) -> c_int {
2073 if value.is_null() {
2074 return -1;
2075 }
2076 let bytes = string::xmlstr_to_bytes(value);
2077 let mut start = 0usize;
2078 if space != 0 {
2079 while start < bytes.len() && is_blank_byte(bytes[start]) {
2080 start += 1;
2081 }
2082 }
2083 let end = scan_name_offsets(bytes, start, 0);
2084 if end == start {
2085 return 1;
2086 }
2087 let mut end2 = end;
2088 if space != 0 {
2089 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2090 end2 += 1;
2091 }
2092 }
2093 if end2 == bytes.len() {
2094 0
2095 } else {
2096 1
2097 }
2098}
2099
2100pub unsafe fn validate_nmtoken_space(value: *const xmlChar, space: c_int) -> c_int {
2106 if value.is_null() {
2107 return -1;
2108 }
2109 let bytes = string::xmlstr_to_bytes(value);
2110 let mut start = 0usize;
2111 if space != 0 {
2112 while start < bytes.len() && is_blank_byte(bytes[start]) {
2113 start += 1;
2114 }
2115 }
2116 let end = scan_name_offsets(bytes, start, XML_SCAN_NMTOKEN);
2117 if end == start {
2118 return 1;
2119 }
2120 let mut end2 = end;
2121 if space != 0 {
2122 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2123 end2 += 1;
2124 }
2125 }
2126 if end2 == bytes.len() {
2127 0
2128 } else {
2129 1
2130 }
2131}
2132
2133unsafe fn validate_value_internal(value: *const xmlChar, flags: u32) -> c_int {
2136 if value.is_null() {
2137 return 0;
2138 }
2139 let bytes = string::xmlstr_to_bytes(value);
2140 if bytes.is_empty() {
2141 return 0;
2142 }
2143 let end = scan_name_offsets(bytes, 0, flags);
2144 if end == 0 {
2145 return 0;
2146 }
2147 if end == bytes.len() {
2148 1
2149 } else {
2150 0
2151 }
2152}
2153
2154unsafe fn validate_values_internal(value: *const xmlChar, flags: u32) -> c_int {
2157 if value.is_null() {
2158 return 0;
2159 }
2160 let bytes = string::xmlstr_to_bytes(value);
2161 let mut cur = scan_name_offsets(bytes, 0, flags);
2162 if cur == 0 {
2163 return 0;
2164 }
2165 while cur < bytes.len() && bytes[cur] == b' ' {
2166 while cur < bytes.len() && bytes[cur] == b' ' {
2167 cur += 1;
2168 }
2169 let end = scan_name_offsets(bytes, cur, flags);
2170 if end == cur {
2171 return 0;
2172 }
2173 cur = end;
2174 }
2175 if cur == bytes.len() {
2176 1
2177 } else {
2178 0
2179 }
2180}
2181
2182pub unsafe fn validate_name_value(value: *const xmlChar) -> c_int {
2188 validate_value_internal(value, 0)
2189}
2190
2191pub unsafe fn validate_names_value(value: *const xmlChar) -> c_int {
2197 validate_values_internal(value, 0)
2198}
2199
2200pub unsafe fn validate_nmtoken_value(value: *const xmlChar) -> c_int {
2206 validate_value_internal(value, XML_SCAN_NMTOKEN)
2207}
2208
2209pub unsafe fn validate_nmtokens_value(value: *const xmlChar) -> c_int {
2215 validate_values_internal(value, XML_SCAN_NMTOKEN)
2216}
2217
2218pub unsafe fn get_dtd_qelement_desc(
2229 dtd: *mut _xmlDtd,
2230 name: *const xmlChar,
2231 prefix: *const xmlChar,
2232) -> *mut _xmlElement {
2233 if dtd.is_null() {
2234 return ptr::null_mut();
2235 }
2236 unsafe {
2237 let elements = (*dtd).elements;
2238 if elements.is_null() {
2239 return ptr::null_mut();
2240 }
2241 hash::hash_lookup2(elements as *mut hash::HashTable, name, prefix) as *mut _xmlElement
2242 }
2243}
2244
2245pub unsafe fn get_dtd_qattr_desc(
2253 dtd: *mut _xmlDtd,
2254 elem: *const xmlChar,
2255 name: *const xmlChar,
2256 prefix: *const xmlChar,
2257) -> *mut _xmlAttribute {
2258 if dtd.is_null() || elem.is_null() || name.is_null() {
2259 return ptr::null_mut();
2260 }
2261 unsafe {
2262 let attrs = (*dtd).attributes;
2263 if attrs.is_null() {
2264 return ptr::null_mut();
2265 }
2266 hash::hash_lookup3(attrs as *mut hash::HashTable, name, prefix, elem) as *mut _xmlAttribute
2267 }
2268}
2269
2270pub unsafe fn get_dtd_notation_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlNotation {
2276 if dtd.is_null() || name.is_null() {
2277 return ptr::null_mut();
2278 }
2279 unsafe {
2280 let notations = (*dtd).notations;
2281 if notations.is_null() {
2282 return ptr::null_mut();
2283 }
2284 hash::hash_lookup(notations as *mut hash::HashTable, name) as *mut _xmlNotation
2285 }
2286}
2287
2288unsafe fn split_qname4(name: *const xmlChar, prefix: *mut *mut xmlChar) -> *const xmlChar {
2297 if prefix.is_null() {
2298 return name;
2299 }
2300 unsafe {
2301 *prefix = ptr::null_mut();
2302 if name.is_null() {
2303 return ptr::null();
2304 }
2305 let bytes = string::xmlstr_to_bytes(name);
2306 match bytes.iter().position(|&b| b == b':') {
2307 None => name,
2308 Some(pos) => {
2309 let p = string::bytes_to_xmlstr(&bytes[..pos]);
2310 *prefix = p;
2311 name.add(pos + 1)
2312 }
2313 }
2314 }
2315}
2316
2317unsafe fn free_id(id: *mut _xmlID) {
2332 if id.is_null() {
2333 return;
2334 }
2335 unsafe {
2336 if !(*id).value.is_null() {
2337 allocator::xmlFreeImpl((*id).value as *mut c_void);
2338 }
2339 if !(*id).name.is_null() {
2340 allocator::xmlFreeImpl((*id).name as *mut c_void);
2341 }
2342 if !(*id).attr.is_null() {
2343 (*(*id).attr).id = ptr::null_mut();
2344 (*(*id).attr).atype = 0;
2345 }
2346 allocator::xmlFreeImpl(id as *mut c_void);
2347 }
2348}
2349
2350unsafe extern "C" fn free_id_entry(payload: *mut c_void, _name: *mut xmlChar) {
2353 free_id(payload as *mut _xmlID);
2354}
2355
2356unsafe fn add_id_internal(
2368 attr: *mut _xmlAttr,
2369 value: *const xmlChar,
2370 id_ptr: *mut *mut _xmlID,
2371) -> c_int {
2372 unsafe {
2373 if !id_ptr.is_null() {
2374 *id_ptr = ptr::null_mut();
2375 }
2376 if value.is_null() || *value == 0 {
2377 return 0;
2378 }
2379 if attr.is_null() {
2380 return 0;
2381 }
2382 let doc = (*attr).doc;
2383 if doc.is_null() {
2384 return 0;
2385 }
2386
2387 let mut table = (*doc).ids as *mut hash::HashTable;
2388 if table.is_null() {
2389 (*doc).ids = hash::hash_create(0) as *mut c_void;
2390 table = (*doc).ids as *mut hash::HashTable;
2391 if table.is_null() {
2392 return -1;
2393 }
2394 } else if !hash::hash_lookup(table, value).is_null() {
2395 return 0;
2396 }
2397
2398 let id = allocator::xmlMallocZero(size_of::<_xmlID>() as usize) as *mut _xmlID;
2399 if id.is_null() {
2400 return -1;
2401 }
2402 (*id).doc = doc;
2403 (*id).value = string::xml_strdup(value);
2404 if (*id).value.is_null() {
2405 free_id(id);
2406 return -1;
2407 }
2408 if !(*attr).id.is_null() {
2410 remove_id(doc, attr);
2411 }
2412 if hash::hash_add_entry(table, value, id as *mut c_void) != 0 {
2413 free_id(id);
2414 return -1;
2415 }
2416 if !id_ptr.is_null() {
2417 *id_ptr = id;
2418 }
2419 (*id).attr = attr;
2420 (*id).lineno = tree::get_line_no((*attr).parent) as c_int;
2421 (*attr).atype = XML_ATTRIBUTE_ID as c_int;
2422 (*attr).id = id as *mut c_void;
2423 1
2424 }
2425}
2426
2427pub unsafe fn add_id(
2435 ctxt: *mut _xmlValidCtxt,
2436 doc: *mut _xmlDoc,
2437 value: *const xmlChar,
2438 attr: *mut _xmlAttr,
2439) -> *mut _xmlID {
2440 unsafe {
2441 if attr.is_null() || doc != (*attr).doc {
2442 return ptr::null_mut();
2443 }
2444 let mut id = ptr::null_mut();
2445 let res = add_id_internal(attr, value, &mut id);
2446 if res < 0 {
2447 vctxt_error(
2448 ctxt,
2449 b"Memory allocation failed : xmlAddID\0" as *const u8 as *const c_char,
2450 );
2451 } else if res == 0 && !ctxt.is_null() {
2452 let msg = format!("ID {} already defined\0", string::xmlstr_to_string(value));
2453 vctxt_error(ctxt, msg.as_ptr() as *const c_char);
2454 }
2455 id
2456 }
2457}
2458
2459pub unsafe fn remove_id(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2466 unsafe {
2467 if doc.is_null() {
2468 return -1;
2469 }
2470 if attr.is_null() || (*attr).id.is_null() {
2471 return -1;
2472 }
2473 let table = (*doc).ids as *mut hash::HashTable;
2474 if table.is_null() {
2475 return -1;
2476 }
2477 let value = (*((*attr).id as *mut _xmlID)).value;
2478 if hash::hash_remove_entry(table, value, Some(free_id_entry)) < 0 {
2479 return -1;
2480 }
2481 0
2482 }
2483}
2484
2485unsafe fn free_ref(r: *mut _xmlRef) {
2493 if r.is_null() {
2494 return;
2495 }
2496 unsafe {
2497 if !(*r).value.is_null() {
2498 allocator::xmlFreeImpl((*r).value as *mut c_void);
2499 }
2500 if !(*r).name.is_null() {
2501 allocator::xmlFreeImpl((*r).name as *mut c_void);
2502 }
2503 allocator::xmlFreeImpl(r as *mut c_void);
2504 }
2505}
2506
2507unsafe extern "C" fn free_ref_list_entry(data: *mut c_void) {
2509 free_ref(data as *mut _xmlRef);
2510}
2511
2512const unsafe extern "C" fn dummy_compare(_a: *const c_void, _b: *const c_void) -> c_int {
2514 1
2515}
2516
2517unsafe extern "C" fn free_ref_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
2519 crate::xml::list::list_delete(payload as *mut crate::xml::list::List);
2520}
2521
2522pub unsafe fn add_ref(
2529 ctxt: *mut _xmlValidCtxt,
2530 doc: *mut _xmlDoc,
2531 value: *const xmlChar,
2532 attr: *mut _xmlAttr,
2533) -> *mut _xmlRef {
2534 unsafe {
2535 if doc.is_null() || value.is_null() || attr.is_null() {
2536 return ptr::null_mut();
2537 }
2538
2539 let mut table = (*doc).refs as *mut hash::HashTable;
2540 if table.is_null() {
2541 (*doc).refs = hash::hash_create(0) as *mut c_void;
2542 table = (*doc).refs as *mut hash::HashTable;
2543 if table.is_null() {
2544 vctxt_error(
2545 ctxt,
2546 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2547 );
2548 return ptr::null_mut();
2549 }
2550 }
2551
2552 let ret = allocator::xmlMallocZero(size_of::<_xmlRef>() as usize) as *mut _xmlRef;
2553 if ret.is_null() {
2554 vctxt_error(
2555 ctxt,
2556 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2557 );
2558 return ptr::null_mut();
2559 }
2560 (*ret).value = string::xml_strdup(value);
2561 if (*ret).value.is_null() {
2562 free_ref(ret);
2563 vctxt_error(
2564 ctxt,
2565 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2566 );
2567 return ptr::null_mut();
2568 }
2569 let streaming = !ctxt.is_null()
2573 && !(*ctxt).userData.is_null()
2574 && (*((*ctxt).userData as *mut _xmlParserCtxt)).parseMode
2575 == crate::abi::types::xmlParserMode::XML_PARSE_READER as c_int;
2576 if streaming {
2577 (*ret).name = string::xml_strdup((*attr).name);
2578 (*ret).attr = ptr::null_mut();
2579 } else {
2580 (*ret).name = ptr::null();
2581 (*ret).attr = attr;
2582 }
2583 (*ret).lineno = tree::get_line_no((*attr).parent) as c_int;
2584
2585 let ref_list = hash::hash_lookup(table, value) as *mut crate::xml::list::List;
2587 if ref_list.is_null() {
2588 let l = crate::xml::list::list_create(Some(free_ref_list_entry), Some(dummy_compare));
2589 if l.is_null() {
2590 free_ref(ret);
2591 vctxt_error(
2592 ctxt,
2593 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2594 );
2595 return ptr::null_mut();
2596 }
2597 if hash::hash_add_entry(table, value, l as *mut c_void) != 0 {
2598 crate::xml::list::list_delete(l);
2599 free_ref(ret);
2600 vctxt_error(
2601 ctxt,
2602 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2603 );
2604 return ptr::null_mut();
2605 }
2606 crate::xml::list::list_append(l, ret as *mut c_void);
2607 } else {
2608 if crate::xml::list::list_append(ref_list, ret as *mut c_void) != 0 {
2609 free_ref(ret);
2610 vctxt_error(
2611 ctxt,
2612 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2613 );
2614 return ptr::null_mut();
2615 }
2616 }
2617 ret
2618 }
2619}
2620
2621pub unsafe fn remove_ref(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2628 if doc.is_null() || attr.is_null() {
2632 return -1;
2633 }
2634 unsafe {
2635 let table = (*doc).refs as *mut hash::HashTable;
2636 if table.is_null() {
2637 return -1;
2638 }
2639 let mut removed = -1;
2640 struct ScanCtx {
2642 table: *mut hash::HashTable,
2643 attr: *mut _xmlAttr,
2644 removed: c_int,
2645 }
2646 extern "C" fn scan_remove(payload: *mut c_void, data: *mut c_void, name: *const xmlChar) {
2647 let ctx = unsafe { &mut *(data as *mut ScanCtx) };
2648 let l = payload as *mut crate::xml::list::List;
2649 let mut cur: *mut c_void = crate::xml::list::list_front(l);
2651 while !cur.is_null() {
2652 let next: *mut c_void = unsafe { (*(cur as *mut _xmlRef)).next as *mut c_void };
2653 let r = cur as *mut _xmlRef;
2654 if unsafe { (*r).attr } == ctx.attr {
2655 unsafe {
2656 crate::xml::list::list_remove_first(l, cur);
2657 }
2658 ctx.removed = 0;
2659 }
2660 cur = next;
2661 }
2662 if crate::xml::list::list_empty(l) != 0 {
2663 unsafe {
2664 hash::hash_remove_entry(ctx.table, name, Some(free_ref_table_entry));
2665 }
2666 }
2667 let _ = name;
2668 }
2669 let mut ctx = ScanCtx {
2670 table,
2671 attr,
2672 removed: -1,
2673 };
2674 hash::hash_scan(
2675 table,
2676 Some(scan_remove),
2677 &mut ctx as *mut ScanCtx as *mut c_void,
2678 );
2679 removed = ctx.removed;
2680 removed
2681 }
2682}
2683
2684pub unsafe fn add_id_safe(attr: *mut _xmlAttr, value: *const xmlChar) -> c_int {
2692 add_id_internal(attr, value, ptr::null_mut())
2693}
2694
2695pub unsafe fn free_id_table(table: *mut hash::HashTable) {
2701 hash::hash_free(table, Some(free_id_entry));
2702}
2703
2704pub unsafe fn free_ref_table(table: *mut hash::HashTable) {
2710 hash::hash_free(table, Some(free_ref_table_entry));
2711}
2712
2713pub unsafe fn get_id(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut _xmlAttr {
2721 unsafe {
2722 if doc.is_null() || id.is_null() {
2723 return ptr::null_mut();
2724 }
2725 let table = (*doc).ids as *mut hash::HashTable;
2726 if table.is_null() {
2727 return ptr::null_mut();
2728 }
2729 let id_entry = hash::hash_lookup(table, id) as *mut _xmlID;
2730 if id_entry.is_null() {
2731 return ptr::null_mut();
2732 }
2733 if (*id_entry).attr.is_null() {
2734 doc as *mut _xmlAttr
2736 } else {
2737 (*id_entry).attr
2738 }
2739 }
2740}
2741
2742pub unsafe fn get_refs(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut crate::xml::list::List {
2748 unsafe {
2749 if doc.is_null() || id.is_null() {
2750 return ptr::null_mut();
2751 }
2752 let table = (*doc).refs as *mut hash::HashTable;
2753 if table.is_null() {
2754 return ptr::null_mut();
2755 }
2756 hash::hash_lookup(table, id) as *mut crate::xml::list::List
2757 }
2758}
2759
2760pub unsafe fn is_id(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2768 unsafe {
2769 if attr.is_null() || (*attr).name.is_null() {
2770 return 0;
2771 }
2772 if !doc.is_null() && (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2773 if string::xml_strcmp(b"id\0" as *const u8 as *const xmlChar, (*attr).name) == 0 {
2774 return 1;
2775 }
2776 if elem.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
2777 return 0;
2778 }
2779 if string::xml_strcmp(b"name\0" as *const u8 as *const xmlChar, (*attr).name) == 0
2780 && string::xml_strcmp(b"a\0" as *const u8 as *const xmlChar, (*elem).name) == 0
2781 {
2782 return 1;
2783 }
2784 } else {
2785 if !(*attr).ns.is_null()
2787 && !(*(*attr).ns).prefix.is_null()
2788 && string::xml_strcmp(
2789 (*(*attr).ns).prefix,
2790 b"xml\0" as *const u8 as *const xmlChar,
2791 ) == 0
2792 && string::xml_strcmp((*attr).name, b"id\0" as *const u8 as *const xmlChar) == 0
2793 {
2794 return 1;
2795 }
2796 if doc.is_null() || ((*doc).intSubset.is_null() && (*doc).extSubset.is_null()) {
2797 return 0;
2798 }
2799 if elem.is_null()
2800 || (*elem).type_ != XML_ELEMENT_NODE as c_int
2801 || (*elem).name.is_null()
2802 {
2803 return 0;
2804 }
2805 let mut fullname = (*elem).name;
2806 let mut owned = false;
2807 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
2808 let f = string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
2809 if f.is_null() {
2810 return -1;
2811 }
2812 fullname = f;
2813 owned = true;
2814 }
2815 let aprefix = if !(*attr).ns.is_null() {
2816 (*(*attr).ns).prefix
2817 } else {
2818 ptr::null()
2819 };
2820 let mut attr_decl =
2821 get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
2822 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2823 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
2824 }
2825 if owned {
2826 allocator::xmlFreeImpl(fullname as *mut c_void);
2827 }
2828 if !attr_decl.is_null() && (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int {
2829 return 1;
2830 }
2831 }
2832 0
2833 }
2834}
2835
2836pub unsafe fn is_ref(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2842 unsafe {
2843 if attr.is_null() {
2844 return 0;
2845 }
2846 let doc = if doc.is_null() { (*attr).doc } else { doc };
2847 if doc.is_null() {
2848 return 0;
2849 }
2850 if (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2851 return 0;
2852 }
2853 if (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2854 return 0;
2855 }
2856 if elem.is_null() {
2857 return 0;
2858 }
2859 let aprefix = if !(*attr).ns.is_null() {
2860 (*(*attr).ns).prefix
2861 } else {
2862 ptr::null()
2863 };
2864 let mut attr_decl =
2865 get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
2866 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2867 attr_decl = get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
2868 }
2869 if !attr_decl.is_null()
2870 && ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
2871 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
2872 {
2873 return 1;
2874 }
2875 0
2876 }
2877}
2878
2879pub unsafe fn get_dtd_element_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlElement {
2886 unsafe {
2887 if dtd.is_null() || name.is_null() {
2888 return ptr::null_mut();
2889 }
2890 let elements = (*dtd).elements;
2891 if elements.is_null() {
2892 return ptr::null_mut();
2893 }
2894 let mut prefix = ptr::null_mut();
2895 let local = split_qname4(name, &mut prefix);
2896 if local.is_null() {
2897 if !prefix.is_null() {
2898 allocator::xmlFreeImpl(prefix as *mut c_void);
2899 }
2900 return ptr::null_mut();
2901 }
2902 let cur =
2903 hash::hash_lookup2(elements as *mut hash::HashTable, local, prefix) as *mut _xmlElement;
2904 if !prefix.is_null() {
2905 allocator::xmlFreeImpl(prefix as *mut c_void);
2906 }
2907 cur
2908 }
2909}
2910
2911pub unsafe fn get_dtd_attr_desc(
2919 dtd: *mut _xmlDtd,
2920 elem: *const xmlChar,
2921 name: *const xmlChar,
2922) -> *mut _xmlAttribute {
2923 unsafe {
2924 if dtd.is_null() || elem.is_null() || name.is_null() {
2925 return ptr::null_mut();
2926 }
2927 let attrs = (*dtd).attributes;
2928 if attrs.is_null() {
2929 return ptr::null_mut();
2930 }
2931 let mut prefix = ptr::null_mut();
2932 let local = split_qname4(name, &mut prefix);
2933 if local.is_null() {
2934 if !prefix.is_null() {
2935 allocator::xmlFreeImpl(prefix as *mut c_void);
2936 }
2937 return ptr::null_mut();
2938 }
2939 let cur = hash::hash_lookup3(attrs as *mut hash::HashTable, local, prefix, elem)
2940 as *mut _xmlAttribute;
2941 if !prefix.is_null() {
2942 allocator::xmlFreeImpl(prefix as *mut c_void);
2943 }
2944 cur
2945 }
2946}
2947
2948unsafe fn vctxt_error_node(ctxt: *mut _xmlValidCtxt, _node: *mut _xmlNode, msg: *const c_char) {
2958 vctxt_error(ctxt, msg);
2959}
2960
2961pub unsafe fn validate_element_decl(
2969 ctxt: *mut _xmlValidCtxt,
2970 doc: *mut _xmlDoc,
2971 elem: *mut _xmlElement,
2972) -> c_int {
2973 unsafe {
2974 if doc.is_null() || (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2975 return 1;
2976 }
2977 if elem.is_null() {
2978 return 1;
2979 }
2980 let mut ret = 1;
2981
2982 if (*elem).etype == XML_ELEMENT_TYPE_MIXED as c_int {
2985 let mut cur = (*elem).content;
2986 while !cur.is_null() {
2987 if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int {
2988 break;
2989 }
2990 if (*cur).c1.is_null() {
2991 break;
2992 }
2993 if (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2994 let name = (*(*cur).c1).name;
2995 let mut next = (*cur).c2;
2996 while !next.is_null() {
2997 if (*next).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2998 if string::xml_strcmp((*next).name, name) == 0
2999 && string::xml_strcmp((*next).prefix, (*(*cur).c1).prefix) == 0
3000 {
3001 if (*(*cur).c1).prefix.is_null() {
3002 let msg = format!(
3003 "Definition of {} has duplicate references of {}\0",
3004 string::xmlstr_to_string((*elem).name),
3005 string::xmlstr_to_string(name)
3006 );
3007 vctxt_error_node(
3008 ctxt,
3009 elem as *mut _xmlNode,
3010 msg.as_ptr() as *const c_char,
3011 );
3012 } else {
3013 let msg = format!(
3014 "Definition of {} has duplicate references of {}:{}\0",
3015 string::xmlstr_to_string((*elem).name),
3016 string::xmlstr_to_string((*(*cur).c1).prefix),
3017 string::xmlstr_to_string(name)
3018 );
3019 vctxt_error_node(
3020 ctxt,
3021 elem as *mut _xmlNode,
3022 msg.as_ptr() as *const c_char,
3023 );
3024 }
3025 ret = 0;
3026 }
3027 break;
3028 }
3029 if (*next).c1.is_null() {
3030 break;
3031 }
3032 if (*(*next).c1).type_ != XML_ELEMENT_CONTENT_ELEMENT as c_int {
3033 break;
3034 }
3035 if string::xml_strcmp((*(*next).c1).name, name) == 0
3036 && string::xml_strcmp((*(*next).c1).prefix, (*(*cur).c1).prefix) == 0
3037 {
3038 if (*(*cur).c1).prefix.is_null() {
3039 let msg = format!(
3040 "Definition of {} has duplicate references to {}\0",
3041 string::xmlstr_to_string((*elem).name),
3042 string::xmlstr_to_string(name)
3043 );
3044 vctxt_error_node(
3045 ctxt,
3046 elem as *mut _xmlNode,
3047 msg.as_ptr() as *const c_char,
3048 );
3049 } else {
3050 let msg = format!(
3051 "Definition of {} has duplicate references to {}:{}\0",
3052 string::xmlstr_to_string((*elem).name),
3053 string::xmlstr_to_string((*(*cur).c1).prefix),
3054 string::xmlstr_to_string(name)
3055 );
3056 vctxt_error_node(
3057 ctxt,
3058 elem as *mut _xmlNode,
3059 msg.as_ptr() as *const c_char,
3060 );
3061 }
3062 ret = 0;
3063 }
3064 next = (*next).c2;
3065 }
3066 }
3067 cur = (*cur).c2;
3068 }
3069 }
3070
3071 let mut prefix = ptr::null_mut();
3074 let local_name = split_qname4((*elem).name, &mut prefix);
3075 if local_name.is_null() {
3076 vctxt_error(
3077 ctxt,
3078 b"Memory allocation failed : xmlValidateElementDecl\0" as *const u8
3079 as *const c_char,
3080 );
3081 if !prefix.is_null() {
3082 allocator::xmlFreeImpl(prefix as *mut c_void);
3083 }
3084 return 0;
3085 }
3086
3087 for subset in [(*doc).intSubset, (*doc).extSubset] {
3088 if subset.is_null() {
3089 continue;
3090 }
3091 let tst = get_dtd_qelement_desc(subset, local_name, prefix);
3092 if !tst.is_null()
3093 && tst != elem
3094 && ((*tst).prefix == (*elem).prefix
3095 || string::xml_strcmp((*tst).prefix, (*elem).prefix) == 0)
3096 && (*tst).etype != XML_ELEMENT_TYPE_UNDEFINED as c_int
3097 {
3098 let msg = format!(
3099 "Redefinition of element {}\0",
3100 string::xmlstr_to_string((*elem).name)
3101 );
3102 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
3103 ret = 0;
3104 }
3105 }
3106 if !prefix.is_null() {
3107 allocator::xmlFreeImpl(prefix as *mut c_void);
3108 }
3109 ret
3110 }
3111}
3112
3113pub const unsafe fn validate_notation_decl(
3132 _ctxt: *mut _xmlValidCtxt,
3133 _doc: *mut _xmlDoc,
3134 _nota: *mut _xmlNotation,
3135) -> c_int {
3136 1
3137}
3138
3139pub unsafe fn validate_one_attribute(
3149 ctxt: *mut _xmlValidCtxt,
3150 doc: *mut _xmlDoc,
3151 elem: *mut _xmlNode,
3152 attr: *mut _xmlAttr,
3153 value: *const xmlChar,
3154) -> c_int {
3155 unsafe {
3156 if doc.is_null() {
3157 return 0;
3158 }
3159 if elem.is_null() || (*elem).name.is_null() {
3160 return 0;
3161 }
3162 if attr.is_null() || (*attr).name.is_null() {
3163 return 0;
3164 }
3165 let mut ret = 1;
3166
3167 let aprefix = if !(*attr).ns.is_null() {
3168 (*(*attr).ns).prefix
3169 } else {
3170 ptr::null()
3171 };
3172
3173 let mut attr_decl = ptr::null_mut();
3174 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3175 let fullname =
3176 string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
3177 if fullname.is_null() {
3178 vctxt_error(
3179 ctxt,
3180 b"Memory allocation failed : xmlValidateOneAttribute\0" as *const u8
3181 as *const c_char,
3182 );
3183 return 0;
3184 }
3185 attr_decl = get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
3186 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3187 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
3188 }
3189 if !std::ptr::eq(fullname, (*elem).name) {
3190 allocator::xmlFreeImpl(fullname as *mut c_void);
3191 }
3192 }
3193 if attr_decl.is_null() {
3194 attr_decl = get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
3195 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3196 attr_decl =
3197 get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
3198 }
3199 }
3200
3201 if attr_decl.is_null() {
3203 let msg = format!(
3204 "No declaration for attribute {} of element {}\0",
3205 string::xmlstr_to_string((*attr).name),
3206 string::xmlstr_to_string((*elem).name)
3207 );
3208 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3209 return 0;
3210 }
3211 if !(*attr).id.is_null() {
3212 remove_id(doc, attr);
3213 }
3214 (*attr).atype = (*attr_decl).atype;
3215
3216 let val = if (*doc).properties & crate::abi::types::xmlDocProperties::XML_DOC_OLD10 as c_int
3218 != 0
3219 {
3220 match (*attr_decl).atype as u32 {
3223 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
3224 validate_values_internal(value, 0)
3225 }
3226 t if t == XML_ATTRIBUTE_ENTITY as u32
3227 || t == XML_ATTRIBUTE_IDREF as u32
3228 || t == XML_ATTRIBUTE_ID as u32
3229 || t == XML_ATTRIBUTE_NOTATION as u32 =>
3230 {
3231 validate_value_internal(value, 0)
3232 }
3233 t if t == XML_ATTRIBUTE_NMTOKENS as u32
3234 || t == XML_ATTRIBUTE_ENUMERATION as u32 =>
3235 {
3236 validate_values_internal(value, XML_SCAN_NMTOKEN)
3237 }
3238 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => {
3239 validate_value_internal(value, XML_SCAN_NMTOKEN)
3240 }
3241 _ => 1,
3242 }
3243 } else {
3244 validate_attribute_value((*attr_decl).atype, value)
3245 };
3246 if val == 0 {
3247 let msg = format!(
3248 "Syntax of value for attribute {} of {} is not valid\0",
3249 string::xmlstr_to_string((*attr).name),
3250 string::xmlstr_to_string((*elem).name)
3251 );
3252 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3253 ret = 0;
3254 }
3255
3256 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3258 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3259 {
3260 let _msg = format!(
3261 "Value for attribute {} of {} is different from default \"{}\n\0",
3262 string::xmlstr_to_string((*attr).name),
3263 string::xmlstr_to_string((*elem).name),
3264 string::xmlstr_to_string((*attr_decl).defaultValue)
3265 );
3266 let msg = format!(
3268 "Value for attribute {} of {} is different from default \"{}\"\0",
3269 string::xmlstr_to_string((*attr).name),
3270 string::xmlstr_to_string((*elem).name),
3271 string::xmlstr_to_string((*attr_decl).defaultValue)
3272 );
3273 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3274 ret = 0;
3275 }
3276
3277 const XML_VCTXT_IN_ENTITY: c_uint = 4; if (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int
3280 && (ctxt.is_null() || (*ctxt).flags & XML_VCTXT_IN_ENTITY == 0)
3281 && add_id(ctxt, doc, value, attr).is_null()
3282 {
3283 ret = 0;
3284 }
3285 if ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
3286 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
3287 && add_ref(ctxt, doc, value, attr).is_null()
3288 {
3289 ret = 0;
3290 }
3291
3292 if (*attr_decl).atype == XML_ATTRIBUTE_NOTATION as c_int {
3294 let mut nota = get_dtd_notation_desc((*doc).intSubset, value);
3295 if nota.is_null() {
3296 nota = get_dtd_notation_desc((*doc).extSubset, value);
3297 }
3298 if nota.is_null() {
3299 let msg = format!(
3300 "Value \"{}\" for attribute {} of {} is not a declared Notation\0",
3301 string::xmlstr_to_string(value),
3302 string::xmlstr_to_string((*attr).name),
3303 string::xmlstr_to_string((*elem).name)
3304 );
3305 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3306 ret = 0;
3307 }
3308 let mut tree = (*attr_decl).tree;
3309 while !tree.is_null() {
3310 if string::xml_strcmp((*tree).name, value) == 0 {
3311 break;
3312 }
3313 tree = (*tree).next;
3314 }
3315 if tree.is_null() {
3316 let msg = format!(
3317 "Value \"{}\" for attribute {} of {} is not among the enumerated notations\0",
3318 string::xmlstr_to_string(value),
3319 string::xmlstr_to_string((*attr).name),
3320 string::xmlstr_to_string((*elem).name)
3321 );
3322 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3323 ret = 0;
3324 }
3325 }
3326
3327 if (*attr_decl).atype == XML_ATTRIBUTE_ENUMERATION as c_int {
3329 let mut tree = (*attr_decl).tree;
3330 while !tree.is_null() {
3331 if string::xml_strcmp((*tree).name, value) == 0 {
3332 break;
3333 }
3334 tree = (*tree).next;
3335 }
3336 if tree.is_null() {
3337 let msg = format!(
3338 "Value \"{}\" for attribute {} of {} is not among the enumerated set\0",
3339 string::xmlstr_to_string(value),
3340 string::xmlstr_to_string((*attr).name),
3341 string::xmlstr_to_string((*elem).name)
3342 );
3343 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3344 ret = 0;
3345 }
3346 }
3347
3348 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3350 && string::xml_strcmp((*attr_decl).defaultValue, value) != 0
3351 {
3352 let msg = format!(
3353 "Value for attribute {} of {} must be \"{}\"\0",
3354 string::xmlstr_to_string((*attr).name),
3355 string::xmlstr_to_string((*elem).name),
3356 string::xmlstr_to_string((*attr_decl).defaultValue)
3357 );
3358 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3359 ret = 0;
3360 }
3361
3362 if (*attr_decl).atype == XML_ATTRIBUTE_ENTITY as c_int {
3364 let ent = tree::get_doc_entity(doc, value);
3365 if ent.is_null() {
3366 let msg = format!(
3367 "ENTITY attribute {} reference an unknown entity \"{}\"\0",
3368 string::xmlstr_to_string((*attr).name),
3369 string::xmlstr_to_string(value)
3370 );
3371 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3372 ret = 0;
3373 } else if (*ent).etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3374 let msg = format!(
3375 "ENTITY attribute {} reference an entity \"{}\" of wrong type\0",
3376 string::xmlstr_to_string((*attr).name),
3377 string::xmlstr_to_string(value)
3378 );
3379 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3380 ret = 0;
3381 }
3382 }
3383 ret
3384 }
3385}
3386
3387pub unsafe fn validate_one_namespace(
3394 ctxt: *mut _xmlValidCtxt,
3395 doc: *mut _xmlDoc,
3396 elem: *mut _xmlNode,
3397 prefix: *const xmlChar,
3398 ns: *mut _xmlNs,
3399 value: *const xmlChar,
3400) -> c_int {
3401 unsafe {
3402 if doc.is_null() {
3403 return 0;
3404 }
3405 if elem.is_null() || (*elem).name.is_null() {
3406 return 0;
3407 }
3408 if ns.is_null() || (*ns).href.is_null() {
3409 return 0;
3410 }
3411 let mut ret = 1;
3412
3413 let mut attr_decl = ptr::null_mut();
3414 if !prefix.is_null() {
3415 let fullname = string::build_qname((*elem).name, prefix, ptr::null_mut(), 0);
3416 if fullname.is_null() {
3417 vctxt_error(
3418 ctxt,
3419 b"Memory allocation failed : xmlValidateOneNamespace\0" as *const u8
3420 as *const c_char,
3421 );
3422 return 0;
3423 }
3424 if !(*ns).prefix.is_null() {
3425 attr_decl = get_dtd_qattr_desc(
3426 (*doc).intSubset,
3427 fullname,
3428 (*ns).prefix,
3429 b"xmlns\0" as *const u8 as *const xmlChar,
3430 );
3431 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3432 attr_decl = get_dtd_qattr_desc(
3433 (*doc).extSubset,
3434 fullname,
3435 (*ns).prefix,
3436 b"xmlns\0" as *const u8 as *const xmlChar,
3437 );
3438 }
3439 } else {
3440 attr_decl = get_dtd_qattr_desc(
3441 (*doc).intSubset,
3442 fullname,
3443 b"xmlns\0" as *const u8 as *const xmlChar,
3444 ptr::null(),
3445 );
3446 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3447 attr_decl = get_dtd_qattr_desc(
3448 (*doc).extSubset,
3449 fullname,
3450 b"xmlns\0" as *const u8 as *const xmlChar,
3451 ptr::null(),
3452 );
3453 }
3454 }
3455 if !std::ptr::eq(fullname, (*elem).name) {
3456 allocator::xmlFreeImpl(fullname as *mut c_void);
3457 }
3458 }
3459 if attr_decl.is_null() {
3460 if !(*ns).prefix.is_null() {
3461 attr_decl = get_dtd_qattr_desc(
3462 (*doc).intSubset,
3463 (*elem).name,
3464 (*ns).prefix,
3465 b"xmlns\0" as *const u8 as *const xmlChar,
3466 );
3467 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3468 attr_decl = get_dtd_qattr_desc(
3469 (*doc).extSubset,
3470 (*elem).name,
3471 (*ns).prefix,
3472 b"xmlns\0" as *const u8 as *const xmlChar,
3473 );
3474 }
3475 } else {
3476 attr_decl = get_dtd_qattr_desc(
3477 (*doc).intSubset,
3478 (*elem).name,
3479 b"xmlns\0" as *const u8 as *const xmlChar,
3480 ptr::null(),
3481 );
3482 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3483 attr_decl = get_dtd_qattr_desc(
3484 (*doc).extSubset,
3485 (*elem).name,
3486 b"xmlns\0" as *const u8 as *const xmlChar,
3487 ptr::null(),
3488 );
3489 }
3490 }
3491 }
3492
3493 if attr_decl.is_null() {
3495 let msg = if !(*ns).prefix.is_null() {
3496 format!(
3497 "No declaration for attribute xmlns:{} of element {}\0",
3498 string::xmlstr_to_string((*ns).prefix),
3499 string::xmlstr_to_string((*elem).name)
3500 )
3501 } else {
3502 format!(
3503 "No declaration for attribute xmlns of element {}\0",
3504 string::xmlstr_to_string((*elem).name)
3505 )
3506 };
3507 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3508 return 0;
3509 }
3510
3511 let val = validate_attribute_value((*attr_decl).atype, value);
3512 if val == 0 {
3513 let msg = if !(*ns).prefix.is_null() {
3514 format!(
3515 "Syntax of value for attribute xmlns:{} of {} is not valid\0",
3516 string::xmlstr_to_string((*ns).prefix),
3517 string::xmlstr_to_string((*elem).name)
3518 )
3519 } else {
3520 format!(
3521 "Syntax of value for attribute xmlns of {} is not valid\0",
3522 string::xmlstr_to_string((*elem).name)
3523 )
3524 };
3525 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3526 ret = 0;
3527 }
3528
3529 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3531 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3532 {
3533 let msg = if !(*ns).prefix.is_null() {
3534 format!(
3535 "Value for attribute xmlns:{} of {} is different from default \"{}\"\0",
3536 string::xmlstr_to_string((*ns).prefix),
3537 string::xmlstr_to_string((*elem).name),
3538 string::xmlstr_to_string((*attr_decl).defaultValue)
3539 )
3540 } else {
3541 format!(
3542 "Value for attribute xmlns of {} is different from default \"{}\"\0",
3543 string::xmlstr_to_string((*elem).name),
3544 string::xmlstr_to_string((*attr_decl).defaultValue)
3545 )
3546 };
3547 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3548 ret = 0;
3549 }
3550 ret
3551 }
3552}
3553
3554pub unsafe fn validate_one_element(
3562 ctxt: *mut _xmlValidCtxt,
3563 doc: *mut _xmlDoc,
3564 elem: *mut _xmlNode,
3565) -> c_int {
3566 unsafe {
3567 if doc.is_null() {
3568 return 0;
3569 }
3570 if elem.is_null() {
3571 return 0;
3572 }
3573 match (*elem).type_ {
3574 t if t == XML_TEXT_NODE as c_int
3575 || t == XML_CDATA_SECTION_NODE as c_int
3576 || t == XML_ENTITY_REF_NODE as c_int
3577 || t == XML_PI_NODE as c_int
3578 || t == XML_COMMENT_NODE as c_int
3579 || t == XML_XINCLUDE_START as c_int
3580 || t == XML_XINCLUDE_END as c_int =>
3581 {
3582 return 1;
3583 }
3584 t if t == XML_ELEMENT_NODE as c_int => {}
3585 _ => {
3586 vctxt_error_node(
3587 ctxt,
3588 elem,
3589 b"unexpected element type\0" as *const u8 as *const c_char,
3590 );
3591 return 0;
3592 }
3593 }
3594
3595 let mut ret = 1;
3596 let mut extsubset = 0;
3597 let elem_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
3598 if elem_decl.is_null() {
3599 return 0;
3600 }
3601
3602 if (*ctxt).vstateNr == 0 {
3605 match (*elem_decl).etype as u32 {
3606 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => {
3607 let msg = format!(
3608 "No declaration for element {}\0",
3609 string::xmlstr_to_string((*elem).name)
3610 );
3611 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3612 return 0;
3613 }
3614 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
3615 if !(*elem).children.is_null() {
3616 let msg = format!(
3617 "Element {} was declared EMPTY this one has content\0",
3618 string::xmlstr_to_string((*elem).name)
3619 );
3620 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3621 ret = 0;
3622 }
3623 }
3624 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
3625 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
3626 if !(*elem_decl).content.is_null()
3627 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
3628 {
3629 let mut child = (*elem).children;
3631 while !child.is_null() {
3632 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3633 let msg = format!(
3634 "Element {} was declared #PCDATA but contains non text nodes\0",
3635 string::xmlstr_to_string((*elem).name)
3636 );
3637 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3638 ret = 0;
3639 break;
3640 }
3641 child = (*child).next;
3642 }
3643 } else {
3644 let mut child = (*elem).children;
3646 while !child.is_null() {
3647 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3648 let mut fullname = (*child).name;
3649 let mut own = false;
3650 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3651 let fnp = string::build_qname(
3652 (*child).name,
3653 (*(*child).ns).prefix,
3654 ptr::null_mut(),
3655 0,
3656 );
3657 if fnp.is_null() {
3658 vctxt_error(
3659 ctxt,
3660 b"Memory allocation failed : xmlValidateOneElement\0"
3661 as *const u8
3662 as *const c_char,
3663 );
3664 return 0;
3665 }
3666 fullname = fnp;
3667 own = true;
3668 }
3669 if validate_check_mixed(ctxt, (*elem_decl).content, fullname) != 1 {
3670 let msg = format!(
3671 "Element {} is not declared in {} list of possible children\0",
3672 string::xmlstr_to_string(fullname),
3673 string::xmlstr_to_string((*elem).name)
3674 );
3675 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3676 ret = 0;
3677 }
3678 if own {
3679 allocator::xmlFreeImpl(fullname as *mut c_void);
3680 }
3681 }
3682 child = (*child).next;
3683 }
3684 }
3685 }
3686 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
3687 let mut names: Vec<*const xmlChar> = Vec::new();
3690 let mut owned: Vec<*mut xmlChar> = Vec::new();
3691 let mut child = (*elem).children;
3692 while !child.is_null() {
3693 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3694 let mut fullname = (*child).name;
3695 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3696 let fnp = string::build_qname(
3697 (*child).name,
3698 (*(*child).ns).prefix,
3699 ptr::null_mut(),
3700 0,
3701 );
3702 if !fnp.is_null() {
3703 fullname = fnp;
3704 owned.push(fnp);
3705 }
3706 }
3707 names.push(fullname);
3708 }
3709 child = (*child).next;
3710 }
3711 let result = dtd::valid_content_model((*elem_decl).content, &names);
3712 for n in owned {
3713 allocator::xmlFreeImpl(n as *mut c_void);
3714 }
3715 if result != dtd::ContentModelResult::Valid {
3716 let msg = format!(
3717 "Element {} content does not follow the DTD\0",
3718 string::xmlstr_to_string((*elem).name)
3719 );
3720 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3721 ret = 0;
3722 }
3723 }
3724 _ => {}
3725 }
3726
3727 let mut attr = (*elem).properties;
3729 while !attr.is_null() {
3730 let aval = if !(*attr).children.is_null() {
3731 (*(*attr).children).content
3732 } else {
3733 ptr::null()
3734 };
3735 if validate_one_attribute(ctxt, doc, elem, attr, aval) == 0 {
3736 ret = 0;
3737 }
3738 attr = (*attr).next;
3739 }
3740 }
3741 ret
3742 }
3743}
3744
3745#[repr(C)]
3760struct ValidState {
3761 elem_decl: *mut _xmlElement,
3762 node: *mut _xmlNode,
3763 exec: *mut ContentModelExec,
3764}
3765
3766unsafe fn valid_get_elem_decl(
3778 ctxt: *mut _xmlValidCtxt,
3779 doc: *mut _xmlDoc,
3780 elem: *mut _xmlNode,
3781 extsubset: *mut c_int,
3782) -> *mut _xmlElement {
3783 unsafe {
3784 if ctxt.is_null() || doc.is_null() || elem.is_null() || (*elem).name.is_null() {
3785 return ptr::null_mut();
3786 }
3787 if !extsubset.is_null() {
3788 *extsubset = 0;
3789 }
3790 let mut elem_decl = ptr::null_mut();
3791
3792 let prefix = if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3793 (*(*elem).ns).prefix
3794 } else {
3795 ptr::null()
3796 };
3797 if !prefix.is_null() {
3798 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, prefix);
3799 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3800 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, prefix);
3801 if !elem_decl.is_null() && !extsubset.is_null() {
3802 *extsubset = 1;
3803 }
3804 }
3805 }
3806 if elem_decl.is_null() {
3807 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, ptr::null());
3809 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3810 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, ptr::null());
3811 if !elem_decl.is_null() && !extsubset.is_null() {
3812 *extsubset = 1;
3813 }
3814 }
3815 }
3816 if elem_decl.is_null() {
3817 let msg = format!(
3818 "No declaration for element {}\0",
3819 string::xmlstr_to_string((*elem).name)
3820 );
3821 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3822 }
3823 elem_decl
3824 }
3825}
3826
3827unsafe fn validate_check_mixed(
3838 ctxt: *mut _xmlValidCtxt,
3839 cont: *mut _xmlElementContent,
3840 qname: *const xmlChar,
3841) -> c_int {
3842 unsafe {
3843 let mut plen: c_int = 0;
3844 let local = string::split_qname3(qname, &mut plen);
3848 let mut cur = cont;
3849 if local.is_null() {
3850 while !cur.is_null() {
3851 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3852 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
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_ELEMENT as c_int
3858 {
3859 if (*(*cur).c1).prefix.is_null()
3860 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3861 {
3862 return 1;
3863 }
3864 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3865 || (*cur).c1.is_null()
3866 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3867 {
3868 vctxt_error(
3869 ctxt,
3870 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3871 );
3872 break;
3873 }
3874 cur = (*cur).c2;
3875 }
3876 } else {
3877 while !cur.is_null() {
3878 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3879 if !(*cur).prefix.is_null()
3880 && prefix_matches((*cur).prefix, qname, plen)
3881 && string::xml_strcmp((*cur).name, local) == 0
3882 {
3883 return 1;
3884 }
3885 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3886 && !(*cur).c1.is_null()
3887 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3888 {
3889 if !(*(*cur).c1).prefix.is_null()
3890 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3891 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3892 {
3893 return 1;
3894 }
3895 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3896 || (*cur).c1.is_null()
3897 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3898 {
3899 vctxt_error(
3900 ctxt,
3901 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3902 );
3903 break;
3904 }
3905 cur = (*cur).c2;
3906 }
3907 }
3908 0
3909 }
3910}
3911
3912unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
3922 unsafe {
3923 let p = string::xmlstr_to_bytes(prefix);
3924 let q = string::xmlstr_to_bytes(qname);
3925 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
3926 }
3927}
3928
3929#[derive(Debug)]
3938#[repr(C)]
3939pub struct ContentModelNfa {
3940 transitions: Vec<(u32, *const xmlChar, u32)>,
3942 start: u32,
3944 accept: Vec<u32>,
3946}
3947
3948#[derive(Debug)]
3950#[repr(C)]
3951pub struct ContentModelExec {
3952 nfa: *mut ContentModelNfa,
3954 current: Vec<u32>,
3956}
3957
3958struct NfaBuilder {
3960 transitions: Vec<(u32, *const xmlChar, u32)>,
3961 n_states: u32,
3962}
3963
3964impl NfaBuilder {
3965 const fn new() -> Self {
3966 NfaBuilder {
3967 transitions: Vec::new(),
3968 n_states: 0,
3969 }
3970 }
3971 const fn new_state(&mut self) -> u32 {
3972 let s = self.n_states;
3973 self.n_states += 1;
3974 s
3975 }
3976 fn eps(&mut self, from: u32, to: u32) {
3977 self.transitions.push((from, ptr::null(), to));
3978 }
3979 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
3980 self.transitions.push((from, name, to));
3981 }
3982}
3983
3984unsafe fn compile_content_sub(
3997 b: &mut NfaBuilder,
3998 model: *mut _xmlElementContent,
3999) -> (u32, Vec<u32>) {
4000 if model.is_null() {
4001 let s = b.new_state();
4002 return (s, vec![s]);
4003 }
4004 let m = unsafe { &*model };
4005 let (mut in_s, outs) = match m.type_ as u32 {
4006 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
4007 let s = b.new_state();
4008 let to = b.new_state();
4009 b.name_trans(s, m.name, to);
4010 (s, vec![to])
4011 }
4012 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
4013 let (in1, out1) = compile_content_sub(b, m.c1);
4014 let (in2, out2) = compile_content_sub(b, m.c2);
4015 for &o in &out1 {
4016 b.eps(o, in2);
4017 }
4018 (in1, out2)
4019 }
4020 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
4021 let (in1, out1) = compile_content_sub(b, m.c1);
4022 let (in2, out2) = compile_content_sub(b, m.c2);
4023 let s = b.new_state();
4024 b.eps(s, in1);
4025 b.eps(s, in2);
4026 let mut all = out1;
4027 all.extend(out2);
4028 (s, all)
4029 }
4030 _ => {
4035 let s = b.new_state();
4036 (s, vec![s])
4037 }
4038 };
4039 match m.ocur as u32 {
4040 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
4041 let s = b.new_state();
4042 b.eps(s, in_s);
4043 for &o2 in &outs {
4044 b.eps(s, o2);
4045 }
4046 in_s = s;
4047 }
4048 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
4049 let s = b.new_state();
4050 b.eps(s, in_s);
4051 for &o2 in &outs {
4052 b.eps(s, o2);
4053 b.eps(o2, s);
4054 }
4055 in_s = s;
4056 }
4057 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
4058 let s = b.new_state();
4059 b.eps(s, in_s);
4060 for &o2 in &outs {
4061 b.eps(o2, s);
4062 }
4063 in_s = s;
4064 }
4065 _ => {}
4066 }
4067 (in_s, outs)
4068}
4069
4070unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
4072 if model.is_null() {
4073 return false;
4074 }
4075 unsafe {
4076 let m = &*model;
4077 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
4078 return true;
4079 }
4080 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
4081 }
4082}
4083
4084unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
4090 unsafe {
4091 if content.is_null() {
4092 return ptr::null_mut();
4093 }
4094 let mut b = NfaBuilder::new();
4095 let (start, outs) = compile_content_sub(&mut b, content);
4096 let nfa = Box::new(ContentModelNfa {
4097 transitions: b.transitions,
4098 start,
4099 accept: outs,
4100 });
4101 Box::into_raw(nfa)
4102 }
4103}
4104
4105pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
4111 if nfa.is_null() {
4112 return;
4113 }
4114 unsafe {
4115 ptr::drop_in_place(nfa);
4116 allocator::xmlFreeImpl(nfa as *mut c_void);
4117 }
4118}
4119
4120unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4122 let mut out = states.to_vec();
4123 let mut stack = states.to_vec();
4124 while let Some(s) = stack.pop() {
4125 for &(from, name, to) in &nfa.transitions {
4126 if from == s && name.is_null() && !out.contains(&to) {
4127 out.push(to);
4128 stack.push(to);
4129 }
4130 }
4131 }
4132 out.sort_unstable();
4133 out.dedup();
4134 out
4135}
4136
4137unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4145 unsafe {
4146 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4147 if exec.is_null() {
4148 return ptr::null_mut();
4149 }
4150 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4151 ptr::write(&mut (*exec).nfa, nfa);
4152 ptr::write(&mut (*exec).current, cur);
4153 exec
4154 }
4155}
4156
4157unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4166 if exec.is_null() {
4167 return;
4168 }
4169 unsafe {
4170 ptr::drop_in_place(&mut (*exec).current);
4171 allocator::xmlFreeImpl(exec as *mut c_void);
4172 }
4173}
4174
4175unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4187 unsafe {
4188 if exec.is_null() {
4189 return -1;
4190 }
4191 let nfa = &*(*exec).nfa;
4192 if value.is_null() {
4193 let cur = eps_closure(nfa, &(*exec).current);
4194 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4195 1
4196 } else {
4197 0
4198 };
4199 }
4200 let mut next: Vec<u32> = Vec::new();
4201 for &s in &(*exec).current {
4202 for &(from, name, to) in &nfa.transitions {
4203 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4204 next.push(to);
4205 }
4206 }
4207 }
4208 next.sort_unstable();
4209 next.dedup();
4210 if next.is_empty() {
4211 return -1;
4212 }
4213 let closed = eps_closure(nfa, &next);
4214 (*exec).current = closed;
4215 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4216 1
4217 } else {
4218 0
4219 }
4220 }
4221}
4222
4223unsafe fn vstate_vpush(
4234 ctxt: *mut _xmlValidCtxt,
4235 elem_decl: *mut _xmlElement,
4236 node: *mut _xmlNode,
4237) -> c_int {
4238 unsafe {
4239 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4240 let new_max = if (*ctxt).vstateMax == 0 {
4241 10
4242 } else {
4243 (*ctxt).vstateMax * 2
4244 };
4245 let new_tab = allocator::xmlReallocImpl(
4246 (*ctxt).vstateTab,
4247 (new_max as usize) * size_of::<ValidState>(),
4248 ) as *mut ValidState;
4249 if new_tab.is_null() {
4250 vctxt_error(
4251 ctxt,
4252 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4253 );
4254 return -1;
4255 }
4256 (*ctxt).vstateTab = new_tab as *mut c_void;
4257 (*ctxt).vstateMax = new_max;
4258 }
4259 let idx = (*ctxt).vstateNr as usize;
4260 let tab = (*ctxt).vstateTab as *mut ValidState;
4261 (*tab.add(idx)).elem_decl = elem_decl;
4262 (*tab.add(idx)).node = node;
4263 (*tab.add(idx)).exec = ptr::null_mut();
4264 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4265 if (*elem_decl).cont_model.is_null() {
4266 validate_build_content_model(ctxt, elem_decl);
4267 }
4268 if !(*elem_decl).cont_model.is_null() {
4269 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4270 if exec.is_null() {
4271 vctxt_error(
4272 ctxt,
4273 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4274 );
4275 return -1;
4276 }
4277 (*tab.add(idx)).exec = exec;
4278 } else {
4279 let msg = format!(
4280 "Failed to build content model regexp for {}\0",
4281 string::xmlstr_to_string((*elem_decl).name)
4282 );
4283 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4284 }
4285 }
4286 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4287 (*ctxt).vstateNr += 1;
4288 0
4289 }
4290}
4291
4292unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4301 unsafe {
4302 if (*ctxt).vstateNr < 1 {
4303 return -1;
4304 }
4305 (*ctxt).vstateNr -= 1;
4306 let idx = (*ctxt).vstateNr as usize;
4307 let tab = (*ctxt).vstateTab as *mut ValidState;
4308 let elem_decl = (*tab.add(idx)).elem_decl;
4309 (*tab.add(idx)).elem_decl = ptr::null_mut();
4310 (*tab.add(idx)).node = ptr::null_mut();
4311 if !elem_decl.is_null()
4312 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4313 && !(*tab.add(idx)).exec.is_null()
4314 {
4315 free_content_exec((*tab.add(idx)).exec);
4316 }
4317 (*tab.add(idx)).exec = ptr::null_mut();
4318 if (*ctxt).vstateNr >= 1 {
4319 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4320 } else {
4321 (*ctxt).vstate = ptr::null_mut();
4322 }
4323 0
4324 }
4325}
4326
4327pub unsafe fn validate_build_content_model(
4335 ctxt: *mut _xmlValidCtxt,
4336 elem: *mut _xmlElement,
4337) -> c_int {
4338 unsafe {
4339 if ctxt.is_null() {
4340 return 0;
4341 }
4342 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4343 return 0;
4344 }
4345 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4346 return 1;
4347 }
4348 if !(*elem).cont_model.is_null() {
4349 return 1;
4350 }
4351 if (*elem).content.is_null() {
4352 return 1;
4353 }
4354 if content_has_pcdata((*elem).content) {
4355 let msg = format!(
4356 "Found PCDATA in content model of {}\0",
4357 string::xmlstr_to_string((*elem).name)
4358 );
4359 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4360 return 0;
4361 }
4362 let nfa = build_content_nfa((*elem).content);
4363 if nfa.is_null() {
4364 vctxt_error(
4365 ctxt,
4366 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4367 as *const c_char,
4368 );
4369 return 0;
4370 }
4371 (*elem).cont_model = nfa as *mut c_void;
4372 1
4373 }
4374}
4375
4376pub unsafe fn validate_push_element(
4384 ctxt: *mut _xmlValidCtxt,
4385 doc: *mut _xmlDoc,
4386 elem: *mut _xmlNode,
4387 qname: *const xmlChar,
4388) -> c_int {
4389 unsafe {
4390 let mut ret = 1;
4391 if ctxt.is_null() {
4392 return 0;
4393 }
4394 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4395 let state = (*ctxt).vstate as *mut ValidState;
4396 let elem_decl = (*state).elem_decl;
4397 if !elem_decl.is_null() {
4398 match (*elem_decl).etype as u32 {
4399 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4400 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4401 let msg = format!(
4402 "Element {} was declared EMPTY this one has content\0",
4403 string::xmlstr_to_string((*(*state).node).name)
4404 );
4405 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4406 ret = 0;
4407 }
4408 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4409 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4410 if !(*elem_decl).content.is_null()
4411 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4412 {
4413 let msg = format!(
4414 "Element {} was declared #PCDATA but contains non text nodes\0",
4415 string::xmlstr_to_string((*(*state).node).name)
4416 );
4417 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4418 ret = 0;
4419 } else {
4420 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4421 if ret != 1 {
4422 let msg = format!(
4423 "Element {} is not declared in {} list of possible children\0",
4424 string::xmlstr_to_string(qname),
4425 string::xmlstr_to_string((*(*state).node).name)
4426 );
4427 vctxt_error_node(
4428 ctxt,
4429 (*state).node,
4430 msg.as_ptr() as *const c_char,
4431 );
4432 }
4433 }
4434 }
4435 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 && !(*state).exec.is_null() => {
4436 ret = content_exec_push((*state).exec, qname);
4437 if ret < 0 {
4438 let msg = format!(
4439 "Element {} content does not follow the DTD, Misplaced {}\0",
4440 string::xmlstr_to_string((*(*state).node).name),
4441 string::xmlstr_to_string(qname)
4442 );
4443 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4444 ret = 0;
4445 } else {
4446 ret = 1;
4447 }
4448 }
4449 _ => {}
4450 }
4451 }
4452 }
4453 let mut extsubset = 0;
4454 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4455 let _ = vstate_vpush(ctxt, e_decl, elem);
4457 ret
4458 }
4459}
4460
4461pub unsafe fn validate_push_cdata(
4468 ctxt: *mut _xmlValidCtxt,
4469 data: *const xmlChar,
4470 len: c_int,
4471) -> c_int {
4472 unsafe {
4473 let mut ret = 1;
4474 if ctxt.is_null() {
4475 return 0;
4476 }
4477 if len <= 0 {
4478 return 1;
4479 }
4480 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4481 let state = (*ctxt).vstate as *mut ValidState;
4482 let elem_decl = (*state).elem_decl;
4483 if !elem_decl.is_null() {
4484 match (*elem_decl).etype as u32 {
4485 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4486 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4487 let msg = format!(
4488 "Element {} was declared EMPTY this one has content\0",
4489 string::xmlstr_to_string((*(*state).node).name)
4490 );
4491 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4492 ret = 0;
4493 }
4494 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4495 }
4496 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4497 let bytes = core::slice::from_raw_parts(data, len as usize);
4498 for &b in bytes {
4499 if !is_blank_byte(b) {
4500 let msg = format!(
4501 "Element {} content does not follow the DTD, Text not allowed\0",
4502 string::xmlstr_to_string((*(*state).node).name)
4503 );
4504 vctxt_error_node(
4505 ctxt,
4506 (*state).node,
4507 msg.as_ptr() as *const c_char,
4508 );
4509 ret = 0;
4510 break;
4511 }
4512 }
4513 }
4514 _ => {}
4515 }
4516 }
4517 }
4518 ret
4519 }
4520}
4521
4522pub unsafe fn validate_pop_element(
4529 ctxt: *mut _xmlValidCtxt,
4530 _doc: *mut _xmlDoc,
4531 _elem: *mut _xmlNode,
4532 _qname: *const xmlChar,
4533) -> c_int {
4534 unsafe {
4535 let mut ret = 1;
4536 if ctxt.is_null() {
4537 return 0;
4538 }
4539 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4540 let state = (*ctxt).vstate as *mut ValidState;
4541 let elem_decl = (*state).elem_decl;
4542 if !elem_decl.is_null()
4543 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4544 && !(*state).exec.is_null()
4545 {
4546 ret = content_exec_push((*state).exec, ptr::null());
4547 if ret <= 0 {
4548 let msg = format!(
4549 "Element {} content does not follow the DTD, Expecting more children\0",
4550 string::xmlstr_to_string((*(*state).node).name)
4551 );
4552 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4553 ret = 0;
4554 } else {
4555 ret = 1;
4556 }
4557 }
4558 let _ = vstate_vpop(ctxt);
4559 }
4560 ret
4561 }
4562}
4563
4564#[cfg(test)]
4569mod tests {
4570 use super::*;
4571 use crate::abi::allocator;
4572
4573 use crate::xml::dtd;
4574 use crate::xml::tree;
4575
4576 unsafe fn c_str(s: &str) -> *const xmlChar {
4580 let bytes = s.as_bytes();
4581 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4582 assert!(!ptr.is_null());
4583 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4584 *ptr.add(bytes.len()) = 0;
4585 ptr
4586 }
4587
4588 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4590 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4591 assert!(!doc.is_null());
4592
4593 let name = c_str("root");
4594 let ext_id = c_str("--//Test//DTD//EN");
4595 let sys_id = c_str("test.dtd");
4596 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4597 assert!(!dtd.is_null());
4598
4599 (doc, dtd)
4600 }
4601
4602 #[allow(unused)]
4604 unsafe fn add_elem_decl(
4605 dtd: *mut _xmlDtd,
4606 name: *const xmlChar,
4607 elem_type: c_int,
4608 content: *mut _xmlElementContent,
4609 ) -> *mut _xmlElement {
4610 dtd::add_element_decl(dtd, name, elem_type, content)
4611 }
4612
4613 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4615 let node = tree::new_node(ptr::null_mut(), name);
4616 assert!(!node.is_null());
4617 tree::add_child(doc as *mut _xmlNode, node);
4618 node
4619 }
4620
4621 #[allow(unused)]
4623 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4624 let node = tree::new_node(ptr::null_mut(), name);
4625 assert!(!node.is_null());
4626 tree::add_child(parent, node);
4627 node
4628 }
4629
4630 #[test]
4640 fn test_validate_name_null() {
4641 unsafe {
4642 assert_eq!(validate_name(ptr::null()), 0);
4643 }
4644 }
4645
4646 #[test]
4654 fn test_validate_name_empty() {
4655 unsafe {
4656 let s = b"\0" as *const u8 as *const xmlChar;
4657 assert_eq!(validate_name(s), 0);
4658 }
4659 }
4660
4661 #[test]
4669 fn test_validate_name_valid() {
4670 unsafe {
4671 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4672 for t in &tests {
4673 let s = c_str(t);
4674 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4675 allocator::xmlFreeImpl(s as *mut c_void);
4676 }
4677 }
4678 }
4679
4680 #[test]
4688 fn test_validate_name_invalid() {
4689 unsafe {
4690 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4691 for t in &tests {
4692 let s = c_str(t);
4693 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4694 allocator::xmlFreeImpl(s as *mut c_void);
4695 }
4696 }
4697 }
4698
4699 #[test]
4707 fn test_validate_names_valid() {
4708 unsafe {
4709 let s = c_str("foo bar baz");
4710 assert_eq!(validate_names(s), 1);
4711 allocator::xmlFreeImpl(s as *mut c_void);
4712 }
4713 }
4714
4715 #[test]
4723 fn test_validate_names_invalid() {
4724 unsafe {
4725 let s = c_str("foo 123bar baz");
4726 assert_eq!(validate_names(s), 0);
4727 allocator::xmlFreeImpl(s as *mut c_void);
4728 }
4729 }
4730
4731 #[test]
4740 fn test_validate_nmtoken_null() {
4741 unsafe {
4742 assert_eq!(validate_nmtoken(ptr::null()), 0);
4743 }
4744 }
4745
4746 #[test]
4754 fn test_validate_nmtoken_valid() {
4755 unsafe {
4756 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4757 for t in &tests {
4758 let s = c_str(t);
4759 assert_eq!(
4760 validate_nmtoken(s),
4761 1,
4762 "Expected '{}' to be a valid NMTOKEN",
4763 t
4764 );
4765 allocator::xmlFreeImpl(s as *mut c_void);
4766 }
4767 }
4768 }
4769
4770 #[test]
4778 fn test_validate_nmtoken_invalid() {
4779 unsafe {
4780 let s = c_str("foo bar");
4781 assert_eq!(validate_nmtoken(s), 0);
4782 allocator::xmlFreeImpl(s as *mut c_void);
4783 }
4784 }
4785
4786 #[test]
4794 fn test_validate_nmtokens_valid() {
4795 unsafe {
4796 let s = c_str("foo 123bar -baz");
4797 assert_eq!(validate_nmtokens(s), 1);
4798 allocator::xmlFreeImpl(s as *mut c_void);
4799 }
4800 }
4801
4802 #[test]
4813 fn test_validate_attribute_value_cdata() {
4814 unsafe {
4815 let s = c_str("anything goes here!@#$%^&*()");
4816 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4817 allocator::xmlFreeImpl(s as *mut c_void);
4818
4819 let empty = b"\0" as *const u8 as *const xmlChar;
4821 assert_eq!(
4822 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4823 1
4824 );
4825 }
4826 }
4827
4828 #[test]
4836 fn test_validate_attribute_value_id() {
4837 unsafe {
4838 let valid = c_str("myId");
4839 assert_eq!(
4840 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4841 1
4842 );
4843 allocator::xmlFreeImpl(valid as *mut c_void);
4844
4845 let invalid = c_str("123id");
4846 assert_eq!(
4847 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4848 0
4849 );
4850 allocator::xmlFreeImpl(invalid as *mut c_void);
4851 }
4852 }
4853
4854 #[test]
4861 fn test_validate_attribute_value_idref() {
4862 unsafe {
4863 let valid = c_str("someId");
4864 assert_eq!(
4865 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4866 1
4867 );
4868 allocator::xmlFreeImpl(valid as *mut c_void);
4869 }
4870 }
4871
4872 #[test]
4880 fn test_validate_attribute_value_idrefs() {
4881 unsafe {
4882 let valid = c_str("id1 id2 id3");
4883 assert_eq!(
4884 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4885 1
4886 );
4887 allocator::xmlFreeImpl(valid as *mut c_void);
4888
4889 let invalid = c_str("id1 123id");
4890 assert_eq!(
4891 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4892 0
4893 );
4894 allocator::xmlFreeImpl(invalid as *mut c_void);
4895 }
4896 }
4897
4898 #[test]
4905 fn test_validate_attribute_value_entity() {
4906 unsafe {
4907 let valid = c_str("myEntity");
4908 assert_eq!(
4909 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
4910 1
4911 );
4912 allocator::xmlFreeImpl(valid as *mut c_void);
4913 }
4914 }
4915
4916 #[test]
4925 fn test_validate_attribute_value_nmtoken() {
4926 unsafe {
4927 let valid = c_str("123abc");
4928 assert_eq!(
4929 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
4930 1
4931 );
4932 allocator::xmlFreeImpl(valid as *mut c_void);
4933
4934 let invalid = c_str("foo bar");
4935 assert_eq!(
4936 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
4937 0
4938 );
4939 allocator::xmlFreeImpl(invalid as *mut c_void);
4940 }
4941 }
4942
4943 #[test]
4951 fn test_validate_attribute_value_null() {
4952 unsafe {
4953 assert_eq!(
4957 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
4958 1
4959 );
4960 assert_eq!(
4961 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
4962 0
4963 );
4964 }
4965 }
4966
4967 #[test]
4979 fn test_validate_enumeration_valid() {
4980 unsafe {
4981 let ctxt = new_valid_ctxt();
4982 assert!(!ctxt.is_null());
4983
4984 let red = c_str("red");
4985 let green = c_str("green");
4986 let blue = c_str("blue");
4987
4988 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4989 (*e3).name = string::xml_strdup(blue);
4990 (*e3).next = ptr::null_mut();
4991
4992 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4993 (*e2).name = string::xml_strdup(green);
4994 (*e2).next = e3;
4995
4996 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4997 (*e1).name = string::xml_strdup(red);
4998 (*e1).next = e2;
4999
5000 let value = c_str("green");
5001 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
5002 assert_eq!((*ctxt).valid, 1);
5003
5004 allocator::xmlFreeImpl(value as *mut c_void);
5005 allocator::xmlFreeImpl(red as *mut c_void);
5006 allocator::xmlFreeImpl(green as *mut c_void);
5007 allocator::xmlFreeImpl(blue as *mut c_void);
5008 free_valid_ctxt(ctxt);
5009 }
5010 }
5011
5012 #[test]
5021 fn test_validate_enumeration_invalid() {
5022 unsafe {
5023 let ctxt = new_valid_ctxt();
5024 assert!(!ctxt.is_null());
5025
5026 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
5027 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
5028 (*e1).next = ptr::null_mut();
5029
5030 let value = c_str("yellow");
5031 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
5032
5033 allocator::xmlFreeImpl(value as *mut c_void);
5034 free_valid_ctxt(ctxt);
5035 }
5036 }
5037
5038 #[test]
5049 fn test_validate_notation_use_valid() {
5050 unsafe {
5051 let (doc, dtd) = make_test_doc();
5052
5053 let notation_name = c_str("GIF");
5054 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
5055
5056 let ctxt = new_valid_ctxt();
5057 assert!(!ctxt.is_null());
5058
5059 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
5060
5061 free_valid_ctxt(ctxt);
5062 tree::free_doc(doc);
5063 }
5064 }
5065
5066 #[test]
5075 fn test_validate_notation_use_invalid() {
5076 unsafe {
5077 let (doc, _dtd) = make_test_doc();
5078
5079 let ctxt = new_valid_ctxt();
5080 assert!(!ctxt.is_null());
5081
5082 let notation_name = c_str("UNDECLARED");
5083 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
5084
5085 free_valid_ctxt(ctxt);
5086 allocator::xmlFreeImpl(notation_name as *mut c_void);
5087 tree::free_doc(doc);
5088 }
5089 }
5090
5091 #[test]
5102 fn test_new_free_valid_ctxt() {
5103 unsafe {
5104 let ctxt = new_valid_ctxt();
5105 assert!(!ctxt.is_null());
5106 assert_eq!((*ctxt).valid, 1);
5107 assert!((*ctxt).node.is_null());
5108 free_valid_ctxt(ctxt);
5109 }
5110 }
5111
5112 #[test]
5119 fn test_free_valid_ctxt_null() {
5120 unsafe {
5121 free_valid_ctxt(ptr::null_mut());
5122 }
5123 }
5124
5125 #[test]
5134 fn test_set_valid_errors_null() {
5135 unsafe {
5136 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
5137 }
5138 }
5139
5140 #[test]
5151 fn test_validate_element_no_dtd() {
5152 unsafe {
5153 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5154 assert!(!doc.is_null());
5155
5156 let root_name = c_str("root");
5157 let root = create_root_elem(doc, root_name);
5158
5159 let ctxt = new_valid_ctxt();
5160 assert!(!ctxt.is_null());
5161
5162 assert_eq!(validate_element(ctxt, doc, root), 1);
5164
5165 free_valid_ctxt(ctxt);
5166 tree::free_doc(doc);
5167 }
5168 }
5169
5170 #[test]
5178 fn test_validate_element_empty_valid() {
5179 unsafe {
5180 let (doc, dtd) = make_test_doc();
5181
5182 let root_name = c_str("root");
5183 add_elem_decl(
5184 dtd,
5185 root_name,
5186 XML_ELEMENT_TYPE_EMPTY as c_int,
5187 ptr::null_mut(),
5188 );
5189
5190 let root = create_root_elem(doc, root_name);
5191
5192 let ctxt = new_valid_ctxt();
5193 assert!(!ctxt.is_null());
5194
5195 assert_eq!(validate_element(ctxt, doc, root), 1);
5196
5197 free_valid_ctxt(ctxt);
5198 tree::free_doc(doc);
5199 }
5200 }
5201
5202 #[test]
5210 fn test_validate_element_undeclared() {
5211 unsafe {
5212 let (doc, _dtd) = make_test_doc();
5213
5214 let root_name = c_str("root");
5215 let root = create_root_elem(doc, root_name);
5216
5217 let ctxt = new_valid_ctxt();
5218 assert!(!ctxt.is_null());
5219
5220 assert_eq!(validate_element(ctxt, doc, root), 0);
5222
5223 free_valid_ctxt(ctxt);
5224 tree::free_doc(doc);
5225 }
5226 }
5227
5228 #[test]
5238 fn test_validate_element_with_content() {
5239 unsafe {
5240 let (doc, dtd) = make_test_doc();
5241
5242 let root_name = c_str("root");
5244 let child_name = c_str("child");
5245
5246 let child_content =
5248 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5249 assert!(!child_content.is_null());
5250 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
5251
5252 add_elem_decl(
5253 dtd,
5254 root_name,
5255 XML_ELEMENT_TYPE_ELEMENT as c_int,
5256 child_content,
5257 );
5258 add_elem_decl(
5259 dtd,
5260 child_name,
5261 XML_ELEMENT_TYPE_EMPTY as c_int,
5262 ptr::null_mut(),
5263 );
5264
5265 let root = create_root_elem(doc, root_name);
5266 let _child = create_child_elem(root, child_name);
5267
5268 let ctxt = new_valid_ctxt();
5269 assert!(!ctxt.is_null());
5270
5271 assert_eq!(validate_element(ctxt, doc, root), 1);
5272
5273 free_valid_ctxt(ctxt);
5274 tree::free_doc(doc);
5275 }
5276 }
5277
5278 #[test]
5287 fn test_validate_element_invalid_content() {
5288 unsafe {
5289 let (doc, dtd) = make_test_doc();
5290
5291 let root_name = c_str("root");
5292 let child_name = c_str("child");
5293 let wrong_name = c_str("wrong");
5294
5295 let child_content =
5297 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5298 assert!(!child_content.is_null());
5299 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
5300
5301 add_elem_decl(
5302 dtd,
5303 root_name,
5304 XML_ELEMENT_TYPE_ELEMENT as c_int,
5305 child_content,
5306 );
5307 add_elem_decl(
5308 dtd,
5309 child_name,
5310 XML_ELEMENT_TYPE_EMPTY as c_int,
5311 ptr::null_mut(),
5312 );
5313 add_elem_decl(
5314 dtd,
5315 wrong_name,
5316 XML_ELEMENT_TYPE_EMPTY as c_int,
5317 ptr::null_mut(),
5318 );
5319
5320 let root = create_root_elem(doc, root_name);
5321 create_child_elem(root, wrong_name);
5323
5324 let ctxt = new_valid_ctxt();
5325 assert!(!ctxt.is_null());
5326
5327 assert_eq!(validate_element(ctxt, doc, root), 0);
5328
5329 free_valid_ctxt(ctxt);
5330 tree::free_doc(doc);
5331 }
5332 }
5333
5334 #[test]
5344 fn test_validate_root_match() {
5345 unsafe {
5346 let (doc, dtd) = make_test_doc();
5347
5348 let root_name = c_str("root");
5349 add_elem_decl(
5350 dtd,
5351 root_name,
5352 XML_ELEMENT_TYPE_EMPTY as c_int,
5353 ptr::null_mut(),
5354 );
5355 create_root_elem(doc, root_name);
5356
5357 let ctxt = new_valid_ctxt();
5358 assert!(!ctxt.is_null());
5359
5360 assert_eq!(validate_root(ctxt, doc), 1);
5361
5362 free_valid_ctxt(ctxt);
5363 tree::free_doc(doc);
5364 }
5365 }
5366
5367 #[test]
5375 fn test_validate_root_no_dtd() {
5376 unsafe {
5377 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5378 assert!(!doc.is_null());
5379
5380 let root_name = c_str("root");
5381 create_root_elem(doc, root_name);
5382
5383 let ctxt = new_valid_ctxt();
5384 assert!(!ctxt.is_null());
5385
5386 assert_eq!(validate_root(ctxt, doc), 1);
5388
5389 free_valid_ctxt(ctxt);
5390 tree::free_doc(doc);
5391 }
5392 }
5393
5394 #[test]
5404 fn test_validate_document_valid() {
5405 unsafe {
5406 let (doc, dtd) = make_test_doc();
5407
5408 let root_name = c_str("root");
5409 add_elem_decl(
5410 dtd,
5411 root_name,
5412 XML_ELEMENT_TYPE_EMPTY as c_int,
5413 ptr::null_mut(),
5414 );
5415 create_root_elem(doc, root_name);
5416
5417 let ctxt = new_valid_ctxt();
5418 assert!(!ctxt.is_null());
5419
5420 assert_eq!(validate_document(ctxt, doc), 1);
5421
5422 free_valid_ctxt(ctxt);
5423 tree::free_doc(doc);
5424 }
5425 }
5426
5427 #[test]
5435 fn test_validate_document_no_root() {
5436 unsafe {
5437 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5438 assert!(!doc.is_null());
5439
5440 let ctxt = new_valid_ctxt();
5441 assert!(!ctxt.is_null());
5442
5443 assert_eq!(validate_document(ctxt, doc), 0);
5444
5445 free_valid_ctxt(ctxt);
5446 tree::free_doc(doc);
5447 }
5448 }
5449
5450 #[test]
5461 fn test_validate_content_valid() {
5462 unsafe {
5463 let (doc, dtd) = make_test_doc();
5464
5465 let root_name = c_str("root");
5466 let child_name = c_str("child");
5467
5468 let child_content =
5469 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5470 assert!(!child_content.is_null());
5471
5472 add_elem_decl(
5473 dtd,
5474 root_name,
5475 XML_ELEMENT_TYPE_ELEMENT as c_int,
5476 child_content,
5477 );
5478 add_elem_decl(
5479 dtd,
5480 child_name,
5481 XML_ELEMENT_TYPE_EMPTY as c_int,
5482 ptr::null_mut(),
5483 );
5484
5485 let root = create_root_elem(doc, root_name);
5486 create_child_elem(root, child_name);
5487
5488 let ctxt = new_valid_ctxt();
5489 assert!(!ctxt.is_null());
5490
5491 assert_eq!(validate_content(ctxt, root, doc), 1);
5492
5493 free_valid_ctxt(ctxt);
5494 tree::free_doc(doc);
5495 }
5496 }
5497
5498 #[test]
5508 fn test_is_mixed_element() {
5509 unsafe {
5510 let (doc, dtd) = make_test_doc();
5511 let name = c_str("mixedElem");
5512 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5513
5514 assert_eq!(is_mixed_element(doc, name), 1);
5515
5516 let other = c_str("other");
5517 assert_eq!(is_mixed_element(doc, other), 0);
5518
5519 allocator::xmlFreeImpl(other as *mut c_void);
5520 tree::free_doc(doc);
5521 }
5522 }
5523
5524 #[test]
5532 fn test_is_empty_element() {
5533 unsafe {
5534 let (doc, dtd) = make_test_doc();
5535 let name = c_str("emptyElem");
5536 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5537
5538 assert_eq!(is_empty_element(doc, name), 1);
5539
5540 let other = c_str("other");
5541 assert_eq!(is_empty_element(doc, other), 0);
5542
5543 allocator::xmlFreeImpl(other as *mut c_void);
5544 tree::free_doc(doc);
5545 }
5546 }
5547
5548 #[test]
5555 fn test_is_mixed_element_no_dtd() {
5556 unsafe {
5557 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5558 assert!(!doc.is_null());
5559
5560 let name = c_str("foo");
5561 assert_eq!(is_mixed_element(doc, name), 0);
5562
5563 allocator::xmlFreeImpl(name as *mut c_void);
5564 tree::free_doc(doc);
5565 }
5566 }
5567
5568 #[test]
5575 fn test_is_empty_element_no_dtd() {
5576 unsafe {
5577 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5578 assert!(!doc.is_null());
5579
5580 let name = c_str("foo");
5581 assert_eq!(is_empty_element(doc, name), 0);
5582
5583 allocator::xmlFreeImpl(name as *mut c_void);
5584 tree::free_doc(doc);
5585 }
5586 }
5587
5588 #[test]
5597 fn test_validate_dtd_null() {
5598 unsafe {
5599 let ctxt = new_valid_ctxt();
5600 assert!(!ctxt.is_null());
5601 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5602 free_valid_ctxt(ctxt);
5603 }
5604 }
5605
5606 #[test]
5616 fn test_validate_element_null() {
5617 unsafe {
5618 let (doc, _dtd) = make_test_doc();
5619 let ctxt = new_valid_ctxt();
5620 assert!(!ctxt.is_null());
5621
5622 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5623
5624 free_valid_ctxt(ctxt);
5625 tree::free_doc(doc);
5626 }
5627 }
5628
5629 #[test]
5637 fn test_validate_document_null() {
5638 unsafe {
5639 let ctxt = new_valid_ctxt();
5640 assert!(!ctxt.is_null());
5641
5642 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5643 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5644
5645 free_valid_ctxt(ctxt);
5646 }
5647 }
5648
5649 #[test]
5657 fn test_validate_document_final_null() {
5658 unsafe {
5659 let ctxt = new_valid_ctxt();
5660 assert!(!ctxt.is_null());
5661
5662 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5663 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5664
5665 free_valid_ctxt(ctxt);
5666 }
5667 }
5668
5669 #[test]
5676 fn test_validate_attribute_decl_null() {
5677 unsafe {
5678 let ctxt = new_valid_ctxt();
5679 assert!(!ctxt.is_null());
5680
5681 assert_eq!(
5682 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut()),
5683 0
5684 );
5685
5686 free_valid_ctxt(ctxt);
5687 }
5688 }
5689
5690 #[test]
5697 fn test_validate_content_null() {
5698 unsafe {
5699 let ctxt = new_valid_ctxt();
5700 assert!(!ctxt.is_null());
5701
5702 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5703
5704 free_valid_ctxt(ctxt);
5705 }
5706 }
5707
5708 #[test]
5715 fn test_validate_root_null() {
5716 unsafe {
5717 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5718 }
5719 }
5720
5721 #[test]
5728 fn test_validate_enumeration_null() {
5729 unsafe {
5730 let ctxt = new_valid_ctxt();
5731 assert!(!ctxt.is_null());
5732
5733 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5734
5735 free_valid_ctxt(ctxt);
5736 }
5737 }
5738
5739 #[test]
5746 fn test_validate_notation_use_null() {
5747 unsafe {
5748 let ctxt = new_valid_ctxt();
5749 assert!(!ctxt.is_null());
5750
5751 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5752
5753 free_valid_ctxt(ctxt);
5754 }
5755 }
5756
5757 #[test]
5765 fn test_validate_name_start_characters() {
5766 unsafe {
5767 let name = c_str("\u{C0}lph\u{E0}");
5769 assert_eq!(validate_name(name), 1);
5770 allocator::xmlFreeImpl(name as *mut c_void);
5771 }
5772 }
5773
5774 #[test]
5782 fn test_validate_names_single() {
5783 unsafe {
5784 let s = c_str("singleName");
5785 assert_eq!(validate_names(s), 1);
5786 allocator::xmlFreeImpl(s as *mut c_void);
5787 }
5788 }
5789
5790 #[test]
5798 fn test_validate_nmtokens_single() {
5799 unsafe {
5800 let s = c_str("123abc");
5801 assert_eq!(validate_nmtokens(s), 1);
5802 allocator::xmlFreeImpl(s as *mut c_void);
5803 }
5804 }
5805
5806 #[test]
5814 fn test_validate_nmtokens_invalid() {
5815 unsafe {
5816 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5819
5820 let s2 = c_str("foo@bar");
5822 assert_eq!(validate_nmtokens(s2), 0);
5823 allocator::xmlFreeImpl(s2 as *mut c_void);
5824 }
5825 }
5826
5827 #[test]
5835 fn test_validate_attribute_value_empty_non_cdata() {
5836 unsafe {
5837 let empty = b"\0" as *const u8 as *const xmlChar;
5838 assert_eq!(
5839 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5840 0
5841 );
5842 assert_eq!(
5843 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5844 0
5845 );
5846 assert_eq!(
5847 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5848 0
5849 );
5850 }
5851 }
5852
5853 #[test]
5860 fn test_validate_attribute_value_unknown_type() {
5861 unsafe {
5862 let s = c_str("test");
5865 assert_eq!(validate_attribute_value(999, s), 1);
5866 allocator::xmlFreeImpl(s as *mut c_void);
5867 }
5868 }
5869
5870 #[test]
5878 fn test_validate_element_any_content() {
5879 unsafe {
5880 let (doc, dtd) = make_test_doc();
5881
5882 let root_name = c_str("root");
5883 add_elem_decl(
5884 dtd,
5885 root_name,
5886 XML_ELEMENT_TYPE_ANY as c_int,
5887 ptr::null_mut(),
5888 );
5889
5890 let child_name = c_str("child");
5891 add_elem_decl(
5892 dtd,
5893 child_name,
5894 XML_ELEMENT_TYPE_EMPTY as c_int,
5895 ptr::null_mut(),
5896 );
5897
5898 let root = create_root_elem(doc, root_name);
5899 create_child_elem(root, child_name);
5900
5901 let ctxt = new_valid_ctxt();
5902 assert!(!ctxt.is_null());
5903
5904 assert_eq!(validate_element(ctxt, doc, root), 1);
5906
5907 free_valid_ctxt(ctxt);
5908 tree::free_doc(doc);
5909 }
5910 }
5911
5912 #[test]
5920 fn test_validate_element_empty_with_child() {
5921 unsafe {
5922 let (doc, dtd) = make_test_doc();
5923
5924 let root_name = c_str("root");
5925 add_elem_decl(
5926 dtd,
5927 root_name,
5928 XML_ELEMENT_TYPE_EMPTY as c_int,
5929 ptr::null_mut(),
5930 );
5931
5932 let child_name = c_str("child");
5933 add_elem_decl(
5934 dtd,
5935 child_name,
5936 XML_ELEMENT_TYPE_EMPTY as c_int,
5937 ptr::null_mut(),
5938 );
5939
5940 let root = create_root_elem(doc, root_name);
5941 create_child_elem(root, child_name);
5942
5943 let ctxt = new_valid_ctxt();
5944 assert!(!ctxt.is_null());
5945
5946 assert_eq!(validate_element(ctxt, doc, root), 0);
5948
5949 free_valid_ctxt(ctxt);
5950 tree::free_doc(doc);
5951 }
5952 }
5953
5954 #[test]
5962 fn test_validate_dtd_final_null() {
5963 unsafe {
5964 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
5965 }
5966 }
5967}