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 let has_structured = crate::xml::globals::with_structured_error(|h, _| h.is_some());
260 if has_structured {
261 crate::xml::errors::raise_error(
262 ctxt as *mut c_void,
263 ptr::null_mut(),
264 ptr::null_mut(),
265 ptr::null_mut(),
266 ptr::null_mut(),
267 crate::abi::types::XML_FROM_VALID,
268 0,
269 crate::abi::types::xmlErrorLevel::XML_ERR_ERROR as c_int,
270 ptr::null(),
271 0,
272 ptr::null(),
273 ptr::null(),
274 ptr::null(),
275 0,
276 0,
277 msg,
278 );
279 }
280 }
281}
282
283unsafe fn vctxt_push_node(ctxt: *mut _xmlValidCtxt, node: *mut _xmlNode) -> c_int {
291 unsafe {
292 let c = &mut *ctxt;
293
294 if c.nodeNr >= c.nodeMax {
295 let new_max = if c.nodeMax == 0 { 4 } else { c.nodeMax * 2 };
296 let new_tab = allocator::xmlReallocImpl(
297 c.nodeTab as *mut c_void,
298 (new_max as usize) * size_of::<*mut _xmlNode>(),
299 ) as *mut *mut _xmlNode;
300 if new_tab.is_null() {
301 return -1;
302 }
303 c.nodeTab = new_tab;
304 c.nodeMax = new_max;
305 }
306
307 *c.nodeTab.add(c.nodeNr as usize) = node;
308 c.nodeNr += 1;
309 c.node = node;
310 }
311 0
312}
313
314unsafe fn vctxt_pop_node(ctxt: *mut _xmlValidCtxt) {
320 unsafe {
321 let c = &mut *ctxt;
322 if c.nodeNr > 0 {
323 c.nodeNr -= 1;
324 }
325 if c.nodeNr > 0 {
326 c.node = *c.nodeTab.add((c.nodeNr - 1) as usize);
327 } else {
328 c.node = ptr::null_mut();
329 }
330 }
331}
332
333unsafe fn get_valid_dtd(doc: *mut _xmlDoc) -> *mut _xmlDtd {
341 if doc.is_null() {
342 return ptr::null_mut();
343 }
344 unsafe {
345 let d = &*doc;
346 if !d.intSubset.is_null() {
347 d.intSubset
348 } else {
349 d.extSubset
350 }
351 }
352}
353
354pub(crate) const fn is_xml_name_start(c: char) -> bool {
368 matches!(c,
369 'a'..='z' | 'A'..='Z' | '_' | ':' |
370 '\u{C0}'..='\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' |
371 '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' |
372 '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' |
373 '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' |
374 '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' |
375 '\u{10000}'..='\u{EFFFF}'
376 )
377}
378
379pub(crate) const fn is_xml_name_char(c: char) -> bool {
386 is_xml_name_start(c)
387 || matches!(c,
388 '-' | '.' | '0'..='9' | '\u{B7}' |
389 '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}'
390 )
391}
392
393pub unsafe fn validate_name(value: *const xmlChar) -> c_int {
411 if value.is_null() {
412 return 0;
413 }
414
415 let s = unsafe { string::xmlstr_to_bytes(value) };
416 let s = core::str::from_utf8(s).unwrap_or("");
417
418 if s.is_empty() {
419 return 0;
420 }
421
422 let mut chars = s.chars();
423
424 match chars.next() {
426 Some(c) if is_xml_name_start(c) => {}
427 _ => return 0,
428 }
429
430 for c in chars {
432 if !is_xml_name_char(c) {
433 return 0;
434 }
435 }
436
437 1
438}
439
440pub unsafe fn validate_names(value: *const xmlChar) -> c_int {
454 if value.is_null() {
455 return 0;
456 }
457
458 let s = unsafe { string::xmlstr_to_bytes(value) };
459 let s = core::str::from_utf8(s).unwrap_or("");
460
461 if s.is_empty() {
462 return 0;
463 }
464
465 for token in s.split_whitespace() {
466 if token.is_empty() {
467 return 0;
468 }
469 let mut chars = token.chars();
470 match chars.next() {
471 Some(c) if is_xml_name_start(c) => {}
472 _ => return 0,
473 }
474 for c in chars {
475 if !is_xml_name_char(c) {
476 return 0;
477 }
478 }
479 }
480
481 1
482}
483
484pub unsafe fn validate_nmtoken(value: *const xmlChar) -> c_int {
503 if value.is_null() {
504 return 0;
505 }
506
507 let s = unsafe { string::xmlstr_to_bytes(value) };
508 let s = core::str::from_utf8(s).unwrap_or("");
509
510 if s.is_empty() {
511 return 0;
512 }
513
514 for c in s.chars() {
515 if !is_xml_name_char(c) {
516 return 0;
517 }
518 }
519
520 1
521}
522
523pub unsafe fn validate_nmtokens(value: *const xmlChar) -> c_int {
537 if value.is_null() {
538 return 0;
539 }
540
541 let s = unsafe { string::xmlstr_to_bytes(value) };
542 let s = core::str::from_utf8(s).unwrap_or("");
543
544 if s.is_empty() {
545 return 0;
546 }
547
548 for token in s.split_whitespace() {
549 if token.is_empty() {
550 return 0;
551 }
552 for c in token.chars() {
553 if !is_xml_name_char(c) {
554 return 0;
555 }
556 }
557 }
558
559 1
560}
561
562pub unsafe fn validate_attribute_value(atype: c_int, value: *const xmlChar) -> c_int {
580 match atype as u32 {
584 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
585 validate_values_internal(value, 0)
586 }
587 t if t == XML_ATTRIBUTE_ENTITY as u32
588 || t == XML_ATTRIBUTE_IDREF as u32
589 || t == XML_ATTRIBUTE_ID as u32
590 || t == XML_ATTRIBUTE_NOTATION as u32 =>
591 {
592 validate_value_internal(value, 0)
593 }
594 t if t == XML_ATTRIBUTE_NMTOKENS as u32 || t == XML_ATTRIBUTE_ENUMERATION as u32 => {
595 validate_values_internal(value, XML_SCAN_NMTOKEN)
596 }
597 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => validate_value_internal(value, XML_SCAN_NMTOKEN),
598 _ => 1, }
600}
601
602pub unsafe fn validate_enumeration(
624 ctxt: *mut _xmlValidCtxt,
625 value: *const xmlChar,
626 tree: *mut _xmlEnumeration,
627) -> c_int {
628 if value.is_null() || tree.is_null() {
629 return 0;
630 }
631
632 let mut cur = tree;
633 while !cur.is_null() {
634 unsafe {
635 if string::xml_strcmp(value, (*cur).name) == 0 {
636 return 1;
637 }
638 cur = (*cur).next;
639 }
640 }
641
642 unsafe {
644 let msg = string::xmlstr_to_string(value);
645 let err_msg = format!("Value '{}' is not a valid enumeration value\0", msg);
646 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
647 }
648 0
649}
650
651pub unsafe fn validate_notation_use(
671 ctxt: *mut _xmlValidCtxt,
672 doc: *mut _xmlDoc,
673 notation_name: *const xmlChar,
674) -> c_int {
675 if notation_name.is_null() {
676 return 0;
677 }
678
679 let dtd = unsafe { get_valid_dtd(doc) };
680 if dtd.is_null() {
681 unsafe {
682 vctxt_error(
683 ctxt,
684 b"No DTD available for notation validation\0" as *const u8 as *const c_char,
685 );
686 }
687 return 0;
688 }
689
690 unsafe {
692 let notations = (*dtd).notations;
693 if notations.is_null() {
694 vctxt_error(
695 ctxt,
696 b"No notations declared in DTD\0" as *const u8 as *const c_char,
697 );
698 return 0;
699 }
700
701 let notation = hash::hash_lookup(notations as *mut hash::HashTable, notation_name);
702 if notation.is_null() {
703 let msg = string::xmlstr_to_string(notation_name);
704 let err_msg = format!("Notation '{}' is not declared\0", msg);
705 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
706 return 0;
707 }
708 }
709
710 1
711}
712
713pub unsafe fn validate_id(
735 ctxt: *mut _xmlValidCtxt,
736 doc: *mut _xmlDoc,
737 node: *mut _xmlNode,
738 value: *const xmlChar,
739) -> c_int {
740 if value.is_null() || doc.is_null() {
741 return 0;
742 }
743
744 if unsafe { validate_name_value(value) } == 0 {
747 unsafe {
748 let msg = string::xmlstr_to_string(value);
749 let err_msg = format!("ID value '{}' is not a valid XML Name\0", msg);
750 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
751 }
752 return 0;
753 }
754
755 unsafe {
757 let doc_ref = &*doc;
758 if !doc_ref.ids.is_null() {
759 let existing = hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value);
760 if !existing.is_null() {
761 let msg = string::xmlstr_to_string(value);
762 let err_msg = format!("Duplicate ID value '{}'\0", msg);
763 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
764 return 0;
765 }
766 }
767 }
768
769 unsafe {
771 if (*doc).ids.is_null() {
772 (*doc).ids = hash::hash_create(16) as *mut c_void;
773 }
774 hash::hash_add_entry(
775 (*doc).ids as *mut hash::HashTable,
776 value,
777 node as *mut c_void,
778 );
779 }
780
781 1
782}
783
784pub unsafe fn validate_id_ref(
801 ctxt: *mut _xmlValidCtxt,
802 doc: *mut _xmlDoc,
803 _node: *mut _xmlNode,
804 value: *const xmlChar,
805) -> c_int {
806 if value.is_null() || doc.is_null() {
807 return 0;
808 }
809
810 if unsafe { validate_name_value(value) } == 0 {
813 unsafe {
814 let msg = string::xmlstr_to_string(value);
815 let err_msg = format!("IDREF value '{}' is not a valid XML Name\0", msg);
816 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
817 }
818 return 0;
819 }
820
821 unsafe {
823 let doc_ref = &*doc;
824 if doc_ref.ids.is_null()
825 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value).is_null()
826 {
827 let msg = string::xmlstr_to_string(value);
831 let err_msg = format!("IDREF '{}' references an unknown ID\0", msg);
832 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
833 return 0;
834 }
835 }
836
837 1
838}
839
840pub unsafe fn validate_id_refs(
857 ctxt: *mut _xmlValidCtxt,
858 doc: *mut _xmlDoc,
859 node: *mut _xmlNode,
860 value: *const xmlChar,
861) -> c_int {
862 if value.is_null() || doc.is_null() {
863 return 0;
864 }
865
866 let s = unsafe { string::xmlstr_to_bytes(value) };
867 let s = core::str::from_utf8(s).unwrap_or("");
868
869 if s.is_empty() {
870 return 0;
871 }
872
873 let mut valid = 1;
874 for token in s.split_whitespace() {
875 if token.is_empty() {
876 continue;
877 }
878 let token_ptr = unsafe { string::bytes_to_xmlstr(token.as_bytes()) };
880 if token_ptr.is_null() {
881 valid = 0;
882 break;
883 }
884 let result = unsafe { validate_id_ref(ctxt, doc, node, token_ptr) };
885 unsafe {
886 allocator::xmlFreeImpl(token_ptr as *mut c_void);
887 }
888 if result == 0 {
889 valid = 0;
890 }
891 }
892
893 valid
894}
895
896pub unsafe fn validate_attribute_decl(
923 ctxt: *mut _xmlValidCtxt,
924 doc: *mut _xmlDoc,
925 attr: *mut _xmlAttribute,
926) -> c_int {
927 if attr.is_null() {
928 return 0;
929 }
930
931 unsafe {
932 let a = &*attr;
933 let atype = a.atype as c_int;
934
935 if !a.defaultValue.is_null() && validate_attribute_value(atype, a.defaultValue) == 0 {
937 let name_str = string::xmlstr_to_string(a.name);
938 let val_str = string::xmlstr_to_string(a.defaultValue);
939 let err_msg = format!(
940 "Default value '{}' for attribute '{}' is not valid for its type\0",
941 val_str, name_str
942 );
943 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
944 return 0;
945 }
946
947 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !a.tree.is_null() {
949 let mut cur = a.tree;
951 while !cur.is_null() {
952 if !(*cur).name.is_null() && validate_nmtoken_value((*cur).name) == 0 {
953 let val_str = string::xmlstr_to_string((*cur).name);
954 let err_msg =
955 format!("Enumeration value '{}' is not a valid NMTOKEN\0", val_str);
956 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
957 return 0;
958 }
959 cur = (*cur).next;
960 }
961 }
962
963 if atype == XML_ATTRIBUTE_NOTATION as c_int && !a.tree.is_null() {
965 let mut cur = a.tree;
966 while !cur.is_null() {
967 if !(*cur).name.is_null() && validate_notation_use(ctxt, doc, (*cur).name) == 0 {
968 let val_str = string::xmlstr_to_string((*cur).name);
969 let err_msg = format!(
970 "NOTATION value '{}' references undeclared notation\0",
971 val_str
972 );
973 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
974 return 0;
975 }
976 cur = (*cur).next;
977 }
978 }
979
980 1
981 }
982}
983
984pub unsafe fn validate_element(
1013 ctxt: *mut _xmlValidCtxt,
1014 doc: *mut _xmlDoc,
1015 elem: *mut _xmlNode,
1016) -> c_int {
1017 if elem.is_null() || doc.is_null() || ctxt.is_null() {
1018 return 0;
1019 }
1020
1021 unsafe {
1022 let e = &*elem;
1023
1024 if e.type_ != XML_ELEMENT_NODE as c_int {
1026 return 1;
1027 }
1028
1029 if vctxt_push_node(ctxt, elem) != 0 {
1031 return 0;
1032 }
1033
1034 let mut valid = 1;
1035
1036 let dtd = get_valid_dtd(doc);
1038 if dtd.is_null() {
1039 vctxt_pop_node(ctxt);
1042 return 1;
1043 }
1044
1045 let dtd_ref = &*dtd;
1046
1047 let elem_name = e.name;
1049 let elem_decl = if !dtd_ref.elements.is_null() {
1050 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, elem_name)
1051 } else {
1052 ptr::null_mut()
1053 };
1054
1055 if elem_decl.is_null() {
1056 let name_str = string::xmlstr_to_string(elem_name);
1057 let err_msg = format!("No declaration for element {}\0", name_str);
1058 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1059 if !dtd_ref.attributes.is_null() {
1065 let mut attr_prop = e.properties;
1066 while !attr_prop.is_null() {
1067 let a_ref = &*attr_prop;
1068 if !a_ref.name.is_null() {
1069 let ad = hash::hash_lookup3(
1070 dtd_ref.attributes as *mut hash::HashTable,
1071 a_ref.name,
1072 ptr::null(),
1073 elem_name,
1074 );
1075 if ad.is_null() {
1076 let aname_str = string::xmlstr_to_string(a_ref.name);
1077 let ename_str = string::xmlstr_to_string(elem_name);
1078 let aerr = format!(
1079 "No declaration for attribute {} of element {}\0",
1080 aname_str, ename_str
1081 );
1082 vctxt_error(ctxt, aerr.as_ptr() as *const c_char);
1083 }
1084 }
1085 attr_prop = (*attr_prop).next;
1086 }
1087 }
1088 let mut child = e.children;
1089 while !child.is_null() {
1090 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1091 validate_element(ctxt, doc, child);
1092 }
1093 child = (*child).next;
1094 }
1095 vctxt_pop_node(ctxt);
1096 return 0;
1097 }
1098
1099 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1100
1101 let elem_type = elem_decl_ref.etype as u32;
1103
1104 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1105 let mut child = e.children;
1107 while !child.is_null() {
1108 let child_type = (*child).type_ as u32;
1109 if child_type != XML_TEXT_NODE as u32 && child_type != XML_CDATA_SECTION_NODE as u32
1110 {
1111 valid = 0;
1112 let name_str = string::xmlstr_to_string(elem_name);
1113 let err_msg = format!(
1114 "Element '{}' is declared EMPTY but has child elements\0",
1115 name_str
1116 );
1117 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1118 break;
1119 }
1120 child = (*child).next;
1121 }
1122 } else if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1123 } else if elem_type == XML_ELEMENT_TYPE_MIXED as u32 {
1125 let mut child = e.children;
1127 while !child.is_null() {
1128 let child_type = (*child).type_ as u32;
1129 if child_type == XML_ELEMENT_NODE as u32 {
1130 let child_name = (*child).name;
1132 let result = dtd::valid_content_model(elem_decl_ref.content, &[child_name]);
1133 if result != dtd::ContentModelResult::Valid {
1134 let cname_str = string::xmlstr_to_string(child_name);
1135 let ename_str = string::xmlstr_to_string(elem_name);
1136 let err_msg = format!(
1137 "Element '{}' is not allowed in mixed content of '{}'\0",
1138 cname_str, ename_str
1139 );
1140 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1141 valid = 0;
1142 }
1143 }
1144 child = (*child).next;
1145 }
1146 } else if elem_type == XML_ELEMENT_TYPE_ELEMENT as u32 {
1147 let mut child_names: Vec<*const xmlChar> = Vec::new();
1149 let mut child = e.children;
1150 while !child.is_null() {
1151 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1152 child_names.push((*child).name);
1153 }
1154 child = (*child).next;
1155 }
1156
1157 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1158 if result != dtd::ContentModelResult::Valid {
1159 let ename_str = string::xmlstr_to_string(elem_name);
1160 let err_msg = format!(
1161 "Content model validation failed for element '{}'\0",
1162 ename_str
1163 );
1164 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1165 valid = 0;
1166 }
1167 }
1168
1169 if !dtd_ref.attributes.is_null() {
1171 let mut attr_prop = e.properties;
1173 while !attr_prop.is_null() {
1174 let attr_ref = &*attr_prop;
1175 let attr_name = attr_ref.name;
1176
1177 let attr_decl = hash::hash_lookup3(
1180 dtd_ref.attributes as *mut hash::HashTable,
1181 attr_name,
1182 ptr::null(),
1183 elem_name,
1184 );
1185
1186 if attr_decl.is_null() {
1187 let aname_str = string::xmlstr_to_string(attr_name);
1192 let ename_str = string::xmlstr_to_string(elem_name);
1193 let err_msg = format!(
1194 "No declaration for attribute {} of element {}\0",
1195 aname_str, ename_str
1196 );
1197 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1198 valid = 0;
1199 attr_prop = attr_ref.next;
1200 continue;
1201 }
1202
1203 let attr_decl_ref = &*(attr_decl as *mut _xmlAttribute);
1204 let atype = attr_decl_ref.atype as c_int;
1205
1206 let attr_value = if !attr_ref.children.is_null() {
1208 let text_node = attr_ref.children;
1210 if (*text_node).type_ == XML_TEXT_NODE as c_int
1211 || (*text_node).type_ == XML_CDATA_SECTION_NODE as c_int
1212 {
1213 (*text_node).content
1214 } else {
1215 ptr::null()
1216 }
1217 } else {
1218 ptr::null()
1219 };
1220
1221 if !attr_value.is_null() {
1223 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !attr_decl_ref.tree.is_null()
1224 {
1225 if validate_enumeration(ctxt, attr_value, attr_decl_ref.tree) == 0 {
1226 let aname_str = string::xmlstr_to_string(attr_name);
1227 let aval_str = string::xmlstr_to_string(attr_value);
1228 let err_msg = format!(
1229 "Attribute '{}' has value '{}' not in enumeration\0",
1230 aname_str, aval_str
1231 );
1232 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1233 valid = 0;
1234 }
1235 } else if atype == XML_ATTRIBUTE_NOTATION as c_int {
1236 if validate_notation_use(ctxt, doc, attr_value) == 0 {
1237 let aname_str = string::xmlstr_to_string(attr_name);
1238 let aval_str = string::xmlstr_to_string(attr_value);
1239 let err_msg = format!(
1240 "Attribute '{}' references undeclared notation '{}'\0",
1241 aname_str, aval_str
1242 );
1243 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1244 valid = 0;
1245 }
1246 } else if validate_attribute_value(atype, attr_value) == 0 {
1247 let aname_str = string::xmlstr_to_string(attr_name);
1248 let aval_str = string::xmlstr_to_string(attr_value);
1249 let err_msg = format!(
1250 "Attribute '{}' has invalid value '{}' for its type\0",
1251 aname_str, aval_str
1252 );
1253 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1254 valid = 0;
1255 }
1256
1257 if atype == XML_ATTRIBUTE_ID as c_int {
1259 if validate_id(ctxt, doc, elem, attr_value) == 0 {
1260 valid = 0;
1261 }
1262 } else if atype == XML_ATTRIBUTE_IDREF as c_int {
1263 if validate_id_ref(ctxt, doc, elem, attr_value) == 0 {
1264 valid = 0;
1265 }
1266 } else if atype == XML_ATTRIBUTE_IDREFS as c_int
1267 && validate_id_refs(ctxt, doc, elem, attr_value) == 0
1268 {
1269 valid = 0;
1270 }
1271 }
1272
1273 attr_prop = attr_ref.next;
1274 }
1275
1276 struct RequiredAttrCheck {
1278 ctxt: *mut _xmlValidCtxt,
1279 elem_name: *const xmlChar,
1280 elem_props: *mut _xmlAttr,
1281 valid: *mut c_int,
1282 }
1283
1284 extern "C" fn check_required_attr(
1285 payload: *mut c_void,
1286 data: *mut c_void,
1287 name: *const xmlChar,
1288 name2: *const xmlChar,
1289 _name3: *const xmlChar,
1290 ) {
1291 if payload.is_null() || data.is_null() || name2.is_null() {
1292 return;
1293 }
1294
1295 let check = unsafe { &*(data as *mut RequiredAttrCheck) };
1297 unsafe {
1298 if string::xml_strcmp(name, check.elem_name) != 0 {
1300 return;
1301 }
1302
1303 let attr_decl = &*(payload as *mut _xmlAttribute);
1304
1305 if attr_decl.def == XML_ATTRIBUTE_REQUIRED as c_int {
1307 let mut found = 0;
1309 let mut prop = check.elem_props;
1310 while !prop.is_null() {
1311 if string::xml_strcmp((*prop).name, name2) == 0 {
1312 found = 1;
1313 break;
1314 }
1315 prop = (*prop).next;
1316 }
1317
1318 if found == 0 {
1319 let aname_str = string::xmlstr_to_string(name2);
1320 let ename_str = string::xmlstr_to_string(check.elem_name);
1321 let err_msg = format!(
1322 "Required attribute '{}' missing on element '{}'\0",
1323 aname_str, ename_str
1324 );
1325 vctxt_error(check.ctxt, err_msg.as_ptr() as *const c_char);
1326 *(check.valid) = 0;
1327 }
1328 }
1329 }
1330 }
1331
1332 let mut required_valid = valid;
1333 let check = RequiredAttrCheck {
1334 ctxt,
1335 elem_name,
1336 elem_props: e.properties,
1337 valid: &mut required_valid,
1338 };
1339
1340 hash::hash_scan_full(
1341 dtd_ref.attributes as *mut hash::HashTable,
1342 Some(check_required_attr),
1343 &check as *const RequiredAttrCheck as *mut c_void,
1344 );
1345
1346 valid = required_valid;
1347 }
1348
1349 let mut child = e.children;
1351 while !child.is_null() {
1352 if (*child).type_ == XML_ELEMENT_NODE as c_int
1353 && validate_element(ctxt, doc, child) == 0
1354 {
1355 valid = 0;
1356 }
1357 child = (*child).next;
1358 }
1359
1360 vctxt_pop_node(ctxt);
1361 valid
1362 }
1363}
1364
1365pub unsafe fn validate_document(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1385 if ctxt.is_null() || doc.is_null() {
1386 return 0;
1387 }
1388
1389 unsafe {
1390 let c = &mut *ctxt;
1391 c.doc = doc;
1392 c.valid = 1;
1393
1394 let d = &*doc;
1395
1396 if d.intSubset.is_null() && d.extSubset.is_null() {
1406 vctxt_error(ctxt, b"no DTD found!\0" as *const u8 as *const c_char);
1407 return 0;
1408 }
1409
1410 let mut root = d.children;
1412 while !root.is_null() {
1413 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1414 break;
1415 }
1416 root = (*root).next;
1417 }
1418
1419 if root.is_null() {
1420 vctxt_error(
1421 ctxt,
1422 b"No root element found in document\0" as *const u8 as *const c_char,
1423 );
1424 return 0;
1425 }
1426
1427 if validate_element(ctxt, doc, root) == 0 {
1429 return 0;
1430 }
1431
1432 c.valid
1433 }
1434}
1435
1436pub unsafe fn validate_document_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1458 if ctxt.is_null() || doc.is_null() {
1459 return 0;
1460 }
1461
1462 unsafe {
1463 let c = &mut *ctxt;
1464 c.doc = doc;
1465
1466 let d = &*doc;
1467
1468 if d.refs.is_null() {
1470 return c.valid;
1471 }
1472
1473 struct IdRefCheckContext {
1475 ctxt: *mut _xmlValidCtxt,
1476 doc: *mut _xmlDoc,
1477 }
1478
1479 extern "C" fn check_idref(
1480 _payload: *mut c_void,
1481 data: *mut c_void,
1482 _name: *const xmlChar,
1483 name2: *const xmlChar,
1484 _name3: *const xmlChar,
1485 ) {
1486 if data.is_null() || name2.is_null() {
1487 return;
1488 }
1489
1490 let cx = unsafe { &*(data as *mut IdRefCheckContext) };
1492 unsafe {
1493 let doc_ref = &*cx.doc;
1494
1495 if doc_ref.ids.is_null()
1497 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, name2).is_null()
1498 {
1499 let ref_str = string::xmlstr_to_string(name2);
1500 let err_msg = format!("IDREF '{}' does not reference a declared ID\0", ref_str);
1501 vctxt_error(cx.ctxt, err_msg.as_ptr() as *const c_char);
1502 }
1503 }
1504 }
1505
1506 let ctx = IdRefCheckContext { ctxt, doc };
1507 hash::hash_scan_full(
1508 d.refs as *mut hash::HashTable,
1509 Some(check_idref),
1510 &ctx as *const IdRefCheckContext as *mut c_void,
1511 );
1512
1513 c.valid
1514 }
1515}
1516
1517pub unsafe fn validate_root(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1535 if ctxt.is_null() || doc.is_null() {
1536 return 0;
1537 }
1538
1539 unsafe {
1540 let c = &mut *ctxt;
1541 c.doc = doc;
1542 c.valid = 1;
1543
1544 let d = &*doc;
1545
1546 let mut root = d.children;
1548 while !root.is_null() {
1549 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1550 break;
1551 }
1552 root = (*root).next;
1553 }
1554
1555 if root.is_null() {
1556 vctxt_error(
1557 ctxt,
1558 b"No root element found\0" as *const u8 as *const c_char,
1559 );
1560 return 0;
1561 }
1562
1563 let dtd = get_valid_dtd(doc);
1565 if dtd.is_null() {
1566 return 1;
1568 }
1569
1570 let dtd_ref = &*dtd;
1573 if !dtd_ref.name.is_null() && string::xml_strcmp((*root).name, dtd_ref.name) != 0 {
1574 let root_str = string::xmlstr_to_string((*root).name);
1575 let dtd_str = string::xmlstr_to_string(dtd_ref.name);
1576 let err_msg = format!(
1577 "Root element '{}' does not match DTD root '{}'\0",
1578 root_str, dtd_str
1579 );
1580 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1581 return 0;
1582 }
1583
1584 c.valid
1585 }
1586}
1587
1588pub unsafe fn validate_content(
1608 ctxt: *mut _xmlValidCtxt,
1609 node: *mut _xmlNode,
1610 doc: *mut _xmlDoc,
1611) -> c_int {
1612 if node.is_null() || doc.is_null() || ctxt.is_null() {
1613 return 0;
1614 }
1615
1616 unsafe {
1617 let n = &*node;
1618 if n.type_ != XML_ELEMENT_NODE as c_int {
1619 return 1;
1620 }
1621
1622 let dtd = get_valid_dtd(doc);
1623 if dtd.is_null() {
1624 return 1;
1625 }
1626
1627 let dtd_ref = &*dtd;
1628 if dtd_ref.elements.is_null() {
1629 return 1;
1630 }
1631
1632 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, n.name);
1633 if elem_decl.is_null() {
1634 return 1;
1635 }
1636
1637 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1638 if elem_decl_ref.content.is_null() {
1639 return 1;
1640 }
1641
1642 let elem_type = elem_decl_ref.etype as u32;
1643 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1644 let mut child = n.children;
1646 while !child.is_null() {
1647 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1648 let name_str = string::xmlstr_to_string(n.name);
1649 let err_msg =
1650 format!("Element '{}' is EMPTY but has child elements\0", name_str);
1651 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1652 return 0;
1653 }
1654 child = (*child).next;
1655 }
1656 return 1;
1657 }
1658
1659 if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1660 return 1;
1661 }
1662
1663 let mut child_names: Vec<*const xmlChar> = Vec::new();
1665 let mut child = n.children;
1666 while !child.is_null() {
1667 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1668 child_names.push((*child).name);
1669 }
1670 child = (*child).next;
1671 }
1672
1673 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1674 if result != dtd::ContentModelResult::Valid {
1675 let name_str = string::xmlstr_to_string(n.name);
1676 let err_msg = format!(
1677 "Content model validation failed for element '{}'\0",
1678 name_str
1679 );
1680 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1681 0
1682 } else {
1683 1
1684 }
1685 }
1686}
1687
1688pub unsafe fn is_mixed_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1706 if doc.is_null() || name.is_null() {
1707 return 0;
1708 }
1709
1710 let dtd = unsafe { get_valid_dtd(doc) };
1711 if dtd.is_null() {
1712 return 0;
1713 }
1714
1715 unsafe {
1716 let dtd_ref = &*dtd;
1717 if dtd_ref.elements.is_null() {
1718 return 0;
1719 }
1720
1721 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1722 if elem_decl.is_null() {
1723 return 0;
1724 }
1725
1726 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1727 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_MIXED as u32) as c_int
1728 }
1729}
1730
1731pub unsafe fn is_empty_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1745 if doc.is_null() || name.is_null() {
1746 return 0;
1747 }
1748
1749 let dtd = unsafe { get_valid_dtd(doc) };
1750 if dtd.is_null() {
1751 return 0;
1752 }
1753
1754 unsafe {
1755 let dtd_ref = &*dtd;
1756 if dtd_ref.elements.is_null() {
1757 return 0;
1758 }
1759
1760 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1761 if elem_decl.is_null() {
1762 return 0;
1763 }
1764
1765 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1766 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_EMPTY as u32) as c_int
1767 }
1768}
1769
1770pub unsafe fn validate_dtd(
1794 ctxt: *mut _xmlValidCtxt,
1795 doc: *mut _xmlDoc,
1796 dtd: *mut _xmlDtd,
1797) -> c_int {
1798 if ctxt.is_null() || dtd.is_null() {
1799 return 0;
1800 }
1801
1802 let c = unsafe { &mut *ctxt };
1803 c.doc = doc;
1804 c.valid = 1;
1805
1806 struct ValidateDtdCtx {
1807 ctxt: *mut _xmlValidCtxt,
1808 doc: *mut _xmlDoc,
1809 }
1810
1811 extern "C" fn validate_attr_decl_cb(
1812 payload: *mut c_void,
1813 data: *mut c_void,
1814 _name: *const xmlChar,
1815 _name2: *const xmlChar,
1816 _name3: *const xmlChar,
1817 ) {
1818 if payload.is_null() || data.is_null() {
1819 return;
1820 }
1821
1822 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1824 unsafe {
1825 let attr = payload as *mut _xmlAttribute;
1826 validate_attribute_decl(ctx.ctxt, ctx.doc, attr);
1827 }
1828 }
1829
1830 extern "C" fn validate_elem_content_cb(
1831 payload: *mut c_void,
1832 data: *mut c_void,
1833 _name: *const xmlChar,
1834 _name2: *const xmlChar,
1835 _name3: *const xmlChar,
1836 ) {
1837 if payload.is_null() || data.is_null() {
1838 return;
1839 }
1840
1841 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1843 unsafe {
1844 let elem = &*(payload as *mut _xmlElement);
1845 if !elem.content.is_null() {
1846 validate_content_model_refs(ctx.ctxt, ctx.doc, elem.content);
1847 }
1848 }
1849 }
1850
1851 unsafe {
1852 let dtd_ref = &*dtd;
1853
1854 if !dtd_ref.attributes.is_null() {
1856 let ctx = ValidateDtdCtx { ctxt, doc };
1857 hash::hash_scan_full(
1858 dtd_ref.attributes as *mut hash::HashTable,
1859 Some(validate_attr_decl_cb),
1860 &ctx as *const ValidateDtdCtx as *mut c_void,
1861 );
1862 }
1863
1864 if !dtd_ref.elements.is_null() {
1866 let ctx = ValidateDtdCtx { ctxt, doc };
1867 hash::hash_scan_full(
1868 dtd_ref.elements as *mut hash::HashTable,
1869 Some(validate_elem_content_cb),
1870 &ctx as *const ValidateDtdCtx as *mut c_void,
1871 );
1872 }
1873
1874 if !doc.is_null() {
1880 let d = &*doc;
1881 let mut root = d.children;
1882 while !root.is_null() {
1883 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1884 break;
1885 }
1886 root = (*root).next;
1887 }
1888 if !root.is_null() {
1889 let el_valid = validate_element(ctxt, doc, root);
1892 if el_valid == 0 {
1893 c.valid = 0;
1894 }
1895 }
1896 }
1897
1898 c.valid
1899 }
1900}
1901
1902unsafe fn validate_content_model_refs(
1909 ctxt: *mut _xmlValidCtxt,
1910 doc: *mut _xmlDoc,
1911 content: *mut _xmlElementContent,
1912) {
1913 if content.is_null() {
1914 return;
1915 }
1916
1917 unsafe {
1918 let c = &*content;
1919
1920 match c.type_ as u32 {
1921 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
1922 if !c.name.is_null() {
1924 let dtd = get_valid_dtd(doc);
1925 if !dtd.is_null() {
1926 let dtd_ref = &*dtd;
1927 if !dtd_ref.elements.is_null() {
1928 let decl =
1929 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, c.name);
1930 if decl.is_null() {
1931 let name_str = string::xmlstr_to_string(c.name);
1932 let err_msg = format!(
1933 "Element '{}' referenced in content model is not declared\0",
1934 name_str
1935 );
1936 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1937 }
1938 }
1939 }
1940 }
1941 }
1942 t if t == XML_ELEMENT_CONTENT_SEQ as u32 || t == XML_ELEMENT_CONTENT_OR as u32 => {
1943 validate_content_model_refs(ctxt, doc, c.c1);
1944 validate_content_model_refs(ctxt, doc, c.c2);
1945 }
1946 _ => {}
1947 }
1948 }
1949}
1950
1951pub unsafe fn validate_dtd_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1972 unsafe { validate_document_final(ctxt, doc) }
1973}
1974
1975const XML_SCAN_NC: u32 = 1; const XML_SCAN_NMTOKEN: u32 = 2; const fn is_blank_byte(b: u8) -> bool {
2003 b == b' ' || b == b'\t' || b == b'\n' || b == b'\r'
2004}
2005
2006const fn utf8_char_len(lead: u8) -> usize {
2008 if lead < 0x80 {
2009 1
2010 } else if lead >= 0xC0 && lead <= 0xDF {
2011 2
2012 } else if lead >= 0xE0 && lead <= 0xEF {
2013 3
2014 } else if lead >= 0xF0 && lead <= 0xF7 {
2015 4
2016 } else {
2017 0
2018 }
2019}
2020
2021unsafe fn scan_name_offsets(bytes: &[u8], start: usize, flags: u32) -> usize {
2034 let stop = if flags & XML_SCAN_NC != 0 {
2035 Some(b':')
2036 } else {
2037 None
2038 };
2039 let mut i = start;
2040 let mut is_nmtoken = flags & XML_SCAN_NMTOKEN != 0;
2041 while i < bytes.len() {
2042 let b = bytes[i];
2043 if b < 0x80 {
2044 if stop == Some(b) {
2045 break;
2046 }
2047 let c = b as char;
2048 let ok = if is_nmtoken {
2049 is_xml_name_char(c)
2050 } else {
2051 is_xml_name_start(c)
2052 };
2053 if !ok {
2054 break;
2055 }
2056 i += 1;
2057 } else {
2058 let len = utf8_char_len(b);
2059 if len == 0 || i + len > bytes.len() {
2060 break;
2061 }
2062 let ch = match core::str::from_utf8(&bytes[i..i + len])
2063 .ok()
2064 .and_then(|s| s.chars().next())
2065 {
2066 Some(c) => c,
2067 None => break,
2068 };
2069 let ok = if is_nmtoken {
2070 is_xml_name_char(ch)
2071 } else {
2072 is_xml_name_start(ch)
2073 };
2074 if !ok {
2075 break;
2076 }
2077 i += len;
2078 }
2079 is_nmtoken = true;
2081 }
2082 i
2083}
2084
2085pub unsafe fn validate_ncname(value: *const xmlChar, space: c_int) -> c_int {
2091 if value.is_null() {
2092 return -1;
2093 }
2094 let bytes = string::xmlstr_to_bytes(value);
2095 let mut start = 0usize;
2096 if space != 0 {
2097 while start < bytes.len() && is_blank_byte(bytes[start]) {
2098 start += 1;
2099 }
2100 }
2101 let end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2102 if end == start {
2103 return 1;
2104 }
2105 let mut end2 = end;
2106 if space != 0 {
2107 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2108 end2 += 1;
2109 }
2110 }
2111 if end2 == bytes.len() {
2112 0
2113 } else {
2114 1
2115 }
2116}
2117
2118pub unsafe fn validate_qname(value: *const xmlChar, space: c_int) -> c_int {
2124 if value.is_null() {
2125 return -1;
2126 }
2127 let bytes = string::xmlstr_to_bytes(value);
2128 let mut start = 0usize;
2129 if space != 0 {
2130 while start < bytes.len() && is_blank_byte(bytes[start]) {
2131 start += 1;
2132 }
2133 }
2134 let mut end = scan_name_offsets(bytes, start, XML_SCAN_NC);
2135 if end == start {
2136 return 1;
2137 }
2138 if end < bytes.len() && bytes[end] == b':' {
2139 end += 1;
2140 let end2 = scan_name_offsets(bytes, end, XML_SCAN_NC);
2141 if end2 == end {
2142 return 1;
2143 }
2144 end = end2;
2145 }
2146 if space != 0 {
2147 while end < bytes.len() && is_blank_byte(bytes[end]) {
2148 end += 1;
2149 }
2150 }
2151 if end == bytes.len() {
2152 0
2153 } else {
2154 1
2155 }
2156}
2157
2158pub unsafe fn validate_name_space(value: *const xmlChar, space: c_int) -> c_int {
2169 if value.is_null() {
2170 return -1;
2171 }
2172 let bytes = string::xmlstr_to_bytes(value);
2173 let mut start = 0usize;
2174 if space != 0 {
2175 while start < bytes.len() && is_blank_byte(bytes[start]) {
2176 start += 1;
2177 }
2178 }
2179 let end = scan_name_offsets(bytes, start, 0);
2180 if end == start {
2181 return 1;
2182 }
2183 let mut end2 = end;
2184 if space != 0 {
2185 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2186 end2 += 1;
2187 }
2188 }
2189 if end2 == bytes.len() {
2190 0
2191 } else {
2192 1
2193 }
2194}
2195
2196pub unsafe fn validate_nmtoken_space(value: *const xmlChar, space: c_int) -> c_int {
2202 if value.is_null() {
2203 return -1;
2204 }
2205 let bytes = string::xmlstr_to_bytes(value);
2206 let mut start = 0usize;
2207 if space != 0 {
2208 while start < bytes.len() && is_blank_byte(bytes[start]) {
2209 start += 1;
2210 }
2211 }
2212 let end = scan_name_offsets(bytes, start, XML_SCAN_NMTOKEN);
2213 if end == start {
2214 return 1;
2215 }
2216 let mut end2 = end;
2217 if space != 0 {
2218 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2219 end2 += 1;
2220 }
2221 }
2222 if end2 == bytes.len() {
2223 0
2224 } else {
2225 1
2226 }
2227}
2228
2229unsafe fn validate_value_internal(value: *const xmlChar, flags: u32) -> c_int {
2232 if value.is_null() {
2233 return 0;
2234 }
2235 let bytes = string::xmlstr_to_bytes(value);
2236 if bytes.is_empty() {
2237 return 0;
2238 }
2239 let end = scan_name_offsets(bytes, 0, flags);
2240 if end == 0 {
2241 return 0;
2242 }
2243 if end == bytes.len() {
2244 1
2245 } else {
2246 0
2247 }
2248}
2249
2250unsafe fn validate_values_internal(value: *const xmlChar, flags: u32) -> c_int {
2253 if value.is_null() {
2254 return 0;
2255 }
2256 let bytes = string::xmlstr_to_bytes(value);
2257 let mut cur = scan_name_offsets(bytes, 0, flags);
2258 if cur == 0 {
2259 return 0;
2260 }
2261 while cur < bytes.len() && bytes[cur] == b' ' {
2262 while cur < bytes.len() && bytes[cur] == b' ' {
2263 cur += 1;
2264 }
2265 let end = scan_name_offsets(bytes, cur, flags);
2266 if end == cur {
2267 return 0;
2268 }
2269 cur = end;
2270 }
2271 if cur == bytes.len() {
2272 1
2273 } else {
2274 0
2275 }
2276}
2277
2278pub unsafe fn validate_name_value(value: *const xmlChar) -> c_int {
2284 validate_value_internal(value, 0)
2285}
2286
2287pub unsafe fn validate_names_value(value: *const xmlChar) -> c_int {
2293 validate_values_internal(value, 0)
2294}
2295
2296pub unsafe fn validate_nmtoken_value(value: *const xmlChar) -> c_int {
2302 validate_value_internal(value, XML_SCAN_NMTOKEN)
2303}
2304
2305pub unsafe fn validate_nmtokens_value(value: *const xmlChar) -> c_int {
2311 validate_values_internal(value, XML_SCAN_NMTOKEN)
2312}
2313
2314pub unsafe fn get_dtd_qelement_desc(
2325 dtd: *mut _xmlDtd,
2326 name: *const xmlChar,
2327 prefix: *const xmlChar,
2328) -> *mut _xmlElement {
2329 if dtd.is_null() {
2330 return ptr::null_mut();
2331 }
2332 unsafe {
2333 let elements = (*dtd).elements;
2334 if elements.is_null() {
2335 return ptr::null_mut();
2336 }
2337 hash::hash_lookup2(elements as *mut hash::HashTable, name, prefix) as *mut _xmlElement
2338 }
2339}
2340
2341pub unsafe fn get_dtd_qattr_desc(
2349 dtd: *mut _xmlDtd,
2350 elem: *const xmlChar,
2351 name: *const xmlChar,
2352 prefix: *const xmlChar,
2353) -> *mut _xmlAttribute {
2354 if dtd.is_null() || elem.is_null() || name.is_null() {
2355 return ptr::null_mut();
2356 }
2357 unsafe {
2358 let attrs = (*dtd).attributes;
2359 if attrs.is_null() {
2360 return ptr::null_mut();
2361 }
2362 hash::hash_lookup3(attrs as *mut hash::HashTable, name, prefix, elem) as *mut _xmlAttribute
2363 }
2364}
2365
2366pub unsafe fn get_dtd_notation_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlNotation {
2372 if dtd.is_null() || name.is_null() {
2373 return ptr::null_mut();
2374 }
2375 unsafe {
2376 let notations = (*dtd).notations;
2377 if notations.is_null() {
2378 return ptr::null_mut();
2379 }
2380 hash::hash_lookup(notations as *mut hash::HashTable, name) as *mut _xmlNotation
2381 }
2382}
2383
2384pub unsafe fn split_qname4(name: *const xmlChar, prefix: *mut *mut xmlChar) -> *const xmlChar {
2393 if prefix.is_null() {
2394 return name;
2395 }
2396 unsafe {
2397 *prefix = ptr::null_mut();
2398 if name.is_null() {
2399 return ptr::null();
2400 }
2401 let bytes = string::xmlstr_to_bytes(name);
2402 match bytes.iter().position(|&b| b == b':') {
2403 None => name,
2404 Some(pos) => {
2405 let p = string::bytes_to_xmlstr(&bytes[..pos]);
2406 *prefix = p;
2407 name.add(pos + 1)
2408 }
2409 }
2410 }
2411}
2412
2413unsafe fn free_id(id: *mut _xmlID) {
2428 if id.is_null() {
2429 return;
2430 }
2431 unsafe {
2432 if !(*id).value.is_null() {
2433 allocator::xmlFreeImpl((*id).value as *mut c_void);
2434 }
2435 if !(*id).name.is_null() {
2436 allocator::xmlFreeImpl((*id).name as *mut c_void);
2437 }
2438 if !(*id).attr.is_null() {
2439 (*(*id).attr).id = ptr::null_mut();
2440 (*(*id).attr).atype = 0;
2441 }
2442 allocator::xmlFreeImpl(id as *mut c_void);
2443 }
2444}
2445
2446unsafe extern "C" fn free_id_entry(payload: *mut c_void, _name: *mut xmlChar) {
2449 free_id(payload as *mut _xmlID);
2450}
2451
2452unsafe fn add_id_internal(
2464 attr: *mut _xmlAttr,
2465 value: *const xmlChar,
2466 id_ptr: *mut *mut _xmlID,
2467) -> c_int {
2468 unsafe {
2469 if !id_ptr.is_null() {
2470 *id_ptr = ptr::null_mut();
2471 }
2472 if value.is_null() || *value == 0 {
2473 return 0;
2474 }
2475 if attr.is_null() {
2476 return 0;
2477 }
2478 let doc = (*attr).doc;
2479 if doc.is_null() {
2480 return 0;
2481 }
2482
2483 let mut table = (*doc).ids as *mut hash::HashTable;
2484 if table.is_null() {
2485 (*doc).ids = hash::hash_create(0) as *mut c_void;
2486 table = (*doc).ids as *mut hash::HashTable;
2487 if table.is_null() {
2488 return -1;
2489 }
2490 } else if !hash::hash_lookup(table, value).is_null() {
2491 return 0;
2492 }
2493
2494 let id = allocator::xmlMallocZero(size_of::<_xmlID>() as usize) as *mut _xmlID;
2495 if id.is_null() {
2496 return -1;
2497 }
2498 (*id).doc = doc;
2499 (*id).value = string::xml_strdup(value);
2500 if (*id).value.is_null() {
2501 free_id(id);
2502 return -1;
2503 }
2504 if !(*attr).id.is_null() {
2506 remove_id(doc, attr);
2507 }
2508 if hash::hash_add_entry(table, value, id as *mut c_void) != 0 {
2509 free_id(id);
2510 return -1;
2511 }
2512 if !id_ptr.is_null() {
2513 *id_ptr = id;
2514 }
2515 (*id).attr = attr;
2516 (*id).lineno = tree::get_line_no((*attr).parent) as c_int;
2517 (*attr).atype = XML_ATTRIBUTE_ID as c_int;
2518 (*attr).id = id as *mut c_void;
2519 1
2520 }
2521}
2522
2523pub unsafe fn add_id(
2531 ctxt: *mut _xmlValidCtxt,
2532 doc: *mut _xmlDoc,
2533 value: *const xmlChar,
2534 attr: *mut _xmlAttr,
2535) -> *mut _xmlID {
2536 unsafe {
2537 if attr.is_null() || doc != (*attr).doc {
2538 return ptr::null_mut();
2539 }
2540 let mut id = ptr::null_mut();
2541 let res = add_id_internal(attr, value, &mut id);
2542 if res < 0 {
2543 vctxt_error(
2544 ctxt,
2545 b"Memory allocation failed : xmlAddID\0" as *const u8 as *const c_char,
2546 );
2547 } else if res == 0 && !ctxt.is_null() {
2548 let msg = format!("ID {} already defined\0", string::xmlstr_to_string(value));
2549 vctxt_error(ctxt, msg.as_ptr() as *const c_char);
2550 }
2551 id
2552 }
2553}
2554
2555pub unsafe fn remove_id(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2562 unsafe {
2563 if doc.is_null() {
2564 return -1;
2565 }
2566 if attr.is_null() || (*attr).id.is_null() {
2567 return -1;
2568 }
2569 let table = (*doc).ids as *mut hash::HashTable;
2570 if table.is_null() {
2571 return -1;
2572 }
2573 let value = (*((*attr).id as *mut _xmlID)).value;
2574 if hash::hash_remove_entry(table, value, Some(free_id_entry)) < 0 {
2575 return -1;
2576 }
2577 0
2578 }
2579}
2580
2581unsafe fn free_ref(r: *mut _xmlRef) {
2589 if r.is_null() {
2590 return;
2591 }
2592 unsafe {
2593 if !(*r).value.is_null() {
2594 allocator::xmlFreeImpl((*r).value as *mut c_void);
2595 }
2596 if !(*r).name.is_null() {
2597 allocator::xmlFreeImpl((*r).name as *mut c_void);
2598 }
2599 allocator::xmlFreeImpl(r as *mut c_void);
2600 }
2601}
2602
2603unsafe extern "C" fn free_ref_list_entry(data: *mut c_void) {
2605 free_ref(data as *mut _xmlRef);
2606}
2607
2608const unsafe extern "C" fn dummy_compare(_a: *const c_void, _b: *const c_void) -> c_int {
2610 1
2611}
2612
2613unsafe extern "C" fn free_ref_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
2615 crate::xml::list::list_delete(payload as *mut crate::xml::list::List);
2616}
2617
2618pub unsafe fn add_ref(
2625 ctxt: *mut _xmlValidCtxt,
2626 doc: *mut _xmlDoc,
2627 value: *const xmlChar,
2628 attr: *mut _xmlAttr,
2629) -> *mut _xmlRef {
2630 unsafe {
2631 if doc.is_null() || value.is_null() || attr.is_null() {
2632 return ptr::null_mut();
2633 }
2634
2635 let mut table = (*doc).refs as *mut hash::HashTable;
2636 if table.is_null() {
2637 (*doc).refs = hash::hash_create(0) as *mut c_void;
2638 table = (*doc).refs as *mut hash::HashTable;
2639 if table.is_null() {
2640 vctxt_error(
2641 ctxt,
2642 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2643 );
2644 return ptr::null_mut();
2645 }
2646 }
2647
2648 let ret = allocator::xmlMallocZero(size_of::<_xmlRef>() as usize) as *mut _xmlRef;
2649 if ret.is_null() {
2650 vctxt_error(
2651 ctxt,
2652 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2653 );
2654 return ptr::null_mut();
2655 }
2656 (*ret).value = string::xml_strdup(value);
2657 if (*ret).value.is_null() {
2658 free_ref(ret);
2659 vctxt_error(
2660 ctxt,
2661 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2662 );
2663 return ptr::null_mut();
2664 }
2665 let streaming = !ctxt.is_null()
2669 && !(*ctxt).userData.is_null()
2670 && (*((*ctxt).userData as *mut _xmlParserCtxt)).parseMode
2671 == crate::abi::types::xmlParserMode::XML_PARSE_READER as c_int;
2672 if streaming {
2673 (*ret).name = string::xml_strdup((*attr).name);
2674 (*ret).attr = ptr::null_mut();
2675 } else {
2676 (*ret).name = ptr::null();
2677 (*ret).attr = attr;
2678 }
2679 (*ret).lineno = tree::get_line_no((*attr).parent) as c_int;
2680
2681 let ref_list = hash::hash_lookup(table, value) as *mut crate::xml::list::List;
2683 if ref_list.is_null() {
2684 let l = crate::xml::list::list_create(Some(free_ref_list_entry), Some(dummy_compare));
2685 if l.is_null() {
2686 free_ref(ret);
2687 vctxt_error(
2688 ctxt,
2689 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2690 );
2691 return ptr::null_mut();
2692 }
2693 if hash::hash_add_entry(table, value, l as *mut c_void) != 0 {
2694 crate::xml::list::list_delete(l);
2695 free_ref(ret);
2696 vctxt_error(
2697 ctxt,
2698 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2699 );
2700 return ptr::null_mut();
2701 }
2702 crate::xml::list::list_append(l, ret as *mut c_void);
2703 } else {
2704 if crate::xml::list::list_append(ref_list, ret as *mut c_void) != 0 {
2705 free_ref(ret);
2706 vctxt_error(
2707 ctxt,
2708 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2709 );
2710 return ptr::null_mut();
2711 }
2712 }
2713 ret
2714 }
2715}
2716
2717pub unsafe fn remove_ref(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2724 if doc.is_null() || attr.is_null() {
2728 return -1;
2729 }
2730 unsafe {
2731 let table = (*doc).refs as *mut hash::HashTable;
2732 if table.is_null() {
2733 return -1;
2734 }
2735 let mut removed = -1;
2736 struct ScanCtx {
2738 table: *mut hash::HashTable,
2739 attr: *mut _xmlAttr,
2740 removed: c_int,
2741 }
2742 extern "C" fn scan_remove(payload: *mut c_void, data: *mut c_void, name: *const xmlChar) {
2743 let ctx = unsafe { &mut *(data as *mut ScanCtx) };
2744 let l = payload as *mut crate::xml::list::List;
2745 let mut cur: *mut c_void = crate::xml::list::list_front(l);
2747 while !cur.is_null() {
2748 let next: *mut c_void = unsafe { (*(cur as *mut _xmlRef)).next as *mut c_void };
2749 let r = cur as *mut _xmlRef;
2750 if unsafe { (*r).attr } == ctx.attr {
2751 unsafe {
2752 crate::xml::list::list_remove_first(l, cur);
2753 }
2754 ctx.removed = 0;
2755 }
2756 cur = next;
2757 }
2758 if crate::xml::list::list_empty(l) != 0 {
2759 unsafe {
2760 hash::hash_remove_entry(ctx.table, name, Some(free_ref_table_entry));
2761 }
2762 }
2763 let _ = name;
2764 }
2765 let mut ctx = ScanCtx {
2766 table,
2767 attr,
2768 removed: -1,
2769 };
2770 hash::hash_scan(
2771 table,
2772 Some(scan_remove),
2773 &mut ctx as *mut ScanCtx as *mut c_void,
2774 );
2775 removed = ctx.removed;
2776 removed
2777 }
2778}
2779
2780pub unsafe fn add_id_safe(attr: *mut _xmlAttr, value: *const xmlChar) -> c_int {
2788 add_id_internal(attr, value, ptr::null_mut())
2789}
2790
2791pub unsafe fn free_id_table(table: *mut hash::HashTable) {
2797 hash::hash_free(table, Some(free_id_entry));
2798}
2799
2800pub unsafe fn free_ref_table(table: *mut hash::HashTable) {
2806 hash::hash_free(table, Some(free_ref_table_entry));
2807}
2808
2809pub unsafe fn get_id(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut _xmlAttr {
2817 unsafe {
2818 if doc.is_null() || id.is_null() {
2819 return ptr::null_mut();
2820 }
2821 let table = (*doc).ids as *mut hash::HashTable;
2822 if table.is_null() {
2823 return ptr::null_mut();
2824 }
2825 let id_entry = hash::hash_lookup(table, id) as *mut _xmlID;
2826 if id_entry.is_null() {
2827 return ptr::null_mut();
2828 }
2829 if (*id_entry).attr.is_null() {
2830 doc as *mut _xmlAttr
2832 } else {
2833 (*id_entry).attr
2834 }
2835 }
2836}
2837
2838pub unsafe fn get_refs(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut crate::xml::list::List {
2844 unsafe {
2845 if doc.is_null() || id.is_null() {
2846 return ptr::null_mut();
2847 }
2848 let table = (*doc).refs as *mut hash::HashTable;
2849 if table.is_null() {
2850 return ptr::null_mut();
2851 }
2852 hash::hash_lookup(table, id) as *mut crate::xml::list::List
2853 }
2854}
2855
2856pub unsafe fn is_id(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2864 unsafe {
2865 if attr.is_null() || (*attr).name.is_null() {
2866 return 0;
2867 }
2868 if !doc.is_null() && (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2869 if string::xml_strcmp(b"id\0" as *const u8 as *const xmlChar, (*attr).name) == 0 {
2870 return 1;
2871 }
2872 if elem.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
2873 return 0;
2874 }
2875 if string::xml_strcmp(b"name\0" as *const u8 as *const xmlChar, (*attr).name) == 0
2876 && string::xml_strcmp(b"a\0" as *const u8 as *const xmlChar, (*elem).name) == 0
2877 {
2878 return 1;
2879 }
2880 } else {
2881 if !(*attr).ns.is_null()
2883 && !(*(*attr).ns).prefix.is_null()
2884 && string::xml_strcmp(
2885 (*(*attr).ns).prefix,
2886 b"xml\0" as *const u8 as *const xmlChar,
2887 ) == 0
2888 && string::xml_strcmp((*attr).name, b"id\0" as *const u8 as *const xmlChar) == 0
2889 {
2890 return 1;
2891 }
2892 if doc.is_null() || ((*doc).intSubset.is_null() && (*doc).extSubset.is_null()) {
2893 return 0;
2894 }
2895 if elem.is_null()
2896 || (*elem).type_ != XML_ELEMENT_NODE as c_int
2897 || (*elem).name.is_null()
2898 {
2899 return 0;
2900 }
2901 let mut fullname = (*elem).name;
2902 let mut owned = false;
2903 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
2904 let f = string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
2905 if f.is_null() {
2906 return -1;
2907 }
2908 fullname = f;
2909 owned = true;
2910 }
2911 let aprefix = if !(*attr).ns.is_null() {
2912 (*(*attr).ns).prefix
2913 } else {
2914 ptr::null()
2915 };
2916 let mut attr_decl =
2917 get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
2918 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2919 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
2920 }
2921 if owned {
2922 allocator::xmlFreeImpl(fullname as *mut c_void);
2923 }
2924 if !attr_decl.is_null() && (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int {
2925 return 1;
2926 }
2927 }
2928 0
2929 }
2930}
2931
2932pub unsafe fn is_ref(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2938 unsafe {
2939 if attr.is_null() {
2940 return 0;
2941 }
2942 let doc = if doc.is_null() { (*attr).doc } else { doc };
2943 if doc.is_null() {
2944 return 0;
2945 }
2946 if (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2947 return 0;
2948 }
2949 if (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2950 return 0;
2951 }
2952 if elem.is_null() {
2953 return 0;
2954 }
2955 let aprefix = if !(*attr).ns.is_null() {
2956 (*(*attr).ns).prefix
2957 } else {
2958 ptr::null()
2959 };
2960 let mut attr_decl =
2961 get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
2962 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2963 attr_decl = get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
2964 }
2965 if !attr_decl.is_null()
2966 && ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
2967 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
2968 {
2969 return 1;
2970 }
2971 0
2972 }
2973}
2974
2975pub unsafe fn get_dtd_element_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlElement {
2982 unsafe {
2983 if dtd.is_null() || name.is_null() {
2984 return ptr::null_mut();
2985 }
2986 let elements = (*dtd).elements;
2987 if elements.is_null() {
2988 return ptr::null_mut();
2989 }
2990 let mut prefix = ptr::null_mut();
2991 let local = split_qname4(name, &mut prefix);
2992 if local.is_null() {
2993 if !prefix.is_null() {
2994 allocator::xmlFreeImpl(prefix as *mut c_void);
2995 }
2996 return ptr::null_mut();
2997 }
2998 let cur =
2999 hash::hash_lookup2(elements as *mut hash::HashTable, local, prefix) as *mut _xmlElement;
3000 if !prefix.is_null() {
3001 allocator::xmlFreeImpl(prefix as *mut c_void);
3002 }
3003 cur
3004 }
3005}
3006
3007pub unsafe fn get_dtd_attr_desc(
3015 dtd: *mut _xmlDtd,
3016 elem: *const xmlChar,
3017 name: *const xmlChar,
3018) -> *mut _xmlAttribute {
3019 unsafe {
3020 if dtd.is_null() || elem.is_null() || name.is_null() {
3021 return ptr::null_mut();
3022 }
3023 let attrs = (*dtd).attributes;
3024 if attrs.is_null() {
3025 return ptr::null_mut();
3026 }
3027 let mut prefix = ptr::null_mut();
3028 let local = split_qname4(name, &mut prefix);
3029 if local.is_null() {
3030 if !prefix.is_null() {
3031 allocator::xmlFreeImpl(prefix as *mut c_void);
3032 }
3033 return ptr::null_mut();
3034 }
3035 let cur = hash::hash_lookup3(attrs as *mut hash::HashTable, local, prefix, elem)
3036 as *mut _xmlAttribute;
3037 if !prefix.is_null() {
3038 allocator::xmlFreeImpl(prefix as *mut c_void);
3039 }
3040 cur
3041 }
3042}
3043
3044unsafe fn vctxt_error_node(ctxt: *mut _xmlValidCtxt, _node: *mut _xmlNode, msg: *const c_char) {
3054 vctxt_error(ctxt, msg);
3055}
3056
3057pub unsafe fn validate_element_decl(
3065 ctxt: *mut _xmlValidCtxt,
3066 doc: *mut _xmlDoc,
3067 elem: *mut _xmlElement,
3068) -> c_int {
3069 unsafe {
3070 if doc.is_null() || (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
3071 return 1;
3072 }
3073 if elem.is_null() {
3074 return 1;
3075 }
3076 let mut ret = 1;
3077
3078 if (*elem).etype == XML_ELEMENT_TYPE_MIXED as c_int {
3081 let mut cur = (*elem).content;
3082 while !cur.is_null() {
3083 if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int {
3084 break;
3085 }
3086 if (*cur).c1.is_null() {
3087 break;
3088 }
3089 if (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3090 let name = (*(*cur).c1).name;
3091 let mut next = (*cur).c2;
3092 while !next.is_null() {
3093 if (*next).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3094 if string::xml_strcmp((*next).name, name) == 0
3095 && string::xml_strcmp((*next).prefix, (*(*cur).c1).prefix) == 0
3096 {
3097 if (*(*cur).c1).prefix.is_null() {
3098 let msg = format!(
3099 "Definition of {} has duplicate references of {}\0",
3100 string::xmlstr_to_string((*elem).name),
3101 string::xmlstr_to_string(name)
3102 );
3103 vctxt_error_node(
3104 ctxt,
3105 elem as *mut _xmlNode,
3106 msg.as_ptr() as *const c_char,
3107 );
3108 } else {
3109 let msg = format!(
3110 "Definition of {} has duplicate references of {}:{}\0",
3111 string::xmlstr_to_string((*elem).name),
3112 string::xmlstr_to_string((*(*cur).c1).prefix),
3113 string::xmlstr_to_string(name)
3114 );
3115 vctxt_error_node(
3116 ctxt,
3117 elem as *mut _xmlNode,
3118 msg.as_ptr() as *const c_char,
3119 );
3120 }
3121 ret = 0;
3122 }
3123 break;
3124 }
3125 if (*next).c1.is_null() {
3126 break;
3127 }
3128 if (*(*next).c1).type_ != XML_ELEMENT_CONTENT_ELEMENT as c_int {
3129 break;
3130 }
3131 if string::xml_strcmp((*(*next).c1).name, name) == 0
3132 && string::xml_strcmp((*(*next).c1).prefix, (*(*cur).c1).prefix) == 0
3133 {
3134 if (*(*cur).c1).prefix.is_null() {
3135 let msg = format!(
3136 "Definition of {} has duplicate references to {}\0",
3137 string::xmlstr_to_string((*elem).name),
3138 string::xmlstr_to_string(name)
3139 );
3140 vctxt_error_node(
3141 ctxt,
3142 elem as *mut _xmlNode,
3143 msg.as_ptr() as *const c_char,
3144 );
3145 } else {
3146 let msg = format!(
3147 "Definition of {} has duplicate references to {}:{}\0",
3148 string::xmlstr_to_string((*elem).name),
3149 string::xmlstr_to_string((*(*cur).c1).prefix),
3150 string::xmlstr_to_string(name)
3151 );
3152 vctxt_error_node(
3153 ctxt,
3154 elem as *mut _xmlNode,
3155 msg.as_ptr() as *const c_char,
3156 );
3157 }
3158 ret = 0;
3159 }
3160 next = (*next).c2;
3161 }
3162 }
3163 cur = (*cur).c2;
3164 }
3165 }
3166
3167 let mut prefix = ptr::null_mut();
3170 let local_name = split_qname4((*elem).name, &mut prefix);
3171 if local_name.is_null() {
3172 vctxt_error(
3173 ctxt,
3174 b"Memory allocation failed : xmlValidateElementDecl\0" as *const u8
3175 as *const c_char,
3176 );
3177 if !prefix.is_null() {
3178 allocator::xmlFreeImpl(prefix as *mut c_void);
3179 }
3180 return 0;
3181 }
3182
3183 for subset in [(*doc).intSubset, (*doc).extSubset] {
3184 if subset.is_null() {
3185 continue;
3186 }
3187 let tst = get_dtd_qelement_desc(subset, local_name, prefix);
3188 if !tst.is_null()
3189 && tst != elem
3190 && ((*tst).prefix == (*elem).prefix
3191 || string::xml_strcmp((*tst).prefix, (*elem).prefix) == 0)
3192 && (*tst).etype != XML_ELEMENT_TYPE_UNDEFINED as c_int
3193 {
3194 let msg = format!(
3195 "Redefinition of element {}\0",
3196 string::xmlstr_to_string((*elem).name)
3197 );
3198 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
3199 ret = 0;
3200 }
3201 }
3202 if !prefix.is_null() {
3203 allocator::xmlFreeImpl(prefix as *mut c_void);
3204 }
3205 ret
3206 }
3207}
3208
3209pub const unsafe fn validate_notation_decl(
3228 _ctxt: *mut _xmlValidCtxt,
3229 _doc: *mut _xmlDoc,
3230 _nota: *mut _xmlNotation,
3231) -> c_int {
3232 1
3233}
3234
3235pub unsafe fn validate_one_attribute(
3245 ctxt: *mut _xmlValidCtxt,
3246 doc: *mut _xmlDoc,
3247 elem: *mut _xmlNode,
3248 attr: *mut _xmlAttr,
3249 value: *const xmlChar,
3250) -> c_int {
3251 unsafe {
3252 if doc.is_null() {
3253 return 0;
3254 }
3255 if elem.is_null() || (*elem).name.is_null() {
3256 return 0;
3257 }
3258 if attr.is_null() || (*attr).name.is_null() {
3259 return 0;
3260 }
3261 let mut ret = 1;
3262
3263 let aprefix = if !(*attr).ns.is_null() {
3264 (*(*attr).ns).prefix
3265 } else {
3266 ptr::null()
3267 };
3268
3269 let mut attr_decl = ptr::null_mut();
3270 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3271 let fullname =
3272 string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
3273 if fullname.is_null() {
3274 vctxt_error(
3275 ctxt,
3276 b"Memory allocation failed : xmlValidateOneAttribute\0" as *const u8
3277 as *const c_char,
3278 );
3279 return 0;
3280 }
3281 attr_decl = get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
3282 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3283 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
3284 }
3285 if !std::ptr::eq(fullname, (*elem).name) {
3286 allocator::xmlFreeImpl(fullname as *mut c_void);
3287 }
3288 }
3289 if attr_decl.is_null() {
3290 attr_decl = get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
3291 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3292 attr_decl =
3293 get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
3294 }
3295 }
3296
3297 if attr_decl.is_null() {
3299 let msg = format!(
3300 "No declaration for attribute {} of element {}\0",
3301 string::xmlstr_to_string((*attr).name),
3302 string::xmlstr_to_string((*elem).name)
3303 );
3304 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3305 return 0;
3306 }
3307 if !(*attr).id.is_null() {
3308 remove_id(doc, attr);
3309 }
3310 (*attr).atype = (*attr_decl).atype;
3311
3312 let val = if (*doc).properties & crate::abi::types::xmlDocProperties::XML_DOC_OLD10 as c_int
3314 != 0
3315 {
3316 match (*attr_decl).atype as u32 {
3319 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
3320 validate_values_internal(value, 0)
3321 }
3322 t if t == XML_ATTRIBUTE_ENTITY as u32
3323 || t == XML_ATTRIBUTE_IDREF as u32
3324 || t == XML_ATTRIBUTE_ID as u32
3325 || t == XML_ATTRIBUTE_NOTATION as u32 =>
3326 {
3327 validate_value_internal(value, 0)
3328 }
3329 t if t == XML_ATTRIBUTE_NMTOKENS as u32
3330 || t == XML_ATTRIBUTE_ENUMERATION as u32 =>
3331 {
3332 validate_values_internal(value, XML_SCAN_NMTOKEN)
3333 }
3334 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => {
3335 validate_value_internal(value, XML_SCAN_NMTOKEN)
3336 }
3337 _ => 1,
3338 }
3339 } else {
3340 validate_attribute_value((*attr_decl).atype, value)
3341 };
3342 if val == 0 {
3343 let msg = format!(
3344 "Syntax of value for attribute {} of {} is not valid\0",
3345 string::xmlstr_to_string((*attr).name),
3346 string::xmlstr_to_string((*elem).name)
3347 );
3348 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3349 ret = 0;
3350 }
3351
3352 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3354 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3355 {
3356 let _msg = format!(
3357 "Value for attribute {} of {} is different from default \"{}\n\0",
3358 string::xmlstr_to_string((*attr).name),
3359 string::xmlstr_to_string((*elem).name),
3360 string::xmlstr_to_string((*attr_decl).defaultValue)
3361 );
3362 let msg = format!(
3364 "Value for attribute {} of {} is different from default \"{}\"\0",
3365 string::xmlstr_to_string((*attr).name),
3366 string::xmlstr_to_string((*elem).name),
3367 string::xmlstr_to_string((*attr_decl).defaultValue)
3368 );
3369 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3370 ret = 0;
3371 }
3372
3373 const XML_VCTXT_IN_ENTITY: c_uint = 4; if (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int
3376 && (ctxt.is_null() || (*ctxt).flags & XML_VCTXT_IN_ENTITY == 0)
3377 && add_id(ctxt, doc, value, attr).is_null()
3378 {
3379 ret = 0;
3380 }
3381 if ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
3382 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
3383 && add_ref(ctxt, doc, value, attr).is_null()
3384 {
3385 ret = 0;
3386 }
3387
3388 if (*attr_decl).atype == XML_ATTRIBUTE_NOTATION as c_int {
3390 let mut nota = get_dtd_notation_desc((*doc).intSubset, value);
3391 if nota.is_null() {
3392 nota = get_dtd_notation_desc((*doc).extSubset, value);
3393 }
3394 if nota.is_null() {
3395 let msg = format!(
3396 "Value \"{}\" for attribute {} of {} is not a declared Notation\0",
3397 string::xmlstr_to_string(value),
3398 string::xmlstr_to_string((*attr).name),
3399 string::xmlstr_to_string((*elem).name)
3400 );
3401 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3402 ret = 0;
3403 }
3404 let mut tree = (*attr_decl).tree;
3405 while !tree.is_null() {
3406 if string::xml_strcmp((*tree).name, value) == 0 {
3407 break;
3408 }
3409 tree = (*tree).next;
3410 }
3411 if tree.is_null() {
3412 let msg = format!(
3413 "Value \"{}\" for attribute {} of {} is not among the enumerated notations\0",
3414 string::xmlstr_to_string(value),
3415 string::xmlstr_to_string((*attr).name),
3416 string::xmlstr_to_string((*elem).name)
3417 );
3418 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3419 ret = 0;
3420 }
3421 }
3422
3423 if (*attr_decl).atype == XML_ATTRIBUTE_ENUMERATION as c_int {
3425 let mut tree = (*attr_decl).tree;
3426 while !tree.is_null() {
3427 if string::xml_strcmp((*tree).name, value) == 0 {
3428 break;
3429 }
3430 tree = (*tree).next;
3431 }
3432 if tree.is_null() {
3433 let msg = format!(
3434 "Value \"{}\" for attribute {} of {} is not among the enumerated set\0",
3435 string::xmlstr_to_string(value),
3436 string::xmlstr_to_string((*attr).name),
3437 string::xmlstr_to_string((*elem).name)
3438 );
3439 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3440 ret = 0;
3441 }
3442 }
3443
3444 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3446 && string::xml_strcmp((*attr_decl).defaultValue, value) != 0
3447 {
3448 let msg = format!(
3449 "Value for attribute {} of {} must be \"{}\"\0",
3450 string::xmlstr_to_string((*attr).name),
3451 string::xmlstr_to_string((*elem).name),
3452 string::xmlstr_to_string((*attr_decl).defaultValue)
3453 );
3454 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3455 ret = 0;
3456 }
3457
3458 if (*attr_decl).atype == XML_ATTRIBUTE_ENTITY as c_int {
3460 let ent = tree::get_doc_entity(doc, value);
3461 if ent.is_null() {
3462 let msg = format!(
3463 "ENTITY attribute {} reference an unknown entity \"{}\"\0",
3464 string::xmlstr_to_string((*attr).name),
3465 string::xmlstr_to_string(value)
3466 );
3467 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3468 ret = 0;
3469 } else if (*ent).etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3470 let msg = format!(
3471 "ENTITY attribute {} reference an entity \"{}\" of wrong type\0",
3472 string::xmlstr_to_string((*attr).name),
3473 string::xmlstr_to_string(value)
3474 );
3475 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3476 ret = 0;
3477 }
3478 }
3479 ret
3480 }
3481}
3482
3483pub unsafe fn validate_one_namespace(
3490 ctxt: *mut _xmlValidCtxt,
3491 doc: *mut _xmlDoc,
3492 elem: *mut _xmlNode,
3493 prefix: *const xmlChar,
3494 ns: *mut _xmlNs,
3495 value: *const xmlChar,
3496) -> c_int {
3497 unsafe {
3498 if doc.is_null() {
3499 return 0;
3500 }
3501 if elem.is_null() || (*elem).name.is_null() {
3502 return 0;
3503 }
3504 if ns.is_null() || (*ns).href.is_null() {
3505 return 0;
3506 }
3507 let mut ret = 1;
3508
3509 let mut attr_decl = ptr::null_mut();
3510 if !prefix.is_null() {
3511 let fullname = string::build_qname((*elem).name, prefix, ptr::null_mut(), 0);
3512 if fullname.is_null() {
3513 vctxt_error(
3514 ctxt,
3515 b"Memory allocation failed : xmlValidateOneNamespace\0" as *const u8
3516 as *const c_char,
3517 );
3518 return 0;
3519 }
3520 if !(*ns).prefix.is_null() {
3521 attr_decl = get_dtd_qattr_desc(
3522 (*doc).intSubset,
3523 fullname,
3524 (*ns).prefix,
3525 b"xmlns\0" as *const u8 as *const xmlChar,
3526 );
3527 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3528 attr_decl = get_dtd_qattr_desc(
3529 (*doc).extSubset,
3530 fullname,
3531 (*ns).prefix,
3532 b"xmlns\0" as *const u8 as *const xmlChar,
3533 );
3534 }
3535 } else {
3536 attr_decl = get_dtd_qattr_desc(
3537 (*doc).intSubset,
3538 fullname,
3539 b"xmlns\0" as *const u8 as *const xmlChar,
3540 ptr::null(),
3541 );
3542 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3543 attr_decl = get_dtd_qattr_desc(
3544 (*doc).extSubset,
3545 fullname,
3546 b"xmlns\0" as *const u8 as *const xmlChar,
3547 ptr::null(),
3548 );
3549 }
3550 }
3551 if !std::ptr::eq(fullname, (*elem).name) {
3552 allocator::xmlFreeImpl(fullname as *mut c_void);
3553 }
3554 }
3555 if attr_decl.is_null() {
3556 if !(*ns).prefix.is_null() {
3557 attr_decl = get_dtd_qattr_desc(
3558 (*doc).intSubset,
3559 (*elem).name,
3560 (*ns).prefix,
3561 b"xmlns\0" as *const u8 as *const xmlChar,
3562 );
3563 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3564 attr_decl = get_dtd_qattr_desc(
3565 (*doc).extSubset,
3566 (*elem).name,
3567 (*ns).prefix,
3568 b"xmlns\0" as *const u8 as *const xmlChar,
3569 );
3570 }
3571 } else {
3572 attr_decl = get_dtd_qattr_desc(
3573 (*doc).intSubset,
3574 (*elem).name,
3575 b"xmlns\0" as *const u8 as *const xmlChar,
3576 ptr::null(),
3577 );
3578 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3579 attr_decl = get_dtd_qattr_desc(
3580 (*doc).extSubset,
3581 (*elem).name,
3582 b"xmlns\0" as *const u8 as *const xmlChar,
3583 ptr::null(),
3584 );
3585 }
3586 }
3587 }
3588
3589 if attr_decl.is_null() {
3591 let msg = if !(*ns).prefix.is_null() {
3592 format!(
3593 "No declaration for attribute xmlns:{} of element {}\0",
3594 string::xmlstr_to_string((*ns).prefix),
3595 string::xmlstr_to_string((*elem).name)
3596 )
3597 } else {
3598 format!(
3599 "No declaration for attribute xmlns of element {}\0",
3600 string::xmlstr_to_string((*elem).name)
3601 )
3602 };
3603 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3604 return 0;
3605 }
3606
3607 let val = validate_attribute_value((*attr_decl).atype, value);
3608 if val == 0 {
3609 let msg = if !(*ns).prefix.is_null() {
3610 format!(
3611 "Syntax of value for attribute xmlns:{} of {} is not valid\0",
3612 string::xmlstr_to_string((*ns).prefix),
3613 string::xmlstr_to_string((*elem).name)
3614 )
3615 } else {
3616 format!(
3617 "Syntax of value for attribute xmlns of {} is not valid\0",
3618 string::xmlstr_to_string((*elem).name)
3619 )
3620 };
3621 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3622 ret = 0;
3623 }
3624
3625 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3627 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3628 {
3629 let msg = if !(*ns).prefix.is_null() {
3630 format!(
3631 "Value for attribute xmlns:{} of {} is different from default \"{}\"\0",
3632 string::xmlstr_to_string((*ns).prefix),
3633 string::xmlstr_to_string((*elem).name),
3634 string::xmlstr_to_string((*attr_decl).defaultValue)
3635 )
3636 } else {
3637 format!(
3638 "Value for attribute xmlns of {} is different from default \"{}\"\0",
3639 string::xmlstr_to_string((*elem).name),
3640 string::xmlstr_to_string((*attr_decl).defaultValue)
3641 )
3642 };
3643 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3644 ret = 0;
3645 }
3646 ret
3647 }
3648}
3649
3650pub unsafe fn validate_one_element(
3658 ctxt: *mut _xmlValidCtxt,
3659 doc: *mut _xmlDoc,
3660 elem: *mut _xmlNode,
3661) -> c_int {
3662 unsafe {
3663 if doc.is_null() {
3664 return 0;
3665 }
3666 if elem.is_null() {
3667 return 0;
3668 }
3669 match (*elem).type_ {
3670 t if t == XML_TEXT_NODE as c_int
3671 || t == XML_CDATA_SECTION_NODE as c_int
3672 || t == XML_ENTITY_REF_NODE as c_int
3673 || t == XML_PI_NODE as c_int
3674 || t == XML_COMMENT_NODE as c_int
3675 || t == XML_XINCLUDE_START as c_int
3676 || t == XML_XINCLUDE_END as c_int =>
3677 {
3678 return 1;
3679 }
3680 t if t == XML_ELEMENT_NODE as c_int => {}
3681 _ => {
3682 vctxt_error_node(
3683 ctxt,
3684 elem,
3685 b"unexpected element type\0" as *const u8 as *const c_char,
3686 );
3687 return 0;
3688 }
3689 }
3690
3691 let mut ret = 1;
3692 let mut extsubset = 0;
3693 let elem_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
3694 if elem_decl.is_null() {
3695 return 0;
3696 }
3697
3698 if (*ctxt).vstateNr == 0 {
3701 match (*elem_decl).etype as u32 {
3702 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => {
3703 let msg = format!(
3704 "No declaration for element {}\0",
3705 string::xmlstr_to_string((*elem).name)
3706 );
3707 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3708 return 0;
3709 }
3710 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
3711 if !(*elem).children.is_null() {
3712 let msg = format!(
3713 "Element {} was declared EMPTY this one has content\0",
3714 string::xmlstr_to_string((*elem).name)
3715 );
3716 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3717 ret = 0;
3718 }
3719 }
3720 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
3721 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
3722 if !(*elem_decl).content.is_null()
3723 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
3724 {
3725 let mut child = (*elem).children;
3727 while !child.is_null() {
3728 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3729 let msg = format!(
3730 "Element {} was declared #PCDATA but contains non text nodes\0",
3731 string::xmlstr_to_string((*elem).name)
3732 );
3733 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3734 ret = 0;
3735 break;
3736 }
3737 child = (*child).next;
3738 }
3739 } else {
3740 let mut child = (*elem).children;
3742 while !child.is_null() {
3743 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3744 let mut fullname = (*child).name;
3745 let mut own = false;
3746 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3747 let fnp = string::build_qname(
3748 (*child).name,
3749 (*(*child).ns).prefix,
3750 ptr::null_mut(),
3751 0,
3752 );
3753 if fnp.is_null() {
3754 vctxt_error(
3755 ctxt,
3756 b"Memory allocation failed : xmlValidateOneElement\0"
3757 as *const u8
3758 as *const c_char,
3759 );
3760 return 0;
3761 }
3762 fullname = fnp;
3763 own = true;
3764 }
3765 if validate_check_mixed(ctxt, (*elem_decl).content, fullname) != 1 {
3766 let msg = format!(
3767 "Element {} is not declared in {} list of possible children\0",
3768 string::xmlstr_to_string(fullname),
3769 string::xmlstr_to_string((*elem).name)
3770 );
3771 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3772 ret = 0;
3773 }
3774 if own {
3775 allocator::xmlFreeImpl(fullname as *mut c_void);
3776 }
3777 }
3778 child = (*child).next;
3779 }
3780 }
3781 }
3782 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
3783 let mut names: Vec<*const xmlChar> = Vec::new();
3786 let mut owned: Vec<*mut xmlChar> = Vec::new();
3787 let mut child = (*elem).children;
3788 while !child.is_null() {
3789 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3790 let mut fullname = (*child).name;
3791 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3792 let fnp = string::build_qname(
3793 (*child).name,
3794 (*(*child).ns).prefix,
3795 ptr::null_mut(),
3796 0,
3797 );
3798 if !fnp.is_null() {
3799 fullname = fnp;
3800 owned.push(fnp);
3801 }
3802 }
3803 names.push(fullname);
3804 }
3805 child = (*child).next;
3806 }
3807 let result = dtd::valid_content_model((*elem_decl).content, &names);
3808 for n in owned {
3809 allocator::xmlFreeImpl(n as *mut c_void);
3810 }
3811 if result != dtd::ContentModelResult::Valid {
3812 let msg = format!(
3813 "Element {} content does not follow the DTD\0",
3814 string::xmlstr_to_string((*elem).name)
3815 );
3816 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3817 ret = 0;
3818 }
3819 }
3820 _ => {}
3821 }
3822
3823 let mut attr = (*elem).properties;
3825 while !attr.is_null() {
3826 let aval = if !(*attr).children.is_null() {
3827 (*(*attr).children).content
3828 } else {
3829 ptr::null()
3830 };
3831 if validate_one_attribute(ctxt, doc, elem, attr, aval) == 0 {
3832 ret = 0;
3833 }
3834 attr = (*attr).next;
3835 }
3836 }
3837 ret
3838 }
3839}
3840
3841#[repr(C)]
3856struct ValidState {
3857 elem_decl: *mut _xmlElement,
3858 node: *mut _xmlNode,
3859 exec: *mut ContentModelExec,
3860}
3861
3862unsafe fn valid_get_elem_decl(
3874 ctxt: *mut _xmlValidCtxt,
3875 doc: *mut _xmlDoc,
3876 elem: *mut _xmlNode,
3877 extsubset: *mut c_int,
3878) -> *mut _xmlElement {
3879 unsafe {
3880 if ctxt.is_null() || doc.is_null() || elem.is_null() || (*elem).name.is_null() {
3881 return ptr::null_mut();
3882 }
3883 if !extsubset.is_null() {
3884 *extsubset = 0;
3885 }
3886 let mut elem_decl = ptr::null_mut();
3887
3888 let prefix = if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3889 (*(*elem).ns).prefix
3890 } else {
3891 ptr::null()
3892 };
3893 if !prefix.is_null() {
3894 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, prefix);
3895 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3896 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, prefix);
3897 if !elem_decl.is_null() && !extsubset.is_null() {
3898 *extsubset = 1;
3899 }
3900 }
3901 }
3902 if elem_decl.is_null() {
3903 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, ptr::null());
3905 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3906 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, ptr::null());
3907 if !elem_decl.is_null() && !extsubset.is_null() {
3908 *extsubset = 1;
3909 }
3910 }
3911 }
3912 if elem_decl.is_null() {
3913 let msg = format!(
3914 "No declaration for element {}\0",
3915 string::xmlstr_to_string((*elem).name)
3916 );
3917 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3918 }
3919 elem_decl
3920 }
3921}
3922
3923pub(crate) unsafe fn validate_check_mixed(
3934 ctxt: *mut _xmlValidCtxt,
3935 cont: *mut _xmlElementContent,
3936 qname: *const xmlChar,
3937) -> c_int {
3938 unsafe {
3939 let mut plen: c_int = 0;
3940 let local = string::split_qname3(qname, &mut plen);
3944 let mut cur = cont;
3945 if local.is_null() {
3946 while !cur.is_null() {
3947 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3948 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
3949 return 1;
3950 }
3951 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3952 && !(*cur).c1.is_null()
3953 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3954 {
3955 if (*(*cur).c1).prefix.is_null()
3956 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3957 {
3958 return 1;
3959 }
3960 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3961 || (*cur).c1.is_null()
3962 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3963 {
3964 vctxt_error(
3965 ctxt,
3966 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3967 );
3968 break;
3969 }
3970 cur = (*cur).c2;
3971 }
3972 } else {
3973 while !cur.is_null() {
3974 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3975 if !(*cur).prefix.is_null()
3976 && prefix_matches((*cur).prefix, qname, plen)
3977 && string::xml_strcmp((*cur).name, local) == 0
3978 {
3979 return 1;
3980 }
3981 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3982 && !(*cur).c1.is_null()
3983 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3984 {
3985 if !(*(*cur).c1).prefix.is_null()
3986 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3987 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3988 {
3989 return 1;
3990 }
3991 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3992 || (*cur).c1.is_null()
3993 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3994 {
3995 vctxt_error(
3996 ctxt,
3997 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3998 );
3999 break;
4000 }
4001 cur = (*cur).c2;
4002 }
4003 }
4004 0
4005 }
4006}
4007
4008unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
4018 unsafe {
4019 let p = string::xmlstr_to_bytes(prefix);
4020 let q = string::xmlstr_to_bytes(qname);
4021 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
4022 }
4023}
4024
4025#[derive(Debug)]
4034#[repr(C)]
4035pub struct ContentModelNfa {
4036 transitions: Vec<(u32, *const xmlChar, u32)>,
4038 start: u32,
4040 accept: Vec<u32>,
4042}
4043
4044#[derive(Debug)]
4046#[repr(C)]
4047pub struct ContentModelExec {
4048 nfa: *mut ContentModelNfa,
4050 current: Vec<u32>,
4052}
4053
4054struct NfaBuilder {
4056 transitions: Vec<(u32, *const xmlChar, u32)>,
4057 n_states: u32,
4058}
4059
4060impl NfaBuilder {
4061 const fn new() -> Self {
4062 NfaBuilder {
4063 transitions: Vec::new(),
4064 n_states: 0,
4065 }
4066 }
4067 const fn new_state(&mut self) -> u32 {
4068 let s = self.n_states;
4069 self.n_states += 1;
4070 s
4071 }
4072 fn eps(&mut self, from: u32, to: u32) {
4073 self.transitions.push((from, ptr::null(), to));
4074 }
4075 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
4076 self.transitions.push((from, name, to));
4077 }
4078}
4079
4080unsafe fn compile_content_sub(
4093 b: &mut NfaBuilder,
4094 model: *mut _xmlElementContent,
4095) -> (u32, Vec<u32>) {
4096 if model.is_null() {
4097 let s = b.new_state();
4098 return (s, vec![s]);
4099 }
4100 let m = unsafe { &*model };
4101 let (mut in_s, outs) = match m.type_ as u32 {
4102 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
4103 let s = b.new_state();
4104 let to = b.new_state();
4105 b.name_trans(s, m.name, to);
4106 (s, vec![to])
4107 }
4108 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
4109 let (in1, out1) = compile_content_sub(b, m.c1);
4110 let (in2, out2) = compile_content_sub(b, m.c2);
4111 for &o in &out1 {
4112 b.eps(o, in2);
4113 }
4114 (in1, out2)
4115 }
4116 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
4117 let (in1, out1) = compile_content_sub(b, m.c1);
4118 let (in2, out2) = compile_content_sub(b, m.c2);
4119 let s = b.new_state();
4120 b.eps(s, in1);
4121 b.eps(s, in2);
4122 let mut all = out1;
4123 all.extend(out2);
4124 (s, all)
4125 }
4126 _ => {
4131 let s = b.new_state();
4132 (s, vec![s])
4133 }
4134 };
4135 match m.ocur as u32 {
4136 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
4137 let s = b.new_state();
4138 b.eps(s, in_s);
4139 for &o2 in &outs {
4140 b.eps(s, o2);
4141 }
4142 in_s = s;
4143 }
4144 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
4145 let s = b.new_state();
4146 b.eps(s, in_s);
4147 for &o2 in &outs {
4148 b.eps(s, o2);
4149 b.eps(o2, s);
4150 }
4151 in_s = s;
4152 }
4153 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
4154 let s = b.new_state();
4155 b.eps(s, in_s);
4156 for &o2 in &outs {
4157 b.eps(o2, s);
4158 }
4159 in_s = s;
4160 }
4161 _ => {}
4162 }
4163 (in_s, outs)
4164}
4165
4166unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
4168 if model.is_null() {
4169 return false;
4170 }
4171 unsafe {
4172 let m = &*model;
4173 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
4174 return true;
4175 }
4176 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
4177 }
4178}
4179
4180unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
4186 unsafe {
4187 if content.is_null() {
4188 return ptr::null_mut();
4189 }
4190 let mut b = NfaBuilder::new();
4191 let (start, outs) = compile_content_sub(&mut b, content);
4192 let nfa = Box::new(ContentModelNfa {
4193 transitions: b.transitions,
4194 start,
4195 accept: outs,
4196 });
4197 Box::into_raw(nfa)
4198 }
4199}
4200
4201pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
4207 if nfa.is_null() {
4208 return;
4209 }
4210 unsafe {
4211 ptr::drop_in_place(nfa);
4212 allocator::xmlFreeImpl(nfa as *mut c_void);
4213 }
4214}
4215
4216unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4218 let mut out = states.to_vec();
4219 let mut stack = states.to_vec();
4220 while let Some(s) = stack.pop() {
4221 for &(from, name, to) in &nfa.transitions {
4222 if from == s && name.is_null() && !out.contains(&to) {
4223 out.push(to);
4224 stack.push(to);
4225 }
4226 }
4227 }
4228 out.sort_unstable();
4229 out.dedup();
4230 out
4231}
4232
4233unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4241 unsafe {
4242 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4243 if exec.is_null() {
4244 return ptr::null_mut();
4245 }
4246 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4247 ptr::write(&mut (*exec).nfa, nfa);
4248 ptr::write(&mut (*exec).current, cur);
4249 exec
4250 }
4251}
4252
4253unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4262 if exec.is_null() {
4263 return;
4264 }
4265 unsafe {
4266 ptr::drop_in_place(&mut (*exec).current);
4267 allocator::xmlFreeImpl(exec as *mut c_void);
4268 }
4269}
4270
4271unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4283 unsafe {
4284 if exec.is_null() {
4285 return -1;
4286 }
4287 let nfa = &*(*exec).nfa;
4288 if value.is_null() {
4289 let cur = eps_closure(nfa, &(*exec).current);
4290 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4291 1
4292 } else {
4293 0
4294 };
4295 }
4296 let mut next: Vec<u32> = Vec::new();
4297 for &s in &(*exec).current {
4298 for &(from, name, to) in &nfa.transitions {
4299 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4300 next.push(to);
4301 }
4302 }
4303 }
4304 next.sort_unstable();
4305 next.dedup();
4306 if next.is_empty() {
4307 return -1;
4308 }
4309 let closed = eps_closure(nfa, &next);
4310 (*exec).current = closed;
4311 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4312 1
4313 } else {
4314 0
4315 }
4316 }
4317}
4318
4319unsafe fn vstate_vpush(
4330 ctxt: *mut _xmlValidCtxt,
4331 elem_decl: *mut _xmlElement,
4332 node: *mut _xmlNode,
4333) -> c_int {
4334 unsafe {
4335 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4336 let new_max = if (*ctxt).vstateMax == 0 {
4337 10
4338 } else {
4339 (*ctxt).vstateMax * 2
4340 };
4341 let new_tab = allocator::xmlReallocImpl(
4342 (*ctxt).vstateTab,
4343 (new_max as usize) * size_of::<ValidState>(),
4344 ) as *mut ValidState;
4345 if new_tab.is_null() {
4346 vctxt_error(
4347 ctxt,
4348 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4349 );
4350 return -1;
4351 }
4352 (*ctxt).vstateTab = new_tab as *mut c_void;
4353 (*ctxt).vstateMax = new_max;
4354 }
4355 let idx = (*ctxt).vstateNr as usize;
4356 let tab = (*ctxt).vstateTab as *mut ValidState;
4357 (*tab.add(idx)).elem_decl = elem_decl;
4358 (*tab.add(idx)).node = node;
4359 (*tab.add(idx)).exec = ptr::null_mut();
4360 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4361 if (*elem_decl).cont_model.is_null() {
4362 validate_build_content_model(ctxt, elem_decl);
4363 }
4364 if !(*elem_decl).cont_model.is_null() {
4365 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4366 if exec.is_null() {
4367 vctxt_error(
4368 ctxt,
4369 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4370 );
4371 return -1;
4372 }
4373 (*tab.add(idx)).exec = exec;
4374 } else {
4375 let msg = format!(
4376 "Failed to build content model regexp for {}\0",
4377 string::xmlstr_to_string((*elem_decl).name)
4378 );
4379 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4380 }
4381 }
4382 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4383 (*ctxt).vstateNr += 1;
4384 0
4385 }
4386}
4387
4388unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4397 unsafe {
4398 if (*ctxt).vstateNr < 1 {
4399 return -1;
4400 }
4401 (*ctxt).vstateNr -= 1;
4402 let idx = (*ctxt).vstateNr as usize;
4403 let tab = (*ctxt).vstateTab as *mut ValidState;
4404 let elem_decl = (*tab.add(idx)).elem_decl;
4405 (*tab.add(idx)).elem_decl = ptr::null_mut();
4406 (*tab.add(idx)).node = ptr::null_mut();
4407 if !elem_decl.is_null()
4408 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4409 && !(*tab.add(idx)).exec.is_null()
4410 {
4411 free_content_exec((*tab.add(idx)).exec);
4412 }
4413 (*tab.add(idx)).exec = ptr::null_mut();
4414 if (*ctxt).vstateNr >= 1 {
4415 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4416 } else {
4417 (*ctxt).vstate = ptr::null_mut();
4418 }
4419 0
4420 }
4421}
4422
4423pub unsafe fn validate_build_content_model(
4431 ctxt: *mut _xmlValidCtxt,
4432 elem: *mut _xmlElement,
4433) -> c_int {
4434 unsafe {
4435 if ctxt.is_null() {
4436 return 0;
4437 }
4438 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4439 return 0;
4440 }
4441 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4442 return 1;
4443 }
4444 if !(*elem).cont_model.is_null() {
4445 return 1;
4446 }
4447 if (*elem).content.is_null() {
4448 return 1;
4449 }
4450 if content_has_pcdata((*elem).content) {
4451 let msg = format!(
4452 "Found PCDATA in content model of {}\0",
4453 string::xmlstr_to_string((*elem).name)
4454 );
4455 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4456 return 0;
4457 }
4458 let nfa = build_content_nfa((*elem).content);
4459 if nfa.is_null() {
4460 vctxt_error(
4461 ctxt,
4462 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4463 as *const c_char,
4464 );
4465 return 0;
4466 }
4467 (*elem).cont_model = nfa as *mut c_void;
4468 1
4469 }
4470}
4471
4472pub unsafe fn validate_push_element(
4480 ctxt: *mut _xmlValidCtxt,
4481 doc: *mut _xmlDoc,
4482 elem: *mut _xmlNode,
4483 qname: *const xmlChar,
4484) -> c_int {
4485 unsafe {
4486 let mut ret = 1;
4487 if ctxt.is_null() {
4488 return 0;
4489 }
4490 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4491 let state = (*ctxt).vstate as *mut ValidState;
4492 let elem_decl = (*state).elem_decl;
4493 if !elem_decl.is_null() {
4494 match (*elem_decl).etype as u32 {
4495 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4496 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4497 let msg = format!(
4498 "Element {} was declared EMPTY this one has content\0",
4499 string::xmlstr_to_string((*(*state).node).name)
4500 );
4501 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4502 ret = 0;
4503 }
4504 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4505 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4506 if !(*elem_decl).content.is_null()
4507 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4508 {
4509 let msg = format!(
4510 "Element {} was declared #PCDATA but contains non text nodes\0",
4511 string::xmlstr_to_string((*(*state).node).name)
4512 );
4513 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4514 ret = 0;
4515 } else {
4516 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4517 if ret != 1 {
4518 let msg = format!(
4519 "Element {} is not declared in {} list of possible children\0",
4520 string::xmlstr_to_string(qname),
4521 string::xmlstr_to_string((*(*state).node).name)
4522 );
4523 vctxt_error_node(
4524 ctxt,
4525 (*state).node,
4526 msg.as_ptr() as *const c_char,
4527 );
4528 }
4529 }
4530 }
4531 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 && !(*state).exec.is_null() => {
4532 ret = content_exec_push((*state).exec, qname);
4533 if ret < 0 {
4534 let msg = format!(
4535 "Element {} content does not follow the DTD, Misplaced {}\0",
4536 string::xmlstr_to_string((*(*state).node).name),
4537 string::xmlstr_to_string(qname)
4538 );
4539 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4540 ret = 0;
4541 } else {
4542 ret = 1;
4543 }
4544 }
4545 _ => {}
4546 }
4547 }
4548 }
4549 let mut extsubset = 0;
4550 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4551 let _ = vstate_vpush(ctxt, e_decl, elem);
4553 ret
4554 }
4555}
4556
4557pub unsafe fn validate_push_cdata(
4564 ctxt: *mut _xmlValidCtxt,
4565 data: *const xmlChar,
4566 len: c_int,
4567) -> c_int {
4568 unsafe {
4569 let mut ret = 1;
4570 if ctxt.is_null() {
4571 return 0;
4572 }
4573 if len <= 0 {
4574 return 1;
4575 }
4576 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4577 let state = (*ctxt).vstate as *mut ValidState;
4578 let elem_decl = (*state).elem_decl;
4579 if !elem_decl.is_null() {
4580 match (*elem_decl).etype as u32 {
4581 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4582 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4583 let msg = format!(
4584 "Element {} was declared EMPTY this one has content\0",
4585 string::xmlstr_to_string((*(*state).node).name)
4586 );
4587 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4588 ret = 0;
4589 }
4590 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4591 }
4592 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4593 let bytes = core::slice::from_raw_parts(data, len as usize);
4594 for &b in bytes {
4595 if !is_blank_byte(b) {
4596 let msg = format!(
4597 "Element {} content does not follow the DTD, Text not allowed\0",
4598 string::xmlstr_to_string((*(*state).node).name)
4599 );
4600 vctxt_error_node(
4601 ctxt,
4602 (*state).node,
4603 msg.as_ptr() as *const c_char,
4604 );
4605 ret = 0;
4606 break;
4607 }
4608 }
4609 }
4610 _ => {}
4611 }
4612 }
4613 }
4614 ret
4615 }
4616}
4617
4618pub unsafe fn validate_pop_element(
4625 ctxt: *mut _xmlValidCtxt,
4626 _doc: *mut _xmlDoc,
4627 _elem: *mut _xmlNode,
4628 _qname: *const xmlChar,
4629) -> c_int {
4630 unsafe {
4631 let mut ret = 1;
4632 if ctxt.is_null() {
4633 return 0;
4634 }
4635 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4636 let state = (*ctxt).vstate as *mut ValidState;
4637 let elem_decl = (*state).elem_decl;
4638 if !elem_decl.is_null()
4639 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4640 && !(*state).exec.is_null()
4641 {
4642 ret = content_exec_push((*state).exec, ptr::null());
4643 if ret <= 0 {
4644 let msg = format!(
4645 "Element {} content does not follow the DTD, Expecting more children\0",
4646 string::xmlstr_to_string((*(*state).node).name)
4647 );
4648 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4649 ret = 0;
4650 } else {
4651 ret = 1;
4652 }
4653 }
4654 let _ = vstate_vpop(ctxt);
4655 }
4656 ret
4657 }
4658}
4659
4660#[cfg(test)]
4665mod tests {
4666 use super::*;
4667 use crate::abi::allocator;
4668
4669 use crate::xml::dtd;
4670 use crate::xml::tree;
4671
4672 unsafe fn c_str(s: &str) -> *const xmlChar {
4676 let bytes = s.as_bytes();
4677 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4678 assert!(!ptr.is_null());
4679 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4680 *ptr.add(bytes.len()) = 0;
4681 ptr
4682 }
4683
4684 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4686 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4687 assert!(!doc.is_null());
4688
4689 let name = c_str("root");
4690 let ext_id = c_str("--//Test//DTD//EN");
4691 let sys_id = c_str("test.dtd");
4692 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4693 assert!(!dtd.is_null());
4694
4695 (doc, dtd)
4696 }
4697
4698 #[allow(unused)]
4700 unsafe fn add_elem_decl(
4701 dtd: *mut _xmlDtd,
4702 name: *const xmlChar,
4703 elem_type: c_int,
4704 content: *mut _xmlElementContent,
4705 ) -> *mut _xmlElement {
4706 dtd::add_element_decl(dtd, name, elem_type, content)
4707 }
4708
4709 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4711 let node = tree::new_node(ptr::null_mut(), name);
4712 assert!(!node.is_null());
4713 tree::add_child(doc as *mut _xmlNode, node);
4714 node
4715 }
4716
4717 #[allow(unused)]
4719 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4720 let node = tree::new_node(ptr::null_mut(), name);
4721 assert!(!node.is_null());
4722 tree::add_child(parent, node);
4723 node
4724 }
4725
4726 #[test]
4736 fn test_validate_name_null() {
4737 unsafe {
4738 assert_eq!(validate_name(ptr::null()), 0);
4739 }
4740 }
4741
4742 #[test]
4750 fn test_validate_name_empty() {
4751 unsafe {
4752 let s = b"\0" as *const u8 as *const xmlChar;
4753 assert_eq!(validate_name(s), 0);
4754 }
4755 }
4756
4757 #[test]
4765 fn test_validate_name_valid() {
4766 unsafe {
4767 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4768 for t in &tests {
4769 let s = c_str(t);
4770 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4771 allocator::xmlFreeImpl(s as *mut c_void);
4772 }
4773 }
4774 }
4775
4776 #[test]
4784 fn test_validate_name_invalid() {
4785 unsafe {
4786 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4787 for t in &tests {
4788 let s = c_str(t);
4789 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4790 allocator::xmlFreeImpl(s as *mut c_void);
4791 }
4792 }
4793 }
4794
4795 #[test]
4803 fn test_validate_names_valid() {
4804 unsafe {
4805 let s = c_str("foo bar baz");
4806 assert_eq!(validate_names(s), 1);
4807 allocator::xmlFreeImpl(s as *mut c_void);
4808 }
4809 }
4810
4811 #[test]
4819 fn test_validate_names_invalid() {
4820 unsafe {
4821 let s = c_str("foo 123bar baz");
4822 assert_eq!(validate_names(s), 0);
4823 allocator::xmlFreeImpl(s as *mut c_void);
4824 }
4825 }
4826
4827 #[test]
4836 fn test_validate_nmtoken_null() {
4837 unsafe {
4838 assert_eq!(validate_nmtoken(ptr::null()), 0);
4839 }
4840 }
4841
4842 #[test]
4850 fn test_validate_nmtoken_valid() {
4851 unsafe {
4852 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4853 for t in &tests {
4854 let s = c_str(t);
4855 assert_eq!(
4856 validate_nmtoken(s),
4857 1,
4858 "Expected '{}' to be a valid NMTOKEN",
4859 t
4860 );
4861 allocator::xmlFreeImpl(s as *mut c_void);
4862 }
4863 }
4864 }
4865
4866 #[test]
4874 fn test_validate_nmtoken_invalid() {
4875 unsafe {
4876 let s = c_str("foo bar");
4877 assert_eq!(validate_nmtoken(s), 0);
4878 allocator::xmlFreeImpl(s as *mut c_void);
4879 }
4880 }
4881
4882 #[test]
4890 fn test_validate_nmtokens_valid() {
4891 unsafe {
4892 let s = c_str("foo 123bar -baz");
4893 assert_eq!(validate_nmtokens(s), 1);
4894 allocator::xmlFreeImpl(s as *mut c_void);
4895 }
4896 }
4897
4898 #[test]
4909 fn test_validate_attribute_value_cdata() {
4910 unsafe {
4911 let s = c_str("anything goes here!@#$%^&*()");
4912 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4913 allocator::xmlFreeImpl(s as *mut c_void);
4914
4915 let empty = b"\0" as *const u8 as *const xmlChar;
4917 assert_eq!(
4918 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4919 1
4920 );
4921 }
4922 }
4923
4924 #[test]
4932 fn test_validate_attribute_value_id() {
4933 unsafe {
4934 let valid = c_str("myId");
4935 assert_eq!(
4936 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4937 1
4938 );
4939 allocator::xmlFreeImpl(valid as *mut c_void);
4940
4941 let invalid = c_str("123id");
4942 assert_eq!(
4943 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4944 0
4945 );
4946 allocator::xmlFreeImpl(invalid as *mut c_void);
4947 }
4948 }
4949
4950 #[test]
4957 fn test_validate_attribute_value_idref() {
4958 unsafe {
4959 let valid = c_str("someId");
4960 assert_eq!(
4961 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4962 1
4963 );
4964 allocator::xmlFreeImpl(valid as *mut c_void);
4965 }
4966 }
4967
4968 #[test]
4976 fn test_validate_attribute_value_idrefs() {
4977 unsafe {
4978 let valid = c_str("id1 id2 id3");
4979 assert_eq!(
4980 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4981 1
4982 );
4983 allocator::xmlFreeImpl(valid as *mut c_void);
4984
4985 let invalid = c_str("id1 123id");
4986 assert_eq!(
4987 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4988 0
4989 );
4990 allocator::xmlFreeImpl(invalid as *mut c_void);
4991 }
4992 }
4993
4994 #[test]
5001 fn test_validate_attribute_value_entity() {
5002 unsafe {
5003 let valid = c_str("myEntity");
5004 assert_eq!(
5005 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
5006 1
5007 );
5008 allocator::xmlFreeImpl(valid as *mut c_void);
5009 }
5010 }
5011
5012 #[test]
5021 fn test_validate_attribute_value_nmtoken() {
5022 unsafe {
5023 let valid = c_str("123abc");
5024 assert_eq!(
5025 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
5026 1
5027 );
5028 allocator::xmlFreeImpl(valid as *mut c_void);
5029
5030 let invalid = c_str("foo bar");
5031 assert_eq!(
5032 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
5033 0
5034 );
5035 allocator::xmlFreeImpl(invalid as *mut c_void);
5036 }
5037 }
5038
5039 #[test]
5047 fn test_validate_attribute_value_null() {
5048 unsafe {
5049 assert_eq!(
5053 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
5054 1
5055 );
5056 assert_eq!(
5057 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
5058 0
5059 );
5060 }
5061 }
5062
5063 #[test]
5075 fn test_validate_enumeration_valid() {
5076 unsafe {
5077 let ctxt = new_valid_ctxt();
5078 assert!(!ctxt.is_null());
5079
5080 let red = c_str("red");
5081 let green = c_str("green");
5082 let blue = c_str("blue");
5083
5084 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
5085 (*e3).name = string::xml_strdup(blue);
5086 (*e3).next = ptr::null_mut();
5087
5088 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
5089 (*e2).name = string::xml_strdup(green);
5090 (*e2).next = e3;
5091
5092 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
5093 (*e1).name = string::xml_strdup(red);
5094 (*e1).next = e2;
5095
5096 let value = c_str("green");
5097 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
5098 assert_eq!((*ctxt).valid, 1);
5099
5100 allocator::xmlFreeImpl(value as *mut c_void);
5101 allocator::xmlFreeImpl(red as *mut c_void);
5102 allocator::xmlFreeImpl(green as *mut c_void);
5103 allocator::xmlFreeImpl(blue as *mut c_void);
5104 free_valid_ctxt(ctxt);
5105 }
5106 }
5107
5108 #[test]
5117 fn test_validate_enumeration_invalid() {
5118 unsafe {
5119 let ctxt = new_valid_ctxt();
5120 assert!(!ctxt.is_null());
5121
5122 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
5123 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
5124 (*e1).next = ptr::null_mut();
5125
5126 let value = c_str("yellow");
5127 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
5128
5129 allocator::xmlFreeImpl(value as *mut c_void);
5130 free_valid_ctxt(ctxt);
5131 }
5132 }
5133
5134 #[test]
5145 fn test_validate_notation_use_valid() {
5146 unsafe {
5147 let (doc, dtd) = make_test_doc();
5148
5149 let notation_name = c_str("GIF");
5150 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
5151
5152 let ctxt = new_valid_ctxt();
5153 assert!(!ctxt.is_null());
5154
5155 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
5156
5157 free_valid_ctxt(ctxt);
5158 tree::free_doc(doc);
5159 }
5160 }
5161
5162 #[test]
5171 fn test_validate_notation_use_invalid() {
5172 unsafe {
5173 let (doc, _dtd) = make_test_doc();
5174
5175 let ctxt = new_valid_ctxt();
5176 assert!(!ctxt.is_null());
5177
5178 let notation_name = c_str("UNDECLARED");
5179 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
5180
5181 free_valid_ctxt(ctxt);
5182 allocator::xmlFreeImpl(notation_name as *mut c_void);
5183 tree::free_doc(doc);
5184 }
5185 }
5186
5187 #[test]
5198 fn test_new_free_valid_ctxt() {
5199 unsafe {
5200 let ctxt = new_valid_ctxt();
5201 assert!(!ctxt.is_null());
5202 assert_eq!((*ctxt).valid, 1);
5203 assert!((*ctxt).node.is_null());
5204 free_valid_ctxt(ctxt);
5205 }
5206 }
5207
5208 #[test]
5215 fn test_free_valid_ctxt_null() {
5216 unsafe {
5217 free_valid_ctxt(ptr::null_mut());
5218 }
5219 }
5220
5221 #[test]
5230 fn test_set_valid_errors_null() {
5231 unsafe {
5232 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
5233 }
5234 }
5235
5236 #[test]
5247 fn test_validate_element_no_dtd() {
5248 unsafe {
5249 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5250 assert!(!doc.is_null());
5251
5252 let root_name = c_str("root");
5253 let root = create_root_elem(doc, root_name);
5254
5255 let ctxt = new_valid_ctxt();
5256 assert!(!ctxt.is_null());
5257
5258 assert_eq!(validate_element(ctxt, doc, root), 1);
5260
5261 free_valid_ctxt(ctxt);
5262 tree::free_doc(doc);
5263 }
5264 }
5265
5266 #[test]
5274 fn test_validate_element_empty_valid() {
5275 unsafe {
5276 let (doc, dtd) = make_test_doc();
5277
5278 let root_name = c_str("root");
5279 add_elem_decl(
5280 dtd,
5281 root_name,
5282 XML_ELEMENT_TYPE_EMPTY as c_int,
5283 ptr::null_mut(),
5284 );
5285
5286 let root = create_root_elem(doc, root_name);
5287
5288 let ctxt = new_valid_ctxt();
5289 assert!(!ctxt.is_null());
5290
5291 assert_eq!(validate_element(ctxt, doc, root), 1);
5292
5293 free_valid_ctxt(ctxt);
5294 tree::free_doc(doc);
5295 }
5296 }
5297
5298 #[test]
5306 fn test_validate_element_undeclared() {
5307 unsafe {
5308 let (doc, _dtd) = make_test_doc();
5309
5310 let root_name = c_str("root");
5311 let root = create_root_elem(doc, root_name);
5312
5313 let ctxt = new_valid_ctxt();
5314 assert!(!ctxt.is_null());
5315
5316 assert_eq!(validate_element(ctxt, doc, root), 0);
5318
5319 free_valid_ctxt(ctxt);
5320 tree::free_doc(doc);
5321 }
5322 }
5323
5324 #[test]
5334 fn test_validate_element_with_content() {
5335 unsafe {
5336 let (doc, dtd) = make_test_doc();
5337
5338 let root_name = c_str("root");
5340 let child_name = c_str("child");
5341
5342 let child_content =
5344 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5345 assert!(!child_content.is_null());
5346 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
5347
5348 add_elem_decl(
5349 dtd,
5350 root_name,
5351 XML_ELEMENT_TYPE_ELEMENT as c_int,
5352 child_content,
5353 );
5354 add_elem_decl(
5355 dtd,
5356 child_name,
5357 XML_ELEMENT_TYPE_EMPTY as c_int,
5358 ptr::null_mut(),
5359 );
5360
5361 let root = create_root_elem(doc, root_name);
5362 let _child = create_child_elem(root, child_name);
5363
5364 let ctxt = new_valid_ctxt();
5365 assert!(!ctxt.is_null());
5366
5367 assert_eq!(validate_element(ctxt, doc, root), 1);
5368
5369 free_valid_ctxt(ctxt);
5370 tree::free_doc(doc);
5371 }
5372 }
5373
5374 #[test]
5383 fn test_validate_element_invalid_content() {
5384 unsafe {
5385 let (doc, dtd) = make_test_doc();
5386
5387 let root_name = c_str("root");
5388 let child_name = c_str("child");
5389 let wrong_name = c_str("wrong");
5390
5391 let child_content =
5393 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5394 assert!(!child_content.is_null());
5395 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
5396
5397 add_elem_decl(
5398 dtd,
5399 root_name,
5400 XML_ELEMENT_TYPE_ELEMENT as c_int,
5401 child_content,
5402 );
5403 add_elem_decl(
5404 dtd,
5405 child_name,
5406 XML_ELEMENT_TYPE_EMPTY as c_int,
5407 ptr::null_mut(),
5408 );
5409 add_elem_decl(
5410 dtd,
5411 wrong_name,
5412 XML_ELEMENT_TYPE_EMPTY as c_int,
5413 ptr::null_mut(),
5414 );
5415
5416 let root = create_root_elem(doc, root_name);
5417 create_child_elem(root, wrong_name);
5419
5420 let ctxt = new_valid_ctxt();
5421 assert!(!ctxt.is_null());
5422
5423 assert_eq!(validate_element(ctxt, doc, root), 0);
5424
5425 free_valid_ctxt(ctxt);
5426 tree::free_doc(doc);
5427 }
5428 }
5429
5430 #[test]
5440 fn test_validate_root_match() {
5441 unsafe {
5442 let (doc, dtd) = make_test_doc();
5443
5444 let root_name = c_str("root");
5445 add_elem_decl(
5446 dtd,
5447 root_name,
5448 XML_ELEMENT_TYPE_EMPTY as c_int,
5449 ptr::null_mut(),
5450 );
5451 create_root_elem(doc, root_name);
5452
5453 let ctxt = new_valid_ctxt();
5454 assert!(!ctxt.is_null());
5455
5456 assert_eq!(validate_root(ctxt, doc), 1);
5457
5458 free_valid_ctxt(ctxt);
5459 tree::free_doc(doc);
5460 }
5461 }
5462
5463 #[test]
5471 fn test_validate_root_no_dtd() {
5472 unsafe {
5473 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5474 assert!(!doc.is_null());
5475
5476 let root_name = c_str("root");
5477 create_root_elem(doc, root_name);
5478
5479 let ctxt = new_valid_ctxt();
5480 assert!(!ctxt.is_null());
5481
5482 assert_eq!(validate_root(ctxt, doc), 1);
5484
5485 free_valid_ctxt(ctxt);
5486 tree::free_doc(doc);
5487 }
5488 }
5489
5490 #[test]
5500 fn test_validate_document_valid() {
5501 unsafe {
5502 let (doc, dtd) = make_test_doc();
5503
5504 let root_name = c_str("root");
5505 add_elem_decl(
5506 dtd,
5507 root_name,
5508 XML_ELEMENT_TYPE_EMPTY as c_int,
5509 ptr::null_mut(),
5510 );
5511 create_root_elem(doc, root_name);
5512
5513 let ctxt = new_valid_ctxt();
5514 assert!(!ctxt.is_null());
5515
5516 assert_eq!(validate_document(ctxt, doc), 1);
5517
5518 free_valid_ctxt(ctxt);
5519 tree::free_doc(doc);
5520 }
5521 }
5522
5523 #[test]
5531 fn test_validate_document_no_root() {
5532 unsafe {
5533 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5534 assert!(!doc.is_null());
5535
5536 let ctxt = new_valid_ctxt();
5537 assert!(!ctxt.is_null());
5538
5539 assert_eq!(validate_document(ctxt, doc), 0);
5540
5541 free_valid_ctxt(ctxt);
5542 tree::free_doc(doc);
5543 }
5544 }
5545
5546 #[test]
5557 fn test_validate_content_valid() {
5558 unsafe {
5559 let (doc, dtd) = make_test_doc();
5560
5561 let root_name = c_str("root");
5562 let child_name = c_str("child");
5563
5564 let child_content =
5565 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5566 assert!(!child_content.is_null());
5567
5568 add_elem_decl(
5569 dtd,
5570 root_name,
5571 XML_ELEMENT_TYPE_ELEMENT as c_int,
5572 child_content,
5573 );
5574 add_elem_decl(
5575 dtd,
5576 child_name,
5577 XML_ELEMENT_TYPE_EMPTY as c_int,
5578 ptr::null_mut(),
5579 );
5580
5581 let root = create_root_elem(doc, root_name);
5582 create_child_elem(root, child_name);
5583
5584 let ctxt = new_valid_ctxt();
5585 assert!(!ctxt.is_null());
5586
5587 assert_eq!(validate_content(ctxt, root, doc), 1);
5588
5589 free_valid_ctxt(ctxt);
5590 tree::free_doc(doc);
5591 }
5592 }
5593
5594 #[test]
5604 fn test_is_mixed_element() {
5605 unsafe {
5606 let (doc, dtd) = make_test_doc();
5607 let name = c_str("mixedElem");
5608 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5609
5610 assert_eq!(is_mixed_element(doc, name), 1);
5611
5612 let other = c_str("other");
5613 assert_eq!(is_mixed_element(doc, other), 0);
5614
5615 allocator::xmlFreeImpl(other as *mut c_void);
5616 tree::free_doc(doc);
5617 }
5618 }
5619
5620 #[test]
5628 fn test_is_empty_element() {
5629 unsafe {
5630 let (doc, dtd) = make_test_doc();
5631 let name = c_str("emptyElem");
5632 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5633
5634 assert_eq!(is_empty_element(doc, name), 1);
5635
5636 let other = c_str("other");
5637 assert_eq!(is_empty_element(doc, other), 0);
5638
5639 allocator::xmlFreeImpl(other as *mut c_void);
5640 tree::free_doc(doc);
5641 }
5642 }
5643
5644 #[test]
5651 fn test_is_mixed_element_no_dtd() {
5652 unsafe {
5653 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5654 assert!(!doc.is_null());
5655
5656 let name = c_str("foo");
5657 assert_eq!(is_mixed_element(doc, name), 0);
5658
5659 allocator::xmlFreeImpl(name as *mut c_void);
5660 tree::free_doc(doc);
5661 }
5662 }
5663
5664 #[test]
5671 fn test_is_empty_element_no_dtd() {
5672 unsafe {
5673 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5674 assert!(!doc.is_null());
5675
5676 let name = c_str("foo");
5677 assert_eq!(is_empty_element(doc, name), 0);
5678
5679 allocator::xmlFreeImpl(name as *mut c_void);
5680 tree::free_doc(doc);
5681 }
5682 }
5683
5684 #[test]
5693 fn test_validate_dtd_null() {
5694 unsafe {
5695 let ctxt = new_valid_ctxt();
5696 assert!(!ctxt.is_null());
5697 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5698 free_valid_ctxt(ctxt);
5699 }
5700 }
5701
5702 #[test]
5712 fn test_validate_element_null() {
5713 unsafe {
5714 let (doc, _dtd) = make_test_doc();
5715 let ctxt = new_valid_ctxt();
5716 assert!(!ctxt.is_null());
5717
5718 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5719
5720 free_valid_ctxt(ctxt);
5721 tree::free_doc(doc);
5722 }
5723 }
5724
5725 #[test]
5733 fn test_validate_document_null() {
5734 unsafe {
5735 let ctxt = new_valid_ctxt();
5736 assert!(!ctxt.is_null());
5737
5738 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5739 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5740
5741 free_valid_ctxt(ctxt);
5742 }
5743 }
5744
5745 #[test]
5753 fn test_validate_document_final_null() {
5754 unsafe {
5755 let ctxt = new_valid_ctxt();
5756 assert!(!ctxt.is_null());
5757
5758 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5759 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5760
5761 free_valid_ctxt(ctxt);
5762 }
5763 }
5764
5765 #[test]
5772 fn test_validate_attribute_decl_null() {
5773 unsafe {
5774 let ctxt = new_valid_ctxt();
5775 assert!(!ctxt.is_null());
5776
5777 assert_eq!(
5778 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut()),
5779 0
5780 );
5781
5782 free_valid_ctxt(ctxt);
5783 }
5784 }
5785
5786 #[test]
5793 fn test_validate_content_null() {
5794 unsafe {
5795 let ctxt = new_valid_ctxt();
5796 assert!(!ctxt.is_null());
5797
5798 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5799
5800 free_valid_ctxt(ctxt);
5801 }
5802 }
5803
5804 #[test]
5811 fn test_validate_root_null() {
5812 unsafe {
5813 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5814 }
5815 }
5816
5817 #[test]
5824 fn test_validate_enumeration_null() {
5825 unsafe {
5826 let ctxt = new_valid_ctxt();
5827 assert!(!ctxt.is_null());
5828
5829 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5830
5831 free_valid_ctxt(ctxt);
5832 }
5833 }
5834
5835 #[test]
5842 fn test_validate_notation_use_null() {
5843 unsafe {
5844 let ctxt = new_valid_ctxt();
5845 assert!(!ctxt.is_null());
5846
5847 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5848
5849 free_valid_ctxt(ctxt);
5850 }
5851 }
5852
5853 #[test]
5861 fn test_validate_name_start_characters() {
5862 unsafe {
5863 let name = c_str("\u{C0}lph\u{E0}");
5865 assert_eq!(validate_name(name), 1);
5866 allocator::xmlFreeImpl(name as *mut c_void);
5867 }
5868 }
5869
5870 #[test]
5878 fn test_validate_names_single() {
5879 unsafe {
5880 let s = c_str("singleName");
5881 assert_eq!(validate_names(s), 1);
5882 allocator::xmlFreeImpl(s as *mut c_void);
5883 }
5884 }
5885
5886 #[test]
5894 fn test_validate_nmtokens_single() {
5895 unsafe {
5896 let s = c_str("123abc");
5897 assert_eq!(validate_nmtokens(s), 1);
5898 allocator::xmlFreeImpl(s as *mut c_void);
5899 }
5900 }
5901
5902 #[test]
5910 fn test_validate_nmtokens_invalid() {
5911 unsafe {
5912 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5915
5916 let s2 = c_str("foo@bar");
5918 assert_eq!(validate_nmtokens(s2), 0);
5919 allocator::xmlFreeImpl(s2 as *mut c_void);
5920 }
5921 }
5922
5923 #[test]
5931 fn test_validate_attribute_value_empty_non_cdata() {
5932 unsafe {
5933 let empty = b"\0" as *const u8 as *const xmlChar;
5934 assert_eq!(
5935 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5936 0
5937 );
5938 assert_eq!(
5939 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5940 0
5941 );
5942 assert_eq!(
5943 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5944 0
5945 );
5946 }
5947 }
5948
5949 #[test]
5956 fn test_validate_attribute_value_unknown_type() {
5957 unsafe {
5958 let s = c_str("test");
5961 assert_eq!(validate_attribute_value(999, s), 1);
5962 allocator::xmlFreeImpl(s as *mut c_void);
5963 }
5964 }
5965
5966 #[test]
5974 fn test_validate_element_any_content() {
5975 unsafe {
5976 let (doc, dtd) = make_test_doc();
5977
5978 let root_name = c_str("root");
5979 add_elem_decl(
5980 dtd,
5981 root_name,
5982 XML_ELEMENT_TYPE_ANY as c_int,
5983 ptr::null_mut(),
5984 );
5985
5986 let child_name = c_str("child");
5987 add_elem_decl(
5988 dtd,
5989 child_name,
5990 XML_ELEMENT_TYPE_EMPTY as c_int,
5991 ptr::null_mut(),
5992 );
5993
5994 let root = create_root_elem(doc, root_name);
5995 create_child_elem(root, child_name);
5996
5997 let ctxt = new_valid_ctxt();
5998 assert!(!ctxt.is_null());
5999
6000 assert_eq!(validate_element(ctxt, doc, root), 1);
6002
6003 free_valid_ctxt(ctxt);
6004 tree::free_doc(doc);
6005 }
6006 }
6007
6008 #[test]
6016 fn test_validate_element_empty_with_child() {
6017 unsafe {
6018 let (doc, dtd) = make_test_doc();
6019
6020 let root_name = c_str("root");
6021 add_elem_decl(
6022 dtd,
6023 root_name,
6024 XML_ELEMENT_TYPE_EMPTY as c_int,
6025 ptr::null_mut(),
6026 );
6027
6028 let child_name = c_str("child");
6029 add_elem_decl(
6030 dtd,
6031 child_name,
6032 XML_ELEMENT_TYPE_EMPTY as c_int,
6033 ptr::null_mut(),
6034 );
6035
6036 let root = create_root_elem(doc, root_name);
6037 create_child_elem(root, child_name);
6038
6039 let ctxt = new_valid_ctxt();
6040 assert!(!ctxt.is_null());
6041
6042 assert_eq!(validate_element(ctxt, doc, root), 0);
6044
6045 free_valid_ctxt(ctxt);
6046 tree::free_doc(doc);
6047 }
6048 }
6049
6050 #[test]
6058 fn test_validate_dtd_final_null() {
6059 unsafe {
6060 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
6061 }
6062 }
6063}