1use core::ffi::c_void;
29use core::ptr;
30use std::os::raw::{c_char, c_int, c_uint};
31
32use crate::abi::allocator;
33use crate::abi::callbacks::xmlGenericErrorFunc;
34use crate::abi::structs::*;
35use crate::abi::types::xmlAttributeDefault::*;
36use crate::abi::types::xmlAttributeType::*;
37use crate::abi::types::xmlElementContentOccur::*;
38use crate::abi::types::xmlElementContentType::*;
39use crate::abi::types::xmlElementType::*;
40use crate::abi::types::xmlElementTypeVal::*;
41use crate::abi::types::xmlEntityType::*;
42use crate::abi::types::*;
43use crate::xml::dtd;
44use crate::xml::hash;
45use crate::xml::string;
46use crate::xml::tree;
47
48#[allow(dead_code)]
54const VALID_CTXT_DEPTH_MAX: c_int = 256;
55
56pub unsafe fn new_valid_ctxt() -> *mut _xmlValidCtxt {
80 let ctxt = allocator::xmlMallocZero(size_of::<_xmlValidCtxt>() as usize) as *mut _xmlValidCtxt;
82 if ctxt.is_null() {
83 return ptr::null_mut();
84 }
85
86 unsafe {
87 (*ctxt).valid = 1;
88 (*ctxt).node = ptr::null_mut();
89 (*ctxt).doc = ptr::null_mut();
90 (*ctxt).nodeNr = 0;
91 (*ctxt).nodeMax = 0;
92 (*ctxt).nodeTab = ptr::null_mut();
93 (*ctxt).flags = 0;
94 (*ctxt).vstate = ptr::null_mut();
95 (*ctxt).vstateNr = 0;
96 (*ctxt).vstateMax = 0;
97 (*ctxt).vstateTab = ptr::null_mut();
98 (*ctxt).am = ptr::null_mut();
99 (*ctxt).state = ptr::null_mut();
100 (*ctxt).error = None;
101 (*ctxt).warning = None;
102 (*ctxt).userData = ptr::null_mut();
103 }
104
105 ctxt
106}
107
108pub unsafe fn free_valid_ctxt(ctxt: *mut _xmlValidCtxt) {
120 if ctxt.is_null() {
121 return;
122 }
123
124 unsafe {
125 let c = &mut *ctxt;
126
127 if !c.nodeTab.is_null() {
129 allocator::xmlFreeImpl(c.nodeTab as *mut c_void);
130 }
131
132 if !c.am.is_null() {
134 }
137
138 if !c.state.is_null() {
140 }
142
143 allocator::xmlFreeImpl(ctxt as *mut c_void);
144 }
145}
146
147pub unsafe fn set_valid_errors(
163 ctxt: *mut _xmlValidCtxt,
164 err: Option<xmlGenericErrorFunc>,
165 warn: Option<xmlGenericErrorFunc>,
166 data: *mut c_void,
167) {
168 if ctxt.is_null() {
169 return;
170 }
171
172 unsafe {
173 (*ctxt).error = err;
176 (*ctxt).warning = warn;
177 (*ctxt).userData = data;
178 }
179}
180
181unsafe fn vctxt_error(ctxt: *mut _xmlValidCtxt, msg: *const c_char) {
192 if ctxt.is_null() {
193 return;
194 }
195 unsafe {
196 let c = &mut *ctxt;
197 c.valid = 0;
198 if let Some(err) = c.error {
199 err(c.userData, msg);
200 }
201 }
202}
203
204unsafe fn vctxt_push_node(ctxt: *mut _xmlValidCtxt, node: *mut _xmlNode) -> c_int {
212 unsafe {
213 let c = &mut *ctxt;
214
215 if c.nodeNr >= c.nodeMax {
216 let new_max = if c.nodeMax == 0 { 4 } else { c.nodeMax * 2 };
217 let new_tab = allocator::xmlReallocImpl(
218 c.nodeTab as *mut c_void,
219 (new_max as usize) * size_of::<*mut _xmlNode>(),
220 ) as *mut *mut _xmlNode;
221 if new_tab.is_null() {
222 return -1;
223 }
224 c.nodeTab = new_tab;
225 c.nodeMax = new_max;
226 }
227
228 *c.nodeTab.add(c.nodeNr as usize) = node;
229 c.nodeNr += 1;
230 c.node = node;
231 }
232 0
233}
234
235unsafe fn vctxt_pop_node(ctxt: *mut _xmlValidCtxt) {
241 unsafe {
242 let c = &mut *ctxt;
243 if c.nodeNr > 0 {
244 c.nodeNr -= 1;
245 }
246 if c.nodeNr > 0 {
247 c.node = *c.nodeTab.add((c.nodeNr - 1) as usize);
248 } else {
249 c.node = ptr::null_mut();
250 }
251 }
252}
253
254unsafe fn get_valid_dtd(doc: *mut _xmlDoc) -> *mut _xmlDtd {
262 if doc.is_null() {
263 return ptr::null_mut();
264 }
265 unsafe {
266 let d = &*doc;
267 if !d.intSubset.is_null() {
268 d.intSubset
269 } else {
270 d.extSubset
271 }
272 }
273}
274
275pub(crate) const fn is_xml_name_start(c: char) -> bool {
289 matches!(c,
290 'a'..='z' | 'A'..='Z' | '_' | ':' |
291 '\u{C0}'..='\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' |
292 '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' |
293 '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' |
294 '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' |
295 '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' |
296 '\u{10000}'..='\u{EFFFF}'
297 )
298}
299
300pub(crate) const fn is_xml_name_char(c: char) -> bool {
307 is_xml_name_start(c)
308 || matches!(c,
309 '-' | '.' | '0'..='9' | '\u{B7}' |
310 '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}'
311 )
312}
313
314pub unsafe fn validate_name(value: *const xmlChar) -> c_int {
332 if value.is_null() {
333 return 0;
334 }
335
336 let s = unsafe { string::xmlstr_to_bytes(value) };
337 let s = core::str::from_utf8(s).unwrap_or("");
338
339 if s.is_empty() {
340 return 0;
341 }
342
343 let mut chars = s.chars();
344
345 match chars.next() {
347 Some(c) if is_xml_name_start(c) => {}
348 _ => return 0,
349 }
350
351 for c in chars {
353 if !is_xml_name_char(c) {
354 return 0;
355 }
356 }
357
358 1
359}
360
361pub unsafe fn validate_names(value: *const xmlChar) -> c_int {
375 if value.is_null() {
376 return 0;
377 }
378
379 let s = unsafe { string::xmlstr_to_bytes(value) };
380 let s = core::str::from_utf8(s).unwrap_or("");
381
382 if s.is_empty() {
383 return 0;
384 }
385
386 for token in s.split_whitespace() {
387 if token.is_empty() {
388 return 0;
389 }
390 let mut chars = token.chars();
391 match chars.next() {
392 Some(c) if is_xml_name_start(c) => {}
393 _ => return 0,
394 }
395 for c in chars {
396 if !is_xml_name_char(c) {
397 return 0;
398 }
399 }
400 }
401
402 1
403}
404
405pub unsafe fn validate_nmtoken(value: *const xmlChar) -> c_int {
424 if value.is_null() {
425 return 0;
426 }
427
428 let s = unsafe { string::xmlstr_to_bytes(value) };
429 let s = core::str::from_utf8(s).unwrap_or("");
430
431 if s.is_empty() {
432 return 0;
433 }
434
435 for c in s.chars() {
436 if !is_xml_name_char(c) {
437 return 0;
438 }
439 }
440
441 1
442}
443
444pub unsafe fn validate_nmtokens(value: *const xmlChar) -> c_int {
458 if value.is_null() {
459 return 0;
460 }
461
462 let s = unsafe { string::xmlstr_to_bytes(value) };
463 let s = core::str::from_utf8(s).unwrap_or("");
464
465 if s.is_empty() {
466 return 0;
467 }
468
469 for token in s.split_whitespace() {
470 if token.is_empty() {
471 return 0;
472 }
473 for c in token.chars() {
474 if !is_xml_name_char(c) {
475 return 0;
476 }
477 }
478 }
479
480 1
481}
482
483pub unsafe fn validate_attribute_value(atype: c_int, value: *const xmlChar) -> c_int {
501 match atype as u32 {
505 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
506 validate_values_internal(value, 0)
507 }
508 t if t == XML_ATTRIBUTE_ENTITY as u32
509 || t == XML_ATTRIBUTE_IDREF as u32
510 || t == XML_ATTRIBUTE_ID as u32
511 || t == XML_ATTRIBUTE_NOTATION as u32 =>
512 {
513 validate_value_internal(value, 0)
514 }
515 t if t == XML_ATTRIBUTE_NMTOKENS as u32 || t == XML_ATTRIBUTE_ENUMERATION as u32 => {
516 validate_values_internal(value, XML_SCAN_NMTOKEN)
517 }
518 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => validate_value_internal(value, XML_SCAN_NMTOKEN),
519 _ => 1, }
521}
522
523pub unsafe fn validate_enumeration(
545 ctxt: *mut _xmlValidCtxt,
546 value: *const xmlChar,
547 tree: *mut _xmlEnumeration,
548) -> c_int {
549 if value.is_null() || tree.is_null() {
550 return 0;
551 }
552
553 let mut cur = tree;
554 while !cur.is_null() {
555 unsafe {
556 if string::xml_strcmp(value, (*cur).name) == 0 {
557 return 1;
558 }
559 cur = (*cur).next;
560 }
561 }
562
563 unsafe {
565 let msg = string::xmlstr_to_string(value);
566 let err_msg = format!("Value '{}' is not a valid enumeration value\0", msg);
567 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
568 }
569 0
570}
571
572pub unsafe fn validate_notation_use(
592 ctxt: *mut _xmlValidCtxt,
593 doc: *mut _xmlDoc,
594 notation_name: *const xmlChar,
595) -> c_int {
596 if notation_name.is_null() {
597 return 0;
598 }
599
600 let dtd = unsafe { get_valid_dtd(doc) };
601 if dtd.is_null() {
602 unsafe {
603 vctxt_error(
604 ctxt,
605 b"No DTD available for notation validation\0" as *const u8 as *const c_char,
606 );
607 }
608 return 0;
609 }
610
611 unsafe {
613 let notations = (*dtd).notations;
614 if notations.is_null() {
615 vctxt_error(
616 ctxt,
617 b"No notations declared in DTD\0" as *const u8 as *const c_char,
618 );
619 return 0;
620 }
621
622 let notation = hash::hash_lookup(notations as *mut hash::HashTable, notation_name);
623 if notation.is_null() {
624 let msg = string::xmlstr_to_string(notation_name);
625 let err_msg = format!("Notation '{}' is not declared\0", msg);
626 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
627 return 0;
628 }
629 }
630
631 1
632}
633
634pub unsafe fn validate_id(
656 ctxt: *mut _xmlValidCtxt,
657 doc: *mut _xmlDoc,
658 node: *mut _xmlNode,
659 value: *const xmlChar,
660) -> c_int {
661 if value.is_null() || doc.is_null() {
662 return 0;
663 }
664
665 if unsafe { validate_name_value(value) } == 0 {
668 unsafe {
669 let msg = string::xmlstr_to_string(value);
670 let err_msg = format!("ID value '{}' is not a valid XML Name\0", msg);
671 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
672 }
673 return 0;
674 }
675
676 unsafe {
678 let doc_ref = &*doc;
679 if !doc_ref.ids.is_null() {
680 let existing = hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value);
681 if !existing.is_null() {
682 let msg = string::xmlstr_to_string(value);
683 let err_msg = format!("Duplicate ID value '{}'\0", msg);
684 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
685 return 0;
686 }
687 }
688 }
689
690 unsafe {
692 if (*doc).ids.is_null() {
693 (*doc).ids = hash::hash_create(16) as *mut c_void;
694 }
695 hash::hash_add_entry(
696 (*doc).ids as *mut hash::HashTable,
697 value,
698 node as *mut c_void,
699 );
700 }
701
702 1
703}
704
705pub unsafe fn validate_id_ref(
722 ctxt: *mut _xmlValidCtxt,
723 doc: *mut _xmlDoc,
724 _node: *mut _xmlNode,
725 value: *const xmlChar,
726) -> c_int {
727 if value.is_null() || doc.is_null() {
728 return 0;
729 }
730
731 if unsafe { validate_name_value(value) } == 0 {
734 unsafe {
735 let msg = string::xmlstr_to_string(value);
736 let err_msg = format!("IDREF value '{}' is not a valid XML Name\0", msg);
737 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
738 }
739 return 0;
740 }
741
742 unsafe {
744 let doc_ref = &*doc;
745 if doc_ref.ids.is_null()
746 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value).is_null()
747 {
748 let msg = string::xmlstr_to_string(value);
752 let err_msg = format!("IDREF '{}' references an unknown ID\0", msg);
753 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
754 return 0;
755 }
756 }
757
758 1
759}
760
761pub unsafe fn validate_id_refs(
778 ctxt: *mut _xmlValidCtxt,
779 doc: *mut _xmlDoc,
780 node: *mut _xmlNode,
781 value: *const xmlChar,
782) -> c_int {
783 if value.is_null() || doc.is_null() {
784 return 0;
785 }
786
787 let s = unsafe { string::xmlstr_to_bytes(value) };
788 let s = core::str::from_utf8(s).unwrap_or("");
789
790 if s.is_empty() {
791 return 0;
792 }
793
794 let mut valid = 1;
795 for token in s.split_whitespace() {
796 if token.is_empty() {
797 continue;
798 }
799 let token_ptr = unsafe { string::bytes_to_xmlstr(token.as_bytes()) };
801 if token_ptr.is_null() {
802 valid = 0;
803 break;
804 }
805 let result = unsafe { validate_id_ref(ctxt, doc, node, token_ptr) };
806 unsafe {
807 allocator::xmlFreeImpl(token_ptr as *mut c_void);
808 }
809 if result == 0 {
810 valid = 0;
811 }
812 }
813
814 valid
815}
816
817pub unsafe fn validate_attribute_decl(
844 ctxt: *mut _xmlValidCtxt,
845 doc: *mut _xmlDoc,
846 _elem: *mut _xmlNode,
847 attr: *mut _xmlAttribute,
848) -> c_int {
849 if attr.is_null() {
850 return 0;
851 }
852
853 unsafe {
854 let a = &*attr;
855 let atype = a.atype as c_int;
856
857 if !a.defaultValue.is_null() && validate_attribute_value(atype, a.defaultValue) == 0 {
859 let name_str = string::xmlstr_to_string(a.name);
860 let val_str = string::xmlstr_to_string(a.defaultValue);
861 let err_msg = format!(
862 "Default value '{}' for attribute '{}' is not valid for its type\0",
863 val_str, name_str
864 );
865 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
866 return 0;
867 }
868
869 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !a.tree.is_null() {
871 let mut cur = a.tree;
873 while !cur.is_null() {
874 if !(*cur).name.is_null() && validate_nmtoken_value((*cur).name) == 0 {
875 let val_str = string::xmlstr_to_string((*cur).name);
876 let err_msg =
877 format!("Enumeration value '{}' is not a valid NMTOKEN\0", val_str);
878 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
879 return 0;
880 }
881 cur = (*cur).next;
882 }
883 }
884
885 if atype == XML_ATTRIBUTE_NOTATION as c_int && !a.tree.is_null() {
887 let mut cur = a.tree;
888 while !cur.is_null() {
889 if !(*cur).name.is_null() && validate_notation_use(ctxt, doc, (*cur).name) == 0 {
890 let val_str = string::xmlstr_to_string((*cur).name);
891 let err_msg = format!(
892 "NOTATION value '{}' references undeclared notation\0",
893 val_str
894 );
895 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
896 return 0;
897 }
898 cur = (*cur).next;
899 }
900 }
901
902 1
903 }
904}
905
906pub unsafe fn validate_element(
935 ctxt: *mut _xmlValidCtxt,
936 doc: *mut _xmlDoc,
937 elem: *mut _xmlNode,
938) -> c_int {
939 if elem.is_null() || doc.is_null() || ctxt.is_null() {
940 return 0;
941 }
942
943 unsafe {
944 let e = &*elem;
945
946 if e.type_ != XML_ELEMENT_NODE as c_int {
948 return 1;
949 }
950
951 if vctxt_push_node(ctxt, elem) != 0 {
953 return 0;
954 }
955
956 let mut valid = 1;
957
958 let dtd = get_valid_dtd(doc);
960 if dtd.is_null() {
961 vctxt_pop_node(ctxt);
964 return 1;
965 }
966
967 let dtd_ref = &*dtd;
968
969 let elem_name = e.name;
971 let elem_decl = if !dtd_ref.elements.is_null() {
972 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, elem_name)
973 } else {
974 ptr::null_mut()
975 };
976
977 if elem_decl.is_null() {
978 let name_str = string::xmlstr_to_string(elem_name);
979 let err_msg = format!("No declaration for element {}\0", name_str);
980 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
981 vctxt_pop_node(ctxt);
982 return 0;
983 }
984
985 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
986
987 let elem_type = elem_decl_ref.etype as u32;
989
990 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
991 let mut child = e.children;
993 while !child.is_null() {
994 let child_type = (*child).type_ as u32;
995 if child_type != XML_TEXT_NODE as u32 && child_type != XML_CDATA_SECTION_NODE as u32
996 {
997 valid = 0;
998 let name_str = string::xmlstr_to_string(elem_name);
999 let err_msg = format!(
1000 "Element '{}' is declared EMPTY but has child elements\0",
1001 name_str
1002 );
1003 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1004 break;
1005 }
1006 child = (*child).next;
1007 }
1008 } else if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1009 } else if elem_type == XML_ELEMENT_TYPE_MIXED as u32 {
1011 let mut child = e.children;
1013 while !child.is_null() {
1014 let child_type = (*child).type_ as u32;
1015 if child_type == XML_ELEMENT_NODE as u32 {
1016 let child_name = (*child).name;
1018 let result = dtd::valid_content_model(elem_decl_ref.content, &[child_name]);
1019 if result != dtd::ContentModelResult::Valid {
1020 let cname_str = string::xmlstr_to_string(child_name);
1021 let ename_str = string::xmlstr_to_string(elem_name);
1022 let err_msg = format!(
1023 "Element '{}' is not allowed in mixed content of '{}'\0",
1024 cname_str, ename_str
1025 );
1026 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1027 valid = 0;
1028 }
1029 }
1030 child = (*child).next;
1031 }
1032 } else if elem_type == XML_ELEMENT_TYPE_ELEMENT as u32 {
1033 let mut child_names: Vec<*const xmlChar> = Vec::new();
1035 let mut child = e.children;
1036 while !child.is_null() {
1037 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1038 child_names.push((*child).name);
1039 }
1040 child = (*child).next;
1041 }
1042
1043 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1044 if result != dtd::ContentModelResult::Valid {
1045 let ename_str = string::xmlstr_to_string(elem_name);
1046 let err_msg = format!(
1047 "Content model validation failed for element '{}'\0",
1048 ename_str
1049 );
1050 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1051 valid = 0;
1052 }
1053 }
1054
1055 if !dtd_ref.attributes.is_null() {
1057 let mut attr_prop = e.properties;
1059 while !attr_prop.is_null() {
1060 let attr_ref = &*attr_prop;
1061 let attr_name = attr_ref.name;
1062
1063 let attr_decl = hash::hash_lookup3(
1066 dtd_ref.attributes as *mut hash::HashTable,
1067 attr_name,
1068 ptr::null(),
1069 elem_name,
1070 );
1071
1072 if attr_decl.is_null() {
1073 attr_prop = attr_ref.next;
1078 continue;
1079 }
1080
1081 let attr_decl_ref = &*(attr_decl as *mut _xmlAttribute);
1082 let atype = attr_decl_ref.atype as c_int;
1083
1084 let attr_value = if !attr_ref.children.is_null() {
1086 let text_node = attr_ref.children;
1088 if (*text_node).type_ == XML_TEXT_NODE as c_int
1089 || (*text_node).type_ == XML_CDATA_SECTION_NODE as c_int
1090 {
1091 (*text_node).content
1092 } else {
1093 ptr::null()
1094 }
1095 } else {
1096 ptr::null()
1097 };
1098
1099 if !attr_value.is_null() {
1101 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !attr_decl_ref.tree.is_null()
1102 {
1103 if validate_enumeration(ctxt, attr_value, attr_decl_ref.tree) == 0 {
1104 let aname_str = string::xmlstr_to_string(attr_name);
1105 let aval_str = string::xmlstr_to_string(attr_value);
1106 let err_msg = format!(
1107 "Attribute '{}' has value '{}' not in enumeration\0",
1108 aname_str, aval_str
1109 );
1110 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1111 valid = 0;
1112 }
1113 } else if atype == XML_ATTRIBUTE_NOTATION as c_int {
1114 if validate_notation_use(ctxt, doc, attr_value) == 0 {
1115 let aname_str = string::xmlstr_to_string(attr_name);
1116 let aval_str = string::xmlstr_to_string(attr_value);
1117 let err_msg = format!(
1118 "Attribute '{}' references undeclared notation '{}'\0",
1119 aname_str, aval_str
1120 );
1121 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1122 valid = 0;
1123 }
1124 } else if validate_attribute_value(atype, attr_value) == 0 {
1125 let aname_str = string::xmlstr_to_string(attr_name);
1126 let aval_str = string::xmlstr_to_string(attr_value);
1127 let err_msg = format!(
1128 "Attribute '{}' has invalid value '{}' for its type\0",
1129 aname_str, aval_str
1130 );
1131 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1132 valid = 0;
1133 }
1134
1135 if atype == XML_ATTRIBUTE_ID as c_int {
1137 if validate_id(ctxt, doc, elem, attr_value) == 0 {
1138 valid = 0;
1139 }
1140 } else if atype == XML_ATTRIBUTE_IDREF as c_int {
1141 if validate_id_ref(ctxt, doc, elem, attr_value) == 0 {
1142 valid = 0;
1143 }
1144 } else if atype == XML_ATTRIBUTE_IDREFS as c_int
1145 && validate_id_refs(ctxt, doc, elem, attr_value) == 0
1146 {
1147 valid = 0;
1148 }
1149 }
1150
1151 attr_prop = attr_ref.next;
1152 }
1153
1154 struct RequiredAttrCheck {
1156 ctxt: *mut _xmlValidCtxt,
1157 elem_name: *const xmlChar,
1158 elem_props: *mut _xmlAttr,
1159 valid: *mut c_int,
1160 }
1161
1162 extern "C" fn check_required_attr(
1163 payload: *mut c_void,
1164 data: *mut c_void,
1165 name: *const xmlChar,
1166 name2: *const xmlChar,
1167 _name3: *const xmlChar,
1168 ) {
1169 if payload.is_null() || data.is_null() || name2.is_null() {
1170 return;
1171 }
1172
1173 let check = unsafe { &*(data as *mut RequiredAttrCheck) };
1175 unsafe {
1176 if string::xml_strcmp(name, check.elem_name) != 0 {
1178 return;
1179 }
1180
1181 let attr_decl = &*(payload as *mut _xmlAttribute);
1182
1183 if attr_decl.def == XML_ATTRIBUTE_REQUIRED as c_int {
1185 let mut found = 0;
1187 let mut prop = check.elem_props;
1188 while !prop.is_null() {
1189 if string::xml_strcmp((*prop).name, name2) == 0 {
1190 found = 1;
1191 break;
1192 }
1193 prop = (*prop).next;
1194 }
1195
1196 if found == 0 {
1197 let aname_str = string::xmlstr_to_string(name2);
1198 let ename_str = string::xmlstr_to_string(check.elem_name);
1199 let err_msg = format!(
1200 "Required attribute '{}' missing on element '{}'\0",
1201 aname_str, ename_str
1202 );
1203 vctxt_error(check.ctxt, err_msg.as_ptr() as *const c_char);
1204 *(check.valid) = 0;
1205 }
1206 }
1207 }
1208 }
1209
1210 let mut required_valid = valid;
1211 let check = RequiredAttrCheck {
1212 ctxt,
1213 elem_name,
1214 elem_props: e.properties,
1215 valid: &mut required_valid,
1216 };
1217
1218 hash::hash_scan_full(
1219 dtd_ref.attributes as *mut hash::HashTable,
1220 Some(check_required_attr),
1221 &check as *const RequiredAttrCheck as *mut c_void,
1222 );
1223
1224 valid = required_valid;
1225 }
1226
1227 let mut child = e.children;
1229 while !child.is_null() {
1230 if (*child).type_ == XML_ELEMENT_NODE as c_int
1231 && validate_element(ctxt, doc, child) == 0
1232 {
1233 valid = 0;
1234 }
1235 child = (*child).next;
1236 }
1237
1238 vctxt_pop_node(ctxt);
1239 valid
1240 }
1241}
1242
1243pub unsafe fn validate_document(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1263 if ctxt.is_null() || doc.is_null() {
1264 return 0;
1265 }
1266
1267 unsafe {
1268 let c = &mut *ctxt;
1269 c.doc = doc;
1270 c.valid = 1;
1271
1272 let d = &*doc;
1273
1274 if d.intSubset.is_null() && d.extSubset.is_null() {
1284 vctxt_error(ctxt, b"no DTD found!\0" as *const u8 as *const c_char);
1285 return 0;
1286 }
1287
1288 let mut root = d.children;
1290 while !root.is_null() {
1291 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1292 break;
1293 }
1294 root = (*root).next;
1295 }
1296
1297 if root.is_null() {
1298 vctxt_error(
1299 ctxt,
1300 b"No root element found in document\0" as *const u8 as *const c_char,
1301 );
1302 return 0;
1303 }
1304
1305 if validate_element(ctxt, doc, root) == 0 {
1307 return 0;
1308 }
1309
1310 c.valid
1311 }
1312}
1313
1314pub unsafe fn validate_document_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1336 if ctxt.is_null() || doc.is_null() {
1337 return 0;
1338 }
1339
1340 unsafe {
1341 let c = &mut *ctxt;
1342 c.doc = doc;
1343
1344 let d = &*doc;
1345
1346 if d.refs.is_null() {
1348 return c.valid;
1349 }
1350
1351 struct IdRefCheckContext {
1353 ctxt: *mut _xmlValidCtxt,
1354 doc: *mut _xmlDoc,
1355 }
1356
1357 extern "C" fn check_idref(
1358 _payload: *mut c_void,
1359 data: *mut c_void,
1360 _name: *const xmlChar,
1361 name2: *const xmlChar,
1362 _name3: *const xmlChar,
1363 ) {
1364 if data.is_null() || name2.is_null() {
1365 return;
1366 }
1367
1368 let cx = unsafe { &*(data as *mut IdRefCheckContext) };
1370 unsafe {
1371 let doc_ref = &*cx.doc;
1372
1373 if doc_ref.ids.is_null()
1375 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, name2).is_null()
1376 {
1377 let ref_str = string::xmlstr_to_string(name2);
1378 let err_msg = format!("IDREF '{}' does not reference a declared ID\0", ref_str);
1379 vctxt_error(cx.ctxt, err_msg.as_ptr() as *const c_char);
1380 }
1381 }
1382 }
1383
1384 let ctx = IdRefCheckContext { ctxt, doc };
1385 hash::hash_scan_full(
1386 d.refs as *mut hash::HashTable,
1387 Some(check_idref),
1388 &ctx as *const IdRefCheckContext as *mut c_void,
1389 );
1390
1391 c.valid
1392 }
1393}
1394
1395pub unsafe fn validate_root(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1413 if ctxt.is_null() || doc.is_null() {
1414 return 0;
1415 }
1416
1417 unsafe {
1418 let c = &mut *ctxt;
1419 c.doc = doc;
1420 c.valid = 1;
1421
1422 let d = &*doc;
1423
1424 let mut root = d.children;
1426 while !root.is_null() {
1427 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1428 break;
1429 }
1430 root = (*root).next;
1431 }
1432
1433 if root.is_null() {
1434 vctxt_error(
1435 ctxt,
1436 b"No root element found\0" as *const u8 as *const c_char,
1437 );
1438 return 0;
1439 }
1440
1441 let dtd = get_valid_dtd(doc);
1443 if dtd.is_null() {
1444 return 1;
1446 }
1447
1448 let dtd_ref = &*dtd;
1451 if !dtd_ref.name.is_null() && string::xml_strcmp((*root).name, dtd_ref.name) != 0 {
1452 let root_str = string::xmlstr_to_string((*root).name);
1453 let dtd_str = string::xmlstr_to_string(dtd_ref.name);
1454 let err_msg = format!(
1455 "Root element '{}' does not match DTD root '{}'\0",
1456 root_str, dtd_str
1457 );
1458 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1459 return 0;
1460 }
1461
1462 c.valid
1463 }
1464}
1465
1466pub unsafe fn validate_content(
1486 ctxt: *mut _xmlValidCtxt,
1487 node: *mut _xmlNode,
1488 doc: *mut _xmlDoc,
1489) -> c_int {
1490 if node.is_null() || doc.is_null() || ctxt.is_null() {
1491 return 0;
1492 }
1493
1494 unsafe {
1495 let n = &*node;
1496 if n.type_ != XML_ELEMENT_NODE as c_int {
1497 return 1;
1498 }
1499
1500 let dtd = get_valid_dtd(doc);
1501 if dtd.is_null() {
1502 return 1;
1503 }
1504
1505 let dtd_ref = &*dtd;
1506 if dtd_ref.elements.is_null() {
1507 return 1;
1508 }
1509
1510 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, n.name);
1511 if elem_decl.is_null() {
1512 return 1;
1513 }
1514
1515 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1516 if elem_decl_ref.content.is_null() {
1517 return 1;
1518 }
1519
1520 let elem_type = elem_decl_ref.etype as u32;
1521 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
1522 let mut child = n.children;
1524 while !child.is_null() {
1525 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1526 let name_str = string::xmlstr_to_string(n.name);
1527 let err_msg =
1528 format!("Element '{}' is EMPTY but has child elements\0", name_str);
1529 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1530 return 0;
1531 }
1532 child = (*child).next;
1533 }
1534 return 1;
1535 }
1536
1537 if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1538 return 1;
1539 }
1540
1541 let mut child_names: Vec<*const xmlChar> = Vec::new();
1543 let mut child = n.children;
1544 while !child.is_null() {
1545 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1546 child_names.push((*child).name);
1547 }
1548 child = (*child).next;
1549 }
1550
1551 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1552 if result != dtd::ContentModelResult::Valid {
1553 let name_str = string::xmlstr_to_string(n.name);
1554 let err_msg = format!(
1555 "Content model validation failed for element '{}'\0",
1556 name_str
1557 );
1558 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1559 0
1560 } else {
1561 1
1562 }
1563 }
1564}
1565
1566pub unsafe fn is_mixed_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1584 if doc.is_null() || name.is_null() {
1585 return 0;
1586 }
1587
1588 let dtd = unsafe { get_valid_dtd(doc) };
1589 if dtd.is_null() {
1590 return 0;
1591 }
1592
1593 unsafe {
1594 let dtd_ref = &*dtd;
1595 if dtd_ref.elements.is_null() {
1596 return 0;
1597 }
1598
1599 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1600 if elem_decl.is_null() {
1601 return 0;
1602 }
1603
1604 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1605 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_MIXED as u32) as c_int
1606 }
1607}
1608
1609pub unsafe fn is_empty_element(doc: *mut _xmlDoc, name: *const xmlChar) -> c_int {
1623 if doc.is_null() || name.is_null() {
1624 return 0;
1625 }
1626
1627 let dtd = unsafe { get_valid_dtd(doc) };
1628 if dtd.is_null() {
1629 return 0;
1630 }
1631
1632 unsafe {
1633 let dtd_ref = &*dtd;
1634 if dtd_ref.elements.is_null() {
1635 return 0;
1636 }
1637
1638 let elem_decl = hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, name);
1639 if elem_decl.is_null() {
1640 return 0;
1641 }
1642
1643 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
1644 ((elem_decl_ref.etype as u32) == XML_ELEMENT_TYPE_EMPTY as u32) as c_int
1645 }
1646}
1647
1648pub unsafe fn validate_dtd(
1672 ctxt: *mut _xmlValidCtxt,
1673 doc: *mut _xmlDoc,
1674 dtd: *mut _xmlDtd,
1675) -> c_int {
1676 if ctxt.is_null() || dtd.is_null() {
1677 return 0;
1678 }
1679
1680 let c = unsafe { &mut *ctxt };
1681 c.doc = doc;
1682 c.valid = 1;
1683
1684 struct ValidateDtdCtx {
1685 ctxt: *mut _xmlValidCtxt,
1686 doc: *mut _xmlDoc,
1687 }
1688
1689 extern "C" fn validate_attr_decl_cb(
1690 payload: *mut c_void,
1691 data: *mut c_void,
1692 _name: *const xmlChar,
1693 _name2: *const xmlChar,
1694 _name3: *const xmlChar,
1695 ) {
1696 if payload.is_null() || data.is_null() {
1697 return;
1698 }
1699
1700 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1702 unsafe {
1703 let attr = payload as *mut _xmlAttribute;
1704 validate_attribute_decl(ctx.ctxt, ctx.doc, ptr::null_mut(), attr);
1705 }
1706 }
1707
1708 extern "C" fn validate_elem_content_cb(
1709 payload: *mut c_void,
1710 data: *mut c_void,
1711 _name: *const xmlChar,
1712 _name2: *const xmlChar,
1713 _name3: *const xmlChar,
1714 ) {
1715 if payload.is_null() || data.is_null() {
1716 return;
1717 }
1718
1719 let ctx = unsafe { &*(data as *mut ValidateDtdCtx) };
1721 unsafe {
1722 let elem = &*(payload as *mut _xmlElement);
1723 if !elem.content.is_null() {
1724 validate_content_model_refs(ctx.ctxt, ctx.doc, elem.content);
1725 }
1726 }
1727 }
1728
1729 unsafe {
1730 let dtd_ref = &*dtd;
1731
1732 if !dtd_ref.attributes.is_null() {
1734 let ctx = ValidateDtdCtx { ctxt, doc };
1735 hash::hash_scan_full(
1736 dtd_ref.attributes as *mut hash::HashTable,
1737 Some(validate_attr_decl_cb),
1738 &ctx as *const ValidateDtdCtx as *mut c_void,
1739 );
1740 }
1741
1742 if !dtd_ref.elements.is_null() {
1744 let ctx = ValidateDtdCtx { ctxt, doc };
1745 hash::hash_scan_full(
1746 dtd_ref.elements as *mut hash::HashTable,
1747 Some(validate_elem_content_cb),
1748 &ctx as *const ValidateDtdCtx as *mut c_void,
1749 );
1750 }
1751
1752 c.valid
1753 }
1754}
1755
1756unsafe fn validate_content_model_refs(
1763 ctxt: *mut _xmlValidCtxt,
1764 doc: *mut _xmlDoc,
1765 content: *mut _xmlElementContent,
1766) {
1767 if content.is_null() {
1768 return;
1769 }
1770
1771 unsafe {
1772 let c = &*content;
1773
1774 match c.type_ as u32 {
1775 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
1776 if !c.name.is_null() {
1778 let dtd = get_valid_dtd(doc);
1779 if !dtd.is_null() {
1780 let dtd_ref = &*dtd;
1781 if !dtd_ref.elements.is_null() {
1782 let decl =
1783 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, c.name);
1784 if decl.is_null() {
1785 let name_str = string::xmlstr_to_string(c.name);
1786 let err_msg = format!(
1787 "Element '{}' referenced in content model is not declared\0",
1788 name_str
1789 );
1790 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1791 }
1792 }
1793 }
1794 }
1795 }
1796 t if t == XML_ELEMENT_CONTENT_SEQ as u32 || t == XML_ELEMENT_CONTENT_OR as u32 => {
1797 validate_content_model_refs(ctxt, doc, c.c1);
1798 validate_content_model_refs(ctxt, doc, c.c2);
1799 }
1800 _ => {}
1801 }
1802 }
1803}
1804
1805pub unsafe fn validate_dtd_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1826 unsafe { validate_document_final(ctxt, doc) }
1827}
1828
1829const XML_SCAN_NC: u32 = 1; const XML_SCAN_NMTOKEN: u32 = 2; const fn is_blank_byte(b: u8) -> bool {
1857 b == b' ' || b == b'\t' || b == b'\n' || b == b'\r'
1858}
1859
1860const fn utf8_char_len(lead: u8) -> usize {
1862 if lead < 0x80 {
1863 1
1864 } else if lead >= 0xC0 && lead <= 0xDF {
1865 2
1866 } else if lead >= 0xE0 && lead <= 0xEF {
1867 3
1868 } else if lead >= 0xF0 && lead <= 0xF7 {
1869 4
1870 } else {
1871 0
1872 }
1873}
1874
1875unsafe fn scan_name_offsets(bytes: &[u8], start: usize, flags: u32) -> usize {
1888 let stop = if flags & XML_SCAN_NC != 0 {
1889 Some(b':')
1890 } else {
1891 None
1892 };
1893 let mut i = start;
1894 let mut is_nmtoken = flags & XML_SCAN_NMTOKEN != 0;
1895 while i < bytes.len() {
1896 let b = bytes[i];
1897 if b < 0x80 {
1898 if stop == Some(b) {
1899 break;
1900 }
1901 let c = b as char;
1902 let ok = if is_nmtoken {
1903 is_xml_name_char(c)
1904 } else {
1905 is_xml_name_start(c)
1906 };
1907 if !ok {
1908 break;
1909 }
1910 i += 1;
1911 } else {
1912 let len = utf8_char_len(b);
1913 if len == 0 || i + len > bytes.len() {
1914 break;
1915 }
1916 let ch = match core::str::from_utf8(&bytes[i..i + len])
1917 .ok()
1918 .and_then(|s| s.chars().next())
1919 {
1920 Some(c) => c,
1921 None => break,
1922 };
1923 let ok = if is_nmtoken {
1924 is_xml_name_char(ch)
1925 } else {
1926 is_xml_name_start(ch)
1927 };
1928 if !ok {
1929 break;
1930 }
1931 i += len;
1932 }
1933 is_nmtoken = true;
1935 }
1936 i
1937}
1938
1939pub unsafe fn validate_ncname(value: *const xmlChar, space: c_int) -> c_int {
1945 if value.is_null() {
1946 return -1;
1947 }
1948 let bytes = string::xmlstr_to_bytes(value);
1949 let mut start = 0usize;
1950 if space != 0 {
1951 while start < bytes.len() && is_blank_byte(bytes[start]) {
1952 start += 1;
1953 }
1954 }
1955 let end = scan_name_offsets(bytes, start, XML_SCAN_NC);
1956 if end == start {
1957 return 1;
1958 }
1959 let mut end2 = end;
1960 if space != 0 {
1961 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
1962 end2 += 1;
1963 }
1964 }
1965 if end2 == bytes.len() {
1966 0
1967 } else {
1968 1
1969 }
1970}
1971
1972pub unsafe fn validate_qname(value: *const xmlChar, space: c_int) -> c_int {
1978 if value.is_null() {
1979 return -1;
1980 }
1981 let bytes = string::xmlstr_to_bytes(value);
1982 let mut start = 0usize;
1983 if space != 0 {
1984 while start < bytes.len() && is_blank_byte(bytes[start]) {
1985 start += 1;
1986 }
1987 }
1988 let mut end = scan_name_offsets(bytes, start, XML_SCAN_NC);
1989 if end == start {
1990 return 1;
1991 }
1992 if end < bytes.len() && bytes[end] == b':' {
1993 end += 1;
1994 let end2 = scan_name_offsets(bytes, end, XML_SCAN_NC);
1995 if end2 == end {
1996 return 1;
1997 }
1998 end = end2;
1999 }
2000 if space != 0 {
2001 while end < bytes.len() && is_blank_byte(bytes[end]) {
2002 end += 1;
2003 }
2004 }
2005 if end == bytes.len() {
2006 0
2007 } else {
2008 1
2009 }
2010}
2011
2012pub unsafe fn validate_name_space(value: *const xmlChar, space: c_int) -> c_int {
2023 if value.is_null() {
2024 return -1;
2025 }
2026 let bytes = string::xmlstr_to_bytes(value);
2027 let mut start = 0usize;
2028 if space != 0 {
2029 while start < bytes.len() && is_blank_byte(bytes[start]) {
2030 start += 1;
2031 }
2032 }
2033 let end = scan_name_offsets(bytes, start, 0);
2034 if end == start {
2035 return 1;
2036 }
2037 let mut end2 = end;
2038 if space != 0 {
2039 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2040 end2 += 1;
2041 }
2042 }
2043 if end2 == bytes.len() {
2044 0
2045 } else {
2046 1
2047 }
2048}
2049
2050pub unsafe fn validate_nmtoken_space(value: *const xmlChar, space: c_int) -> c_int {
2056 if value.is_null() {
2057 return -1;
2058 }
2059 let bytes = string::xmlstr_to_bytes(value);
2060 let mut start = 0usize;
2061 if space != 0 {
2062 while start < bytes.len() && is_blank_byte(bytes[start]) {
2063 start += 1;
2064 }
2065 }
2066 let end = scan_name_offsets(bytes, start, XML_SCAN_NMTOKEN);
2067 if end == start {
2068 return 1;
2069 }
2070 let mut end2 = end;
2071 if space != 0 {
2072 while end2 < bytes.len() && is_blank_byte(bytes[end2]) {
2073 end2 += 1;
2074 }
2075 }
2076 if end2 == bytes.len() {
2077 0
2078 } else {
2079 1
2080 }
2081}
2082
2083unsafe fn validate_value_internal(value: *const xmlChar, flags: u32) -> c_int {
2086 if value.is_null() {
2087 return 0;
2088 }
2089 let bytes = string::xmlstr_to_bytes(value);
2090 if bytes.is_empty() {
2091 return 0;
2092 }
2093 let end = scan_name_offsets(bytes, 0, flags);
2094 if end == 0 {
2095 return 0;
2096 }
2097 if end == bytes.len() {
2098 1
2099 } else {
2100 0
2101 }
2102}
2103
2104unsafe fn validate_values_internal(value: *const xmlChar, flags: u32) -> c_int {
2107 if value.is_null() {
2108 return 0;
2109 }
2110 let bytes = string::xmlstr_to_bytes(value);
2111 let mut cur = scan_name_offsets(bytes, 0, flags);
2112 if cur == 0 {
2113 return 0;
2114 }
2115 while cur < bytes.len() && bytes[cur] == b' ' {
2116 while cur < bytes.len() && bytes[cur] == b' ' {
2117 cur += 1;
2118 }
2119 let end = scan_name_offsets(bytes, cur, flags);
2120 if end == cur {
2121 return 0;
2122 }
2123 cur = end;
2124 }
2125 if cur == bytes.len() {
2126 1
2127 } else {
2128 0
2129 }
2130}
2131
2132pub unsafe fn validate_name_value(value: *const xmlChar) -> c_int {
2138 validate_value_internal(value, 0)
2139}
2140
2141pub unsafe fn validate_names_value(value: *const xmlChar) -> c_int {
2147 validate_values_internal(value, 0)
2148}
2149
2150pub unsafe fn validate_nmtoken_value(value: *const xmlChar) -> c_int {
2156 validate_value_internal(value, XML_SCAN_NMTOKEN)
2157}
2158
2159pub unsafe fn validate_nmtokens_value(value: *const xmlChar) -> c_int {
2165 validate_values_internal(value, XML_SCAN_NMTOKEN)
2166}
2167
2168pub unsafe fn get_dtd_qelement_desc(
2179 dtd: *mut _xmlDtd,
2180 name: *const xmlChar,
2181 prefix: *const xmlChar,
2182) -> *mut _xmlElement {
2183 if dtd.is_null() {
2184 return ptr::null_mut();
2185 }
2186 unsafe {
2187 let elements = (*dtd).elements;
2188 if elements.is_null() {
2189 return ptr::null_mut();
2190 }
2191 hash::hash_lookup2(elements as *mut hash::HashTable, name, prefix) as *mut _xmlElement
2192 }
2193}
2194
2195pub unsafe fn get_dtd_qattr_desc(
2203 dtd: *mut _xmlDtd,
2204 elem: *const xmlChar,
2205 name: *const xmlChar,
2206 prefix: *const xmlChar,
2207) -> *mut _xmlAttribute {
2208 if dtd.is_null() || elem.is_null() || name.is_null() {
2209 return ptr::null_mut();
2210 }
2211 unsafe {
2212 let attrs = (*dtd).attributes;
2213 if attrs.is_null() {
2214 return ptr::null_mut();
2215 }
2216 hash::hash_lookup3(attrs as *mut hash::HashTable, name, prefix, elem) as *mut _xmlAttribute
2217 }
2218}
2219
2220pub unsafe fn get_dtd_notation_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlNotation {
2226 if dtd.is_null() || name.is_null() {
2227 return ptr::null_mut();
2228 }
2229 unsafe {
2230 let notations = (*dtd).notations;
2231 if notations.is_null() {
2232 return ptr::null_mut();
2233 }
2234 hash::hash_lookup(notations as *mut hash::HashTable, name) as *mut _xmlNotation
2235 }
2236}
2237
2238unsafe fn split_qname4(name: *const xmlChar, prefix: *mut *mut xmlChar) -> *const xmlChar {
2247 if prefix.is_null() {
2248 return name;
2249 }
2250 unsafe {
2251 *prefix = ptr::null_mut();
2252 if name.is_null() {
2253 return ptr::null();
2254 }
2255 let bytes = string::xmlstr_to_bytes(name);
2256 match bytes.iter().position(|&b| b == b':') {
2257 None => name,
2258 Some(pos) => {
2259 let p = string::bytes_to_xmlstr(&bytes[..pos]);
2260 *prefix = p;
2261 name.add(pos + 1)
2262 }
2263 }
2264 }
2265}
2266
2267unsafe fn free_id(id: *mut _xmlID) {
2274 if id.is_null() {
2275 return;
2276 }
2277 unsafe {
2278 if !(*id).value.is_null() {
2279 allocator::xmlFreeImpl((*id).value as *mut c_void);
2280 }
2281 if !(*id).name.is_null() {
2282 allocator::xmlFreeImpl((*id).name as *mut c_void);
2283 }
2284 if !(*id).attr.is_null() {
2285 (*(*id).attr).id = ptr::null_mut();
2286 (*(*id).attr).atype = 0;
2287 }
2288 allocator::xmlFreeImpl(id as *mut c_void);
2289 }
2290}
2291
2292unsafe extern "C" fn free_id_entry(payload: *mut c_void, _name: *mut xmlChar) {
2295 free_id(payload as *mut _xmlID);
2296}
2297
2298unsafe fn add_id_internal(
2301 attr: *mut _xmlAttr,
2302 value: *const xmlChar,
2303 id_ptr: *mut *mut _xmlID,
2304) -> c_int {
2305 unsafe {
2306 if !id_ptr.is_null() {
2307 *id_ptr = ptr::null_mut();
2308 }
2309 if value.is_null() || *value == 0 {
2310 return 0;
2311 }
2312 if attr.is_null() {
2313 return 0;
2314 }
2315 let doc = (*attr).doc;
2316 if doc.is_null() {
2317 return 0;
2318 }
2319
2320 let mut table = (*doc).ids as *mut hash::HashTable;
2321 if table.is_null() {
2322 (*doc).ids = hash::hash_create(0) as *mut c_void;
2323 table = (*doc).ids as *mut hash::HashTable;
2324 if table.is_null() {
2325 return -1;
2326 }
2327 } else if !hash::hash_lookup(table, value).is_null() {
2328 return 0;
2329 }
2330
2331 let id = allocator::xmlMallocZero(size_of::<_xmlID>() as usize) as *mut _xmlID;
2332 if id.is_null() {
2333 return -1;
2334 }
2335 (*id).doc = doc;
2336 (*id).value = string::xml_strdup(value);
2337 if (*id).value.is_null() {
2338 free_id(id);
2339 return -1;
2340 }
2341 if !(*attr).id.is_null() {
2343 remove_id(doc, attr);
2344 }
2345 if hash::hash_add_entry(table, value, id as *mut c_void) != 0 {
2346 free_id(id);
2347 return -1;
2348 }
2349 if !id_ptr.is_null() {
2350 *id_ptr = id;
2351 }
2352 (*id).attr = attr;
2353 (*id).lineno = tree::get_line_no((*attr).parent) as c_int;
2354 (*attr).atype = XML_ATTRIBUTE_ID as c_int;
2355 (*attr).id = id as *mut c_void;
2356 1
2357 }
2358}
2359
2360pub unsafe fn add_id(
2368 ctxt: *mut _xmlValidCtxt,
2369 doc: *mut _xmlDoc,
2370 value: *const xmlChar,
2371 attr: *mut _xmlAttr,
2372) -> *mut _xmlID {
2373 unsafe {
2374 if attr.is_null() || doc != (*attr).doc {
2375 return ptr::null_mut();
2376 }
2377 let mut id = ptr::null_mut();
2378 let res = add_id_internal(attr, value, &mut id);
2379 if res < 0 {
2380 vctxt_error(
2381 ctxt,
2382 b"Memory allocation failed : xmlAddID\0" as *const u8 as *const c_char,
2383 );
2384 } else if res == 0 && !ctxt.is_null() {
2385 let msg = format!("ID {} already defined\0", string::xmlstr_to_string(value));
2386 vctxt_error(ctxt, msg.as_ptr() as *const c_char);
2387 }
2388 id
2389 }
2390}
2391
2392pub unsafe fn remove_id(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2399 unsafe {
2400 if doc.is_null() {
2401 return -1;
2402 }
2403 if attr.is_null() || (*attr).id.is_null() {
2404 return -1;
2405 }
2406 let table = (*doc).ids as *mut hash::HashTable;
2407 if table.is_null() {
2408 return -1;
2409 }
2410 let value = (*((*attr).id as *mut _xmlID)).value;
2411 if hash::hash_remove_entry(table, value, Some(free_id_entry)) < 0 {
2412 return -1;
2413 }
2414 0
2415 }
2416}
2417
2418unsafe fn free_ref(r: *mut _xmlRef) {
2420 if r.is_null() {
2421 return;
2422 }
2423 unsafe {
2424 if !(*r).value.is_null() {
2425 allocator::xmlFreeImpl((*r).value as *mut c_void);
2426 }
2427 if !(*r).name.is_null() {
2428 allocator::xmlFreeImpl((*r).name as *mut c_void);
2429 }
2430 allocator::xmlFreeImpl(r as *mut c_void);
2431 }
2432}
2433
2434unsafe extern "C" fn free_ref_list_entry(data: *mut c_void) {
2436 free_ref(data as *mut _xmlRef);
2437}
2438
2439const unsafe extern "C" fn dummy_compare(_a: *const c_void, _b: *const c_void) -> c_int {
2441 1
2442}
2443
2444unsafe extern "C" fn free_ref_table_entry(payload: *mut c_void, _name: *mut xmlChar) {
2446 crate::xml::list::list_delete(payload as *mut crate::xml::list::List);
2447}
2448
2449pub unsafe fn add_ref(
2456 ctxt: *mut _xmlValidCtxt,
2457 doc: *mut _xmlDoc,
2458 value: *const xmlChar,
2459 attr: *mut _xmlAttr,
2460) -> *mut _xmlRef {
2461 unsafe {
2462 if doc.is_null() || value.is_null() || attr.is_null() {
2463 return ptr::null_mut();
2464 }
2465
2466 let mut table = (*doc).refs as *mut hash::HashTable;
2467 if table.is_null() {
2468 (*doc).refs = hash::hash_create(0) as *mut c_void;
2469 table = (*doc).refs as *mut hash::HashTable;
2470 if table.is_null() {
2471 vctxt_error(
2472 ctxt,
2473 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2474 );
2475 return ptr::null_mut();
2476 }
2477 }
2478
2479 let ret = allocator::xmlMallocZero(size_of::<_xmlRef>() as usize) as *mut _xmlRef;
2480 if ret.is_null() {
2481 vctxt_error(
2482 ctxt,
2483 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2484 );
2485 return ptr::null_mut();
2486 }
2487 (*ret).value = string::xml_strdup(value);
2488 if (*ret).value.is_null() {
2489 free_ref(ret);
2490 vctxt_error(
2491 ctxt,
2492 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2493 );
2494 return ptr::null_mut();
2495 }
2496 let streaming = !ctxt.is_null()
2500 && !(*ctxt).userData.is_null()
2501 && (*((*ctxt).userData as *mut _xmlParserCtxt)).parseMode
2502 == crate::abi::types::xmlParserMode::XML_PARSE_READER as c_int;
2503 if streaming {
2504 (*ret).name = string::xml_strdup((*attr).name);
2505 (*ret).attr = ptr::null_mut();
2506 } else {
2507 (*ret).name = ptr::null();
2508 (*ret).attr = attr;
2509 }
2510 (*ret).lineno = tree::get_line_no((*attr).parent) as c_int;
2511
2512 let ref_list = hash::hash_lookup(table, value) as *mut crate::xml::list::List;
2514 if ref_list.is_null() {
2515 let l = crate::xml::list::list_create(Some(free_ref_list_entry), Some(dummy_compare));
2516 if l.is_null() {
2517 free_ref(ret);
2518 vctxt_error(
2519 ctxt,
2520 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2521 );
2522 return ptr::null_mut();
2523 }
2524 if hash::hash_add_entry(table, value, l as *mut c_void) != 0 {
2525 crate::xml::list::list_delete(l);
2526 free_ref(ret);
2527 vctxt_error(
2528 ctxt,
2529 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2530 );
2531 return ptr::null_mut();
2532 }
2533 crate::xml::list::list_append(l, ret as *mut c_void);
2534 } else {
2535 if crate::xml::list::list_append(ref_list, ret as *mut c_void) != 0 {
2536 free_ref(ret);
2537 vctxt_error(
2538 ctxt,
2539 b"Memory allocation failed : xmlAddRef\0" as *const u8 as *const c_char,
2540 );
2541 return ptr::null_mut();
2542 }
2543 }
2544 ret
2545 }
2546}
2547
2548pub unsafe fn remove_ref(doc: *mut _xmlDoc, attr: *mut _xmlAttr) -> c_int {
2555 if doc.is_null() || attr.is_null() {
2559 return -1;
2560 }
2561 unsafe {
2562 let table = (*doc).refs as *mut hash::HashTable;
2563 if table.is_null() {
2564 return -1;
2565 }
2566 let mut removed = -1;
2567 struct ScanCtx {
2569 table: *mut hash::HashTable,
2570 attr: *mut _xmlAttr,
2571 removed: c_int,
2572 }
2573 extern "C" fn scan_remove(payload: *mut c_void, data: *mut c_void, name: *const xmlChar) {
2574 let ctx = unsafe { &mut *(data as *mut ScanCtx) };
2575 let l = payload as *mut crate::xml::list::List;
2576 let mut cur: *mut c_void = crate::xml::list::list_front(l);
2578 while !cur.is_null() {
2579 let next: *mut c_void = unsafe { (*(cur as *mut _xmlRef)).next as *mut c_void };
2580 let r = cur as *mut _xmlRef;
2581 if unsafe { (*r).attr } == ctx.attr {
2582 unsafe {
2583 crate::xml::list::list_remove_first(l, cur);
2584 }
2585 ctx.removed = 0;
2586 }
2587 cur = next;
2588 }
2589 if crate::xml::list::list_empty(l) != 0 {
2590 unsafe {
2591 hash::hash_remove_entry(ctx.table, name, Some(free_ref_table_entry));
2592 }
2593 }
2594 let _ = name;
2595 }
2596 let mut ctx = ScanCtx {
2597 table,
2598 attr,
2599 removed: -1,
2600 };
2601 hash::hash_scan(
2602 table,
2603 Some(scan_remove),
2604 &mut ctx as *mut ScanCtx as *mut c_void,
2605 );
2606 removed = ctx.removed;
2607 removed
2608 }
2609}
2610
2611pub unsafe fn add_id_safe(attr: *mut _xmlAttr, value: *const xmlChar) -> c_int {
2619 add_id_internal(attr, value, ptr::null_mut())
2620}
2621
2622pub unsafe fn free_id_table(table: *mut hash::HashTable) {
2628 hash::hash_free(table, Some(free_id_entry));
2629}
2630
2631pub unsafe fn free_ref_table(table: *mut hash::HashTable) {
2637 hash::hash_free(table, Some(free_ref_table_entry));
2638}
2639
2640pub unsafe fn get_id(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut _xmlAttr {
2648 unsafe {
2649 if doc.is_null() || id.is_null() {
2650 return ptr::null_mut();
2651 }
2652 let table = (*doc).ids as *mut hash::HashTable;
2653 if table.is_null() {
2654 return ptr::null_mut();
2655 }
2656 let id_entry = hash::hash_lookup(table, id) as *mut _xmlID;
2657 if id_entry.is_null() {
2658 return ptr::null_mut();
2659 }
2660 if (*id_entry).attr.is_null() {
2661 doc as *mut _xmlAttr
2663 } else {
2664 (*id_entry).attr
2665 }
2666 }
2667}
2668
2669pub unsafe fn get_refs(doc: *mut _xmlDoc, id: *const xmlChar) -> *mut crate::xml::list::List {
2675 unsafe {
2676 if doc.is_null() || id.is_null() {
2677 return ptr::null_mut();
2678 }
2679 let table = (*doc).refs as *mut hash::HashTable;
2680 if table.is_null() {
2681 return ptr::null_mut();
2682 }
2683 hash::hash_lookup(table, id) as *mut crate::xml::list::List
2684 }
2685}
2686
2687pub unsafe fn is_id(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2695 unsafe {
2696 if attr.is_null() || (*attr).name.is_null() {
2697 return 0;
2698 }
2699 if !doc.is_null() && (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2700 if string::xml_strcmp(b"id\0" as *const u8 as *const xmlChar, (*attr).name) == 0 {
2701 return 1;
2702 }
2703 if elem.is_null() || (*elem).type_ != XML_ELEMENT_NODE as c_int {
2704 return 0;
2705 }
2706 if string::xml_strcmp(b"name\0" as *const u8 as *const xmlChar, (*attr).name) == 0
2707 && string::xml_strcmp(b"a\0" as *const u8 as *const xmlChar, (*elem).name) == 0
2708 {
2709 return 1;
2710 }
2711 } else {
2712 if !(*attr).ns.is_null()
2714 && !(*(*attr).ns).prefix.is_null()
2715 && string::xml_strcmp(
2716 (*(*attr).ns).prefix,
2717 b"xml\0" as *const u8 as *const xmlChar,
2718 ) == 0
2719 && string::xml_strcmp((*attr).name, b"id\0" as *const u8 as *const xmlChar) == 0
2720 {
2721 return 1;
2722 }
2723 if doc.is_null() || ((*doc).intSubset.is_null() && (*doc).extSubset.is_null()) {
2724 return 0;
2725 }
2726 if elem.is_null()
2727 || (*elem).type_ != XML_ELEMENT_NODE as c_int
2728 || (*elem).name.is_null()
2729 {
2730 return 0;
2731 }
2732 let mut fullname = (*elem).name;
2733 let mut owned = false;
2734 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
2735 let f = string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
2736 if f.is_null() {
2737 return -1;
2738 }
2739 fullname = f;
2740 owned = true;
2741 }
2742 let aprefix = if !(*attr).ns.is_null() {
2743 (*(*attr).ns).prefix
2744 } else {
2745 ptr::null()
2746 };
2747 let mut attr_decl =
2748 get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
2749 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2750 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
2751 }
2752 if owned {
2753 allocator::xmlFreeImpl(fullname as *mut c_void);
2754 }
2755 if !attr_decl.is_null() && (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int {
2756 return 1;
2757 }
2758 }
2759 0
2760 }
2761}
2762
2763pub unsafe fn is_ref(doc: *mut _xmlDoc, elem: *mut _xmlNode, attr: *mut _xmlAttr) -> c_int {
2769 unsafe {
2770 if attr.is_null() {
2771 return 0;
2772 }
2773 let doc = if doc.is_null() { (*attr).doc } else { doc };
2774 if doc.is_null() {
2775 return 0;
2776 }
2777 if (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2778 return 0;
2779 }
2780 if (*doc).type_ == XML_HTML_DOCUMENT_NODE as c_int {
2781 return 0;
2782 }
2783 if elem.is_null() {
2784 return 0;
2785 }
2786 let aprefix = if !(*attr).ns.is_null() {
2787 (*(*attr).ns).prefix
2788 } else {
2789 ptr::null()
2790 };
2791 let mut attr_decl =
2792 get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
2793 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
2794 attr_decl = get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
2795 }
2796 if !attr_decl.is_null()
2797 && ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
2798 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
2799 {
2800 return 1;
2801 }
2802 0
2803 }
2804}
2805
2806pub unsafe fn get_dtd_element_desc(dtd: *mut _xmlDtd, name: *const xmlChar) -> *mut _xmlElement {
2813 unsafe {
2814 if dtd.is_null() || name.is_null() {
2815 return ptr::null_mut();
2816 }
2817 let elements = (*dtd).elements;
2818 if elements.is_null() {
2819 return ptr::null_mut();
2820 }
2821 let mut prefix = ptr::null_mut();
2822 let local = split_qname4(name, &mut prefix);
2823 if local.is_null() {
2824 if !prefix.is_null() {
2825 allocator::xmlFreeImpl(prefix as *mut c_void);
2826 }
2827 return ptr::null_mut();
2828 }
2829 let cur =
2830 hash::hash_lookup2(elements as *mut hash::HashTable, local, prefix) as *mut _xmlElement;
2831 if !prefix.is_null() {
2832 allocator::xmlFreeImpl(prefix as *mut c_void);
2833 }
2834 cur
2835 }
2836}
2837
2838pub unsafe fn get_dtd_attr_desc(
2846 dtd: *mut _xmlDtd,
2847 elem: *const xmlChar,
2848 name: *const xmlChar,
2849) -> *mut _xmlAttribute {
2850 unsafe {
2851 if dtd.is_null() || elem.is_null() || name.is_null() {
2852 return ptr::null_mut();
2853 }
2854 let attrs = (*dtd).attributes;
2855 if attrs.is_null() {
2856 return ptr::null_mut();
2857 }
2858 let mut prefix = ptr::null_mut();
2859 let local = split_qname4(name, &mut prefix);
2860 if local.is_null() {
2861 if !prefix.is_null() {
2862 allocator::xmlFreeImpl(prefix as *mut c_void);
2863 }
2864 return ptr::null_mut();
2865 }
2866 let cur = hash::hash_lookup3(attrs as *mut hash::HashTable, local, prefix, elem)
2867 as *mut _xmlAttribute;
2868 if !prefix.is_null() {
2869 allocator::xmlFreeImpl(prefix as *mut c_void);
2870 }
2871 cur
2872 }
2873}
2874
2875unsafe fn vctxt_error_node(ctxt: *mut _xmlValidCtxt, _node: *mut _xmlNode, msg: *const c_char) {
2885 vctxt_error(ctxt, msg);
2886}
2887
2888pub unsafe fn validate_element_decl(
2896 ctxt: *mut _xmlValidCtxt,
2897 doc: *mut _xmlDoc,
2898 elem: *mut _xmlElement,
2899) -> c_int {
2900 unsafe {
2901 if doc.is_null() || (*doc).intSubset.is_null() && (*doc).extSubset.is_null() {
2902 return 1;
2903 }
2904 if elem.is_null() {
2905 return 1;
2906 }
2907 let mut ret = 1;
2908
2909 if (*elem).etype == XML_ELEMENT_TYPE_MIXED as c_int {
2912 let mut cur = (*elem).content;
2913 while !cur.is_null() {
2914 if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int {
2915 break;
2916 }
2917 if (*cur).c1.is_null() {
2918 break;
2919 }
2920 if (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2921 let name = (*(*cur).c1).name;
2922 let mut next = (*cur).c2;
2923 while !next.is_null() {
2924 if (*next).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
2925 if string::xml_strcmp((*next).name, name) == 0
2926 && string::xml_strcmp((*next).prefix, (*(*cur).c1).prefix) == 0
2927 {
2928 if (*(*cur).c1).prefix.is_null() {
2929 let msg = format!(
2930 "Definition of {} has duplicate references of {}\0",
2931 string::xmlstr_to_string((*elem).name),
2932 string::xmlstr_to_string(name)
2933 );
2934 vctxt_error_node(
2935 ctxt,
2936 elem as *mut _xmlNode,
2937 msg.as_ptr() as *const c_char,
2938 );
2939 } else {
2940 let msg = format!(
2941 "Definition of {} has duplicate references of {}:{}\0",
2942 string::xmlstr_to_string((*elem).name),
2943 string::xmlstr_to_string((*(*cur).c1).prefix),
2944 string::xmlstr_to_string(name)
2945 );
2946 vctxt_error_node(
2947 ctxt,
2948 elem as *mut _xmlNode,
2949 msg.as_ptr() as *const c_char,
2950 );
2951 }
2952 ret = 0;
2953 }
2954 break;
2955 }
2956 if (*next).c1.is_null() {
2957 break;
2958 }
2959 if (*(*next).c1).type_ != XML_ELEMENT_CONTENT_ELEMENT as c_int {
2960 break;
2961 }
2962 if string::xml_strcmp((*(*next).c1).name, name) == 0
2963 && string::xml_strcmp((*(*next).c1).prefix, (*(*cur).c1).prefix) == 0
2964 {
2965 if (*(*cur).c1).prefix.is_null() {
2966 let msg = format!(
2967 "Definition of {} has duplicate references to {}\0",
2968 string::xmlstr_to_string((*elem).name),
2969 string::xmlstr_to_string(name)
2970 );
2971 vctxt_error_node(
2972 ctxt,
2973 elem as *mut _xmlNode,
2974 msg.as_ptr() as *const c_char,
2975 );
2976 } else {
2977 let msg = format!(
2978 "Definition of {} has duplicate references to {}:{}\0",
2979 string::xmlstr_to_string((*elem).name),
2980 string::xmlstr_to_string((*(*cur).c1).prefix),
2981 string::xmlstr_to_string(name)
2982 );
2983 vctxt_error_node(
2984 ctxt,
2985 elem as *mut _xmlNode,
2986 msg.as_ptr() as *const c_char,
2987 );
2988 }
2989 ret = 0;
2990 }
2991 next = (*next).c2;
2992 }
2993 }
2994 cur = (*cur).c2;
2995 }
2996 }
2997
2998 let mut prefix = ptr::null_mut();
3001 let local_name = split_qname4((*elem).name, &mut prefix);
3002 if local_name.is_null() {
3003 vctxt_error(
3004 ctxt,
3005 b"Memory allocation failed : xmlValidateElementDecl\0" as *const u8
3006 as *const c_char,
3007 );
3008 if !prefix.is_null() {
3009 allocator::xmlFreeImpl(prefix as *mut c_void);
3010 }
3011 return 0;
3012 }
3013
3014 for subset in [(*doc).intSubset, (*doc).extSubset] {
3015 if subset.is_null() {
3016 continue;
3017 }
3018 let tst = get_dtd_qelement_desc(subset, local_name, prefix);
3019 if !tst.is_null()
3020 && tst != elem
3021 && ((*tst).prefix == (*elem).prefix
3022 || string::xml_strcmp((*tst).prefix, (*elem).prefix) == 0)
3023 && (*tst).etype != XML_ELEMENT_TYPE_UNDEFINED as c_int
3024 {
3025 let msg = format!(
3026 "Redefinition of element {}\0",
3027 string::xmlstr_to_string((*elem).name)
3028 );
3029 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
3030 ret = 0;
3031 }
3032 }
3033 if !prefix.is_null() {
3034 allocator::xmlFreeImpl(prefix as *mut c_void);
3035 }
3036 ret
3037 }
3038}
3039
3040pub const unsafe fn validate_notation_decl(
3059 _ctxt: *mut _xmlValidCtxt,
3060 _doc: *mut _xmlDoc,
3061 _nota: *mut _xmlNotation,
3062) -> c_int {
3063 1
3064}
3065
3066pub unsafe fn validate_one_attribute(
3076 ctxt: *mut _xmlValidCtxt,
3077 doc: *mut _xmlDoc,
3078 elem: *mut _xmlNode,
3079 attr: *mut _xmlAttr,
3080 value: *const xmlChar,
3081) -> c_int {
3082 unsafe {
3083 if doc.is_null() {
3084 return 0;
3085 }
3086 if elem.is_null() || (*elem).name.is_null() {
3087 return 0;
3088 }
3089 if attr.is_null() || (*attr).name.is_null() {
3090 return 0;
3091 }
3092 let mut ret = 1;
3093
3094 let aprefix = if !(*attr).ns.is_null() {
3095 (*(*attr).ns).prefix
3096 } else {
3097 ptr::null()
3098 };
3099
3100 let mut attr_decl = ptr::null_mut();
3101 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3102 let fullname =
3103 string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
3104 if fullname.is_null() {
3105 vctxt_error(
3106 ctxt,
3107 b"Memory allocation failed : xmlValidateOneAttribute\0" as *const u8
3108 as *const c_char,
3109 );
3110 return 0;
3111 }
3112 attr_decl = get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
3113 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3114 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
3115 }
3116 if !std::ptr::eq(fullname, (*elem).name) {
3117 allocator::xmlFreeImpl(fullname as *mut c_void);
3118 }
3119 }
3120 if attr_decl.is_null() {
3121 attr_decl = get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
3122 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3123 attr_decl =
3124 get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
3125 }
3126 }
3127
3128 if attr_decl.is_null() {
3130 let msg = format!(
3131 "No declaration for attribute {} of element {}\0",
3132 string::xmlstr_to_string((*attr).name),
3133 string::xmlstr_to_string((*elem).name)
3134 );
3135 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3136 return 0;
3137 }
3138 if !(*attr).id.is_null() {
3139 remove_id(doc, attr);
3140 }
3141 (*attr).atype = (*attr_decl).atype;
3142
3143 let val = if (*doc).properties & crate::abi::types::xmlDocProperties::XML_DOC_OLD10 as c_int
3145 != 0
3146 {
3147 match (*attr_decl).atype as u32 {
3150 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
3151 validate_values_internal(value, 0)
3152 }
3153 t if t == XML_ATTRIBUTE_ENTITY as u32
3154 || t == XML_ATTRIBUTE_IDREF as u32
3155 || t == XML_ATTRIBUTE_ID as u32
3156 || t == XML_ATTRIBUTE_NOTATION as u32 =>
3157 {
3158 validate_value_internal(value, 0)
3159 }
3160 t if t == XML_ATTRIBUTE_NMTOKENS as u32
3161 || t == XML_ATTRIBUTE_ENUMERATION as u32 =>
3162 {
3163 validate_values_internal(value, XML_SCAN_NMTOKEN)
3164 }
3165 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => {
3166 validate_value_internal(value, XML_SCAN_NMTOKEN)
3167 }
3168 _ => 1,
3169 }
3170 } else {
3171 validate_attribute_value((*attr_decl).atype, value)
3172 };
3173 if val == 0 {
3174 let msg = format!(
3175 "Syntax of value for attribute {} of {} is not valid\0",
3176 string::xmlstr_to_string((*attr).name),
3177 string::xmlstr_to_string((*elem).name)
3178 );
3179 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3180 ret = 0;
3181 }
3182
3183 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3185 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3186 {
3187 let _msg = format!(
3188 "Value for attribute {} of {} is different from default \"{}\n\0",
3189 string::xmlstr_to_string((*attr).name),
3190 string::xmlstr_to_string((*elem).name),
3191 string::xmlstr_to_string((*attr_decl).defaultValue)
3192 );
3193 let msg = format!(
3195 "Value for attribute {} of {} is different from default \"{}\"\0",
3196 string::xmlstr_to_string((*attr).name),
3197 string::xmlstr_to_string((*elem).name),
3198 string::xmlstr_to_string((*attr_decl).defaultValue)
3199 );
3200 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3201 ret = 0;
3202 }
3203
3204 const XML_VCTXT_IN_ENTITY: c_uint = 4; if (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int
3207 && (ctxt.is_null() || (*ctxt).flags & XML_VCTXT_IN_ENTITY == 0)
3208 && add_id(ctxt, doc, value, attr).is_null()
3209 {
3210 ret = 0;
3211 }
3212 if ((*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
3213 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int)
3214 && add_ref(ctxt, doc, value, attr).is_null()
3215 {
3216 ret = 0;
3217 }
3218
3219 if (*attr_decl).atype == XML_ATTRIBUTE_NOTATION as c_int {
3221 let mut nota = get_dtd_notation_desc((*doc).intSubset, value);
3222 if nota.is_null() {
3223 nota = get_dtd_notation_desc((*doc).extSubset, value);
3224 }
3225 if nota.is_null() {
3226 let msg = format!(
3227 "Value \"{}\" for attribute {} of {} is not a declared Notation\0",
3228 string::xmlstr_to_string(value),
3229 string::xmlstr_to_string((*attr).name),
3230 string::xmlstr_to_string((*elem).name)
3231 );
3232 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3233 ret = 0;
3234 }
3235 let mut tree = (*attr_decl).tree;
3236 while !tree.is_null() {
3237 if string::xml_strcmp((*tree).name, value) == 0 {
3238 break;
3239 }
3240 tree = (*tree).next;
3241 }
3242 if tree.is_null() {
3243 let msg = format!(
3244 "Value \"{}\" for attribute {} of {} is not among the enumerated notations\0",
3245 string::xmlstr_to_string(value),
3246 string::xmlstr_to_string((*attr).name),
3247 string::xmlstr_to_string((*elem).name)
3248 );
3249 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3250 ret = 0;
3251 }
3252 }
3253
3254 if (*attr_decl).atype == XML_ATTRIBUTE_ENUMERATION as c_int {
3256 let mut tree = (*attr_decl).tree;
3257 while !tree.is_null() {
3258 if string::xml_strcmp((*tree).name, value) == 0 {
3259 break;
3260 }
3261 tree = (*tree).next;
3262 }
3263 if tree.is_null() {
3264 let msg = format!(
3265 "Value \"{}\" for attribute {} of {} is not among the enumerated set\0",
3266 string::xmlstr_to_string(value),
3267 string::xmlstr_to_string((*attr).name),
3268 string::xmlstr_to_string((*elem).name)
3269 );
3270 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3271 ret = 0;
3272 }
3273 }
3274
3275 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3277 && string::xml_strcmp((*attr_decl).defaultValue, value) != 0
3278 {
3279 let msg = format!(
3280 "Value for attribute {} of {} must be \"{}\"\0",
3281 string::xmlstr_to_string((*attr).name),
3282 string::xmlstr_to_string((*elem).name),
3283 string::xmlstr_to_string((*attr_decl).defaultValue)
3284 );
3285 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3286 ret = 0;
3287 }
3288
3289 if (*attr_decl).atype == XML_ATTRIBUTE_ENTITY as c_int {
3291 let ent = tree::get_doc_entity(doc, value);
3292 if ent.is_null() {
3293 let msg = format!(
3294 "ENTITY attribute {} reference an unknown entity \"{}\"\0",
3295 string::xmlstr_to_string((*attr).name),
3296 string::xmlstr_to_string(value)
3297 );
3298 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3299 ret = 0;
3300 } else if (*ent).etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3301 let msg = format!(
3302 "ENTITY attribute {} reference an entity \"{}\" of wrong type\0",
3303 string::xmlstr_to_string((*attr).name),
3304 string::xmlstr_to_string(value)
3305 );
3306 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3307 ret = 0;
3308 }
3309 }
3310 ret
3311 }
3312}
3313
3314pub unsafe fn validate_one_namespace(
3321 ctxt: *mut _xmlValidCtxt,
3322 doc: *mut _xmlDoc,
3323 elem: *mut _xmlNode,
3324 prefix: *const xmlChar,
3325 ns: *mut _xmlNs,
3326 value: *const xmlChar,
3327) -> c_int {
3328 unsafe {
3329 if doc.is_null() {
3330 return 0;
3331 }
3332 if elem.is_null() || (*elem).name.is_null() {
3333 return 0;
3334 }
3335 if ns.is_null() || (*ns).href.is_null() {
3336 return 0;
3337 }
3338 let mut ret = 1;
3339
3340 let mut attr_decl = ptr::null_mut();
3341 if !prefix.is_null() {
3342 let fullname = string::build_qname((*elem).name, prefix, ptr::null_mut(), 0);
3343 if fullname.is_null() {
3344 vctxt_error(
3345 ctxt,
3346 b"Memory allocation failed : xmlValidateOneNamespace\0" as *const u8
3347 as *const c_char,
3348 );
3349 return 0;
3350 }
3351 if !(*ns).prefix.is_null() {
3352 attr_decl = get_dtd_qattr_desc(
3353 (*doc).intSubset,
3354 fullname,
3355 (*ns).prefix,
3356 b"xmlns\0" as *const u8 as *const xmlChar,
3357 );
3358 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3359 attr_decl = get_dtd_qattr_desc(
3360 (*doc).extSubset,
3361 fullname,
3362 (*ns).prefix,
3363 b"xmlns\0" as *const u8 as *const xmlChar,
3364 );
3365 }
3366 } else {
3367 attr_decl = get_dtd_qattr_desc(
3368 (*doc).intSubset,
3369 fullname,
3370 b"xmlns\0" as *const u8 as *const xmlChar,
3371 ptr::null(),
3372 );
3373 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3374 attr_decl = get_dtd_qattr_desc(
3375 (*doc).extSubset,
3376 fullname,
3377 b"xmlns\0" as *const u8 as *const xmlChar,
3378 ptr::null(),
3379 );
3380 }
3381 }
3382 if !std::ptr::eq(fullname, (*elem).name) {
3383 allocator::xmlFreeImpl(fullname as *mut c_void);
3384 }
3385 }
3386 if attr_decl.is_null() {
3387 if !(*ns).prefix.is_null() {
3388 attr_decl = get_dtd_qattr_desc(
3389 (*doc).intSubset,
3390 (*elem).name,
3391 (*ns).prefix,
3392 b"xmlns\0" as *const u8 as *const xmlChar,
3393 );
3394 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3395 attr_decl = get_dtd_qattr_desc(
3396 (*doc).extSubset,
3397 (*elem).name,
3398 (*ns).prefix,
3399 b"xmlns\0" as *const u8 as *const xmlChar,
3400 );
3401 }
3402 } else {
3403 attr_decl = get_dtd_qattr_desc(
3404 (*doc).intSubset,
3405 (*elem).name,
3406 b"xmlns\0" as *const u8 as *const xmlChar,
3407 ptr::null(),
3408 );
3409 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3410 attr_decl = get_dtd_qattr_desc(
3411 (*doc).extSubset,
3412 (*elem).name,
3413 b"xmlns\0" as *const u8 as *const xmlChar,
3414 ptr::null(),
3415 );
3416 }
3417 }
3418 }
3419
3420 if attr_decl.is_null() {
3422 let msg = if !(*ns).prefix.is_null() {
3423 format!(
3424 "No declaration for attribute xmlns:{} of element {}\0",
3425 string::xmlstr_to_string((*ns).prefix),
3426 string::xmlstr_to_string((*elem).name)
3427 )
3428 } else {
3429 format!(
3430 "No declaration for attribute xmlns of element {}\0",
3431 string::xmlstr_to_string((*elem).name)
3432 )
3433 };
3434 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3435 return 0;
3436 }
3437
3438 let val = validate_attribute_value((*attr_decl).atype, value);
3439 if val == 0 {
3440 let msg = if !(*ns).prefix.is_null() {
3441 format!(
3442 "Syntax of value for attribute xmlns:{} of {} is not valid\0",
3443 string::xmlstr_to_string((*ns).prefix),
3444 string::xmlstr_to_string((*elem).name)
3445 )
3446 } else {
3447 format!(
3448 "Syntax of value for attribute xmlns of {} is not valid\0",
3449 string::xmlstr_to_string((*elem).name)
3450 )
3451 };
3452 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3453 ret = 0;
3454 }
3455
3456 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3458 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3459 {
3460 let msg = if !(*ns).prefix.is_null() {
3461 format!(
3462 "Value for attribute xmlns:{} of {} is different from default \"{}\"\0",
3463 string::xmlstr_to_string((*ns).prefix),
3464 string::xmlstr_to_string((*elem).name),
3465 string::xmlstr_to_string((*attr_decl).defaultValue)
3466 )
3467 } else {
3468 format!(
3469 "Value for attribute xmlns of {} is different from default \"{}\"\0",
3470 string::xmlstr_to_string((*elem).name),
3471 string::xmlstr_to_string((*attr_decl).defaultValue)
3472 )
3473 };
3474 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3475 ret = 0;
3476 }
3477 ret
3478 }
3479}
3480
3481pub unsafe fn validate_one_element(
3489 ctxt: *mut _xmlValidCtxt,
3490 doc: *mut _xmlDoc,
3491 elem: *mut _xmlNode,
3492) -> c_int {
3493 unsafe {
3494 if doc.is_null() {
3495 return 0;
3496 }
3497 if elem.is_null() {
3498 return 0;
3499 }
3500 match (*elem).type_ {
3501 t if t == XML_TEXT_NODE as c_int
3502 || t == XML_CDATA_SECTION_NODE as c_int
3503 || t == XML_ENTITY_REF_NODE as c_int
3504 || t == XML_PI_NODE as c_int
3505 || t == XML_COMMENT_NODE as c_int
3506 || t == XML_XINCLUDE_START as c_int
3507 || t == XML_XINCLUDE_END as c_int =>
3508 {
3509 return 1;
3510 }
3511 t if t == XML_ELEMENT_NODE as c_int => {}
3512 _ => {
3513 vctxt_error_node(
3514 ctxt,
3515 elem,
3516 b"unexpected element type\0" as *const u8 as *const c_char,
3517 );
3518 return 0;
3519 }
3520 }
3521
3522 let mut ret = 1;
3523 let mut extsubset = 0;
3524 let elem_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
3525 if elem_decl.is_null() {
3526 return 0;
3527 }
3528
3529 if (*ctxt).vstateNr == 0 {
3532 match (*elem_decl).etype as u32 {
3533 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => {
3534 let msg = format!(
3535 "No declaration for element {}\0",
3536 string::xmlstr_to_string((*elem).name)
3537 );
3538 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3539 return 0;
3540 }
3541 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
3542 if !(*elem).children.is_null() {
3543 let msg = format!(
3544 "Element {} was declared EMPTY this one has content\0",
3545 string::xmlstr_to_string((*elem).name)
3546 );
3547 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3548 ret = 0;
3549 }
3550 }
3551 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
3552 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
3553 if !(*elem_decl).content.is_null()
3554 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
3555 {
3556 let mut child = (*elem).children;
3558 while !child.is_null() {
3559 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3560 let msg = format!(
3561 "Element {} was declared #PCDATA but contains non text nodes\0",
3562 string::xmlstr_to_string((*elem).name)
3563 );
3564 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3565 ret = 0;
3566 break;
3567 }
3568 child = (*child).next;
3569 }
3570 } else {
3571 let mut child = (*elem).children;
3573 while !child.is_null() {
3574 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3575 let mut fullname = (*child).name;
3576 let mut own = false;
3577 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3578 let fnp = string::build_qname(
3579 (*child).name,
3580 (*(*child).ns).prefix,
3581 ptr::null_mut(),
3582 0,
3583 );
3584 if fnp.is_null() {
3585 vctxt_error(
3586 ctxt,
3587 b"Memory allocation failed : xmlValidateOneElement\0"
3588 as *const u8
3589 as *const c_char,
3590 );
3591 return 0;
3592 }
3593 fullname = fnp;
3594 own = true;
3595 }
3596 if validate_check_mixed(ctxt, (*elem_decl).content, fullname) != 1 {
3597 let msg = format!(
3598 "Element {} is not declared in {} list of possible children\0",
3599 string::xmlstr_to_string(fullname),
3600 string::xmlstr_to_string((*elem).name)
3601 );
3602 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3603 ret = 0;
3604 }
3605 if own {
3606 allocator::xmlFreeImpl(fullname as *mut c_void);
3607 }
3608 }
3609 child = (*child).next;
3610 }
3611 }
3612 }
3613 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
3614 let mut names: Vec<*const xmlChar> = Vec::new();
3617 let mut owned: Vec<*mut xmlChar> = Vec::new();
3618 let mut child = (*elem).children;
3619 while !child.is_null() {
3620 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3621 let mut fullname = (*child).name;
3622 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3623 let fnp = string::build_qname(
3624 (*child).name,
3625 (*(*child).ns).prefix,
3626 ptr::null_mut(),
3627 0,
3628 );
3629 if !fnp.is_null() {
3630 fullname = fnp;
3631 owned.push(fnp);
3632 }
3633 }
3634 names.push(fullname);
3635 }
3636 child = (*child).next;
3637 }
3638 let result = dtd::valid_content_model((*elem_decl).content, &names);
3639 for n in owned {
3640 allocator::xmlFreeImpl(n as *mut c_void);
3641 }
3642 if result != dtd::ContentModelResult::Valid {
3643 let msg = format!(
3644 "Element {} content does not follow the DTD\0",
3645 string::xmlstr_to_string((*elem).name)
3646 );
3647 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3648 ret = 0;
3649 }
3650 }
3651 _ => {}
3652 }
3653
3654 let mut attr = (*elem).properties;
3656 while !attr.is_null() {
3657 let aval = if !(*attr).children.is_null() {
3658 (*(*attr).children).content
3659 } else {
3660 ptr::null()
3661 };
3662 if validate_one_attribute(ctxt, doc, elem, attr, aval) == 0 {
3663 ret = 0;
3664 }
3665 attr = (*attr).next;
3666 }
3667 }
3668 ret
3669 }
3670}
3671
3672#[repr(C)]
3687struct ValidState {
3688 elem_decl: *mut _xmlElement,
3689 node: *mut _xmlNode,
3690 exec: *mut ContentModelExec,
3691}
3692
3693unsafe fn valid_get_elem_decl(
3696 ctxt: *mut _xmlValidCtxt,
3697 doc: *mut _xmlDoc,
3698 elem: *mut _xmlNode,
3699 extsubset: *mut c_int,
3700) -> *mut _xmlElement {
3701 unsafe {
3702 if ctxt.is_null() || doc.is_null() || elem.is_null() || (*elem).name.is_null() {
3703 return ptr::null_mut();
3704 }
3705 if !extsubset.is_null() {
3706 *extsubset = 0;
3707 }
3708 let mut elem_decl = ptr::null_mut();
3709
3710 let prefix = if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3711 (*(*elem).ns).prefix
3712 } else {
3713 ptr::null()
3714 };
3715 if !prefix.is_null() {
3716 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, prefix);
3717 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3718 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, prefix);
3719 if !elem_decl.is_null() && !extsubset.is_null() {
3720 *extsubset = 1;
3721 }
3722 }
3723 }
3724 if elem_decl.is_null() {
3725 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, ptr::null());
3727 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3728 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, ptr::null());
3729 if !elem_decl.is_null() && !extsubset.is_null() {
3730 *extsubset = 1;
3731 }
3732 }
3733 }
3734 if elem_decl.is_null() {
3735 let msg = format!(
3736 "No declaration for element {}\0",
3737 string::xmlstr_to_string((*elem).name)
3738 );
3739 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3740 }
3741 elem_decl
3742 }
3743}
3744
3745unsafe fn validate_check_mixed(
3747 ctxt: *mut _xmlValidCtxt,
3748 cont: *mut _xmlElementContent,
3749 qname: *const xmlChar,
3750) -> c_int {
3751 unsafe {
3752 let mut plen: c_int = 0;
3753 let has_colon = string::split_qname3(qname, &mut plen) != 0;
3754 let local = if has_colon {
3758 qname.add(plen as usize + 1)
3759 } else {
3760 ptr::null()
3761 };
3762 let mut cur = cont;
3763 if local.is_null() {
3764 while !cur.is_null() {
3765 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3766 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
3767 return 1;
3768 }
3769 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3770 && !(*cur).c1.is_null()
3771 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3772 {
3773 if (*(*cur).c1).prefix.is_null()
3774 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3775 {
3776 return 1;
3777 }
3778 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3779 || (*cur).c1.is_null()
3780 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3781 {
3782 vctxt_error(
3783 ctxt,
3784 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3785 );
3786 break;
3787 }
3788 cur = (*cur).c2;
3789 }
3790 } else {
3791 while !cur.is_null() {
3792 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3793 if !(*cur).prefix.is_null()
3794 && prefix_matches((*cur).prefix, qname, plen)
3795 && string::xml_strcmp((*cur).name, local) == 0
3796 {
3797 return 1;
3798 }
3799 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3800 && !(*cur).c1.is_null()
3801 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3802 {
3803 if !(*(*cur).c1).prefix.is_null()
3804 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3805 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3806 {
3807 return 1;
3808 }
3809 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3810 || (*cur).c1.is_null()
3811 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3812 {
3813 vctxt_error(
3814 ctxt,
3815 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3816 );
3817 break;
3818 }
3819 cur = (*cur).c2;
3820 }
3821 }
3822 0
3823 }
3824}
3825
3826unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
3829 unsafe {
3830 let p = string::xmlstr_to_bytes(prefix);
3831 let q = string::xmlstr_to_bytes(qname);
3832 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
3833 }
3834}
3835
3836#[derive(Debug)]
3845#[repr(C)]
3846pub struct ContentModelNfa {
3847 transitions: Vec<(u32, *const xmlChar, u32)>,
3849 start: u32,
3851 accept: Vec<u32>,
3853}
3854
3855#[derive(Debug)]
3857#[repr(C)]
3858pub struct ContentModelExec {
3859 nfa: *mut ContentModelNfa,
3861 current: Vec<u32>,
3863}
3864
3865struct NfaBuilder {
3867 transitions: Vec<(u32, *const xmlChar, u32)>,
3868 n_states: u32,
3869}
3870
3871impl NfaBuilder {
3872 const fn new() -> Self {
3873 NfaBuilder {
3874 transitions: Vec::new(),
3875 n_states: 0,
3876 }
3877 }
3878 const fn new_state(&mut self) -> u32 {
3879 let s = self.n_states;
3880 self.n_states += 1;
3881 s
3882 }
3883 fn eps(&mut self, from: u32, to: u32) {
3884 self.transitions.push((from, ptr::null(), to));
3885 }
3886 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
3887 self.transitions.push((from, name, to));
3888 }
3889}
3890
3891unsafe fn compile_content_sub(
3896 b: &mut NfaBuilder,
3897 model: *mut _xmlElementContent,
3898) -> (u32, Vec<u32>) {
3899 if model.is_null() {
3900 let s = b.new_state();
3901 return (s, vec![s]);
3902 }
3903 let m = unsafe { &*model };
3904 let (mut in_s, outs) = match m.type_ as u32 {
3905 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
3906 let s = b.new_state();
3907 let to = b.new_state();
3908 b.name_trans(s, m.name, to);
3909 (s, vec![to])
3910 }
3911 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
3912 let (in1, out1) = compile_content_sub(b, m.c1);
3913 let (in2, out2) = compile_content_sub(b, m.c2);
3914 for &o in &out1 {
3915 b.eps(o, in2);
3916 }
3917 (in1, out2)
3918 }
3919 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
3920 let (in1, out1) = compile_content_sub(b, m.c1);
3921 let (in2, out2) = compile_content_sub(b, m.c2);
3922 let s = b.new_state();
3923 b.eps(s, in1);
3924 b.eps(s, in2);
3925 let mut all = out1;
3926 all.extend(out2);
3927 (s, all)
3928 }
3929 _ => {
3934 let s = b.new_state();
3935 (s, vec![s])
3936 }
3937 };
3938 match m.ocur as u32 {
3939 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
3940 let s = b.new_state();
3941 b.eps(s, in_s);
3942 for &o2 in &outs {
3943 b.eps(s, o2);
3944 }
3945 in_s = s;
3946 }
3947 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
3948 let s = b.new_state();
3949 b.eps(s, in_s);
3950 for &o2 in &outs {
3951 b.eps(s, o2);
3952 b.eps(o2, s);
3953 }
3954 in_s = s;
3955 }
3956 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
3957 let s = b.new_state();
3958 b.eps(s, in_s);
3959 for &o2 in &outs {
3960 b.eps(o2, s);
3961 }
3962 in_s = s;
3963 }
3964 _ => {}
3965 }
3966 (in_s, outs)
3967}
3968
3969unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
3971 if model.is_null() {
3972 return false;
3973 }
3974 unsafe {
3975 let m = &*model;
3976 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
3977 return true;
3978 }
3979 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
3980 }
3981}
3982
3983unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
3989 unsafe {
3990 if content.is_null() {
3991 return ptr::null_mut();
3992 }
3993 let mut b = NfaBuilder::new();
3994 let (start, outs) = compile_content_sub(&mut b, content);
3995 let nfa = Box::new(ContentModelNfa {
3996 transitions: b.transitions,
3997 start,
3998 accept: outs,
3999 });
4000 Box::into_raw(nfa)
4001 }
4002}
4003
4004pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
4010 if nfa.is_null() {
4011 return;
4012 }
4013 unsafe {
4014 ptr::drop_in_place(nfa);
4015 allocator::xmlFreeImpl(nfa as *mut c_void);
4016 }
4017}
4018
4019unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4021 let mut out = states.to_vec();
4022 let mut stack = states.to_vec();
4023 while let Some(s) = stack.pop() {
4024 for &(from, name, to) in &nfa.transitions {
4025 if from == s && name.is_null() && !out.contains(&to) {
4026 out.push(to);
4027 stack.push(to);
4028 }
4029 }
4030 }
4031 out.sort_unstable();
4032 out.dedup();
4033 out
4034}
4035
4036unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4038 unsafe {
4039 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4040 if exec.is_null() {
4041 return ptr::null_mut();
4042 }
4043 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4044 ptr::write(&mut (*exec).nfa, nfa);
4045 ptr::write(&mut (*exec).current, cur);
4046 exec
4047 }
4048}
4049
4050unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4052 if exec.is_null() {
4053 return;
4054 }
4055 unsafe {
4056 ptr::drop_in_place(&mut (*exec).current);
4057 allocator::xmlFreeImpl(exec as *mut c_void);
4058 }
4059}
4060
4061unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4066 unsafe {
4067 if exec.is_null() {
4068 return -1;
4069 }
4070 let nfa = &*(*exec).nfa;
4071 if value.is_null() {
4072 let cur = eps_closure(nfa, &(*exec).current);
4073 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4074 1
4075 } else {
4076 0
4077 };
4078 }
4079 let mut next: Vec<u32> = Vec::new();
4080 for &s in &(*exec).current {
4081 for &(from, name, to) in &nfa.transitions {
4082 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4083 next.push(to);
4084 }
4085 }
4086 }
4087 next.sort_unstable();
4088 next.dedup();
4089 if next.is_empty() {
4090 return -1;
4091 }
4092 let closed = eps_closure(nfa, &next);
4093 (*exec).current = closed;
4094 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4095 1
4096 } else {
4097 0
4098 }
4099 }
4100}
4101
4102unsafe fn vstate_vpush(
4104 ctxt: *mut _xmlValidCtxt,
4105 elem_decl: *mut _xmlElement,
4106 node: *mut _xmlNode,
4107) -> c_int {
4108 unsafe {
4109 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4110 let new_max = if (*ctxt).vstateMax == 0 {
4111 10
4112 } else {
4113 (*ctxt).vstateMax * 2
4114 };
4115 let new_tab = allocator::xmlReallocImpl(
4116 (*ctxt).vstateTab,
4117 (new_max as usize) * size_of::<ValidState>(),
4118 ) as *mut ValidState;
4119 if new_tab.is_null() {
4120 vctxt_error(
4121 ctxt,
4122 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4123 );
4124 return -1;
4125 }
4126 (*ctxt).vstateTab = new_tab as *mut c_void;
4127 (*ctxt).vstateMax = new_max;
4128 }
4129 let idx = (*ctxt).vstateNr as usize;
4130 let tab = (*ctxt).vstateTab as *mut ValidState;
4131 (*tab.add(idx)).elem_decl = elem_decl;
4132 (*tab.add(idx)).node = node;
4133 (*tab.add(idx)).exec = ptr::null_mut();
4134 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4135 if (*elem_decl).cont_model.is_null() {
4136 validate_build_content_model(ctxt, elem_decl);
4137 }
4138 if !(*elem_decl).cont_model.is_null() {
4139 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4140 if exec.is_null() {
4141 vctxt_error(
4142 ctxt,
4143 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4144 );
4145 return -1;
4146 }
4147 (*tab.add(idx)).exec = exec;
4148 } else {
4149 let msg = format!(
4150 "Failed to build content model regexp for {}\0",
4151 string::xmlstr_to_string((*elem_decl).name)
4152 );
4153 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4154 }
4155 }
4156 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4157 (*ctxt).vstateNr += 1;
4158 0
4159 }
4160}
4161
4162unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4164 unsafe {
4165 if (*ctxt).vstateNr < 1 {
4166 return -1;
4167 }
4168 (*ctxt).vstateNr -= 1;
4169 let idx = (*ctxt).vstateNr as usize;
4170 let tab = (*ctxt).vstateTab as *mut ValidState;
4171 let elem_decl = (*tab.add(idx)).elem_decl;
4172 (*tab.add(idx)).elem_decl = ptr::null_mut();
4173 (*tab.add(idx)).node = ptr::null_mut();
4174 if !elem_decl.is_null()
4175 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4176 && !(*tab.add(idx)).exec.is_null()
4177 {
4178 free_content_exec((*tab.add(idx)).exec);
4179 }
4180 (*tab.add(idx)).exec = ptr::null_mut();
4181 if (*ctxt).vstateNr >= 1 {
4182 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4183 } else {
4184 (*ctxt).vstate = ptr::null_mut();
4185 }
4186 0
4187 }
4188}
4189
4190pub unsafe fn validate_build_content_model(
4198 ctxt: *mut _xmlValidCtxt,
4199 elem: *mut _xmlElement,
4200) -> c_int {
4201 unsafe {
4202 if ctxt.is_null() {
4203 return 0;
4204 }
4205 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4206 return 0;
4207 }
4208 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4209 return 1;
4210 }
4211 if !(*elem).cont_model.is_null() {
4212 return 1;
4213 }
4214 if (*elem).content.is_null() {
4215 return 1;
4216 }
4217 if content_has_pcdata((*elem).content) {
4218 let msg = format!(
4219 "Found PCDATA in content model of {}\0",
4220 string::xmlstr_to_string((*elem).name)
4221 );
4222 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4223 return 0;
4224 }
4225 let nfa = build_content_nfa((*elem).content);
4226 if nfa.is_null() {
4227 vctxt_error(
4228 ctxt,
4229 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4230 as *const c_char,
4231 );
4232 return 0;
4233 }
4234 (*elem).cont_model = nfa as *mut c_void;
4235 1
4236 }
4237}
4238
4239pub unsafe fn validate_push_element(
4247 ctxt: *mut _xmlValidCtxt,
4248 doc: *mut _xmlDoc,
4249 elem: *mut _xmlNode,
4250 qname: *const xmlChar,
4251) -> c_int {
4252 unsafe {
4253 let mut ret = 1;
4254 if ctxt.is_null() {
4255 return 0;
4256 }
4257 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4258 let state = (*ctxt).vstate as *mut ValidState;
4259 let elem_decl = (*state).elem_decl;
4260 if !elem_decl.is_null() {
4261 match (*elem_decl).etype as u32 {
4262 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4263 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4264 let msg = format!(
4265 "Element {} was declared EMPTY this one has content\0",
4266 string::xmlstr_to_string((*(*state).node).name)
4267 );
4268 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4269 ret = 0;
4270 }
4271 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4272 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4273 if !(*elem_decl).content.is_null()
4274 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4275 {
4276 let msg = format!(
4277 "Element {} was declared #PCDATA but contains non text nodes\0",
4278 string::xmlstr_to_string((*(*state).node).name)
4279 );
4280 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4281 ret = 0;
4282 } else {
4283 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4284 if ret != 1 {
4285 let msg = format!(
4286 "Element {} is not declared in {} list of possible children\0",
4287 string::xmlstr_to_string(qname),
4288 string::xmlstr_to_string((*(*state).node).name)
4289 );
4290 vctxt_error_node(
4291 ctxt,
4292 (*state).node,
4293 msg.as_ptr() as *const c_char,
4294 );
4295 }
4296 }
4297 }
4298 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 && !(*state).exec.is_null() => {
4299 ret = content_exec_push((*state).exec, qname);
4300 if ret < 0 {
4301 let msg = format!(
4302 "Element {} content does not follow the DTD, Misplaced {}\0",
4303 string::xmlstr_to_string((*(*state).node).name),
4304 string::xmlstr_to_string(qname)
4305 );
4306 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4307 ret = 0;
4308 } else {
4309 ret = 1;
4310 }
4311 }
4312 _ => {}
4313 }
4314 }
4315 }
4316 let mut extsubset = 0;
4317 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4318 let _ = vstate_vpush(ctxt, e_decl, elem);
4320 ret
4321 }
4322}
4323
4324pub unsafe fn validate_push_cdata(
4331 ctxt: *mut _xmlValidCtxt,
4332 data: *const xmlChar,
4333 len: c_int,
4334) -> c_int {
4335 unsafe {
4336 let mut ret = 1;
4337 if ctxt.is_null() {
4338 return 0;
4339 }
4340 if len <= 0 {
4341 return 1;
4342 }
4343 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4344 let state = (*ctxt).vstate as *mut ValidState;
4345 let elem_decl = (*state).elem_decl;
4346 if !elem_decl.is_null() {
4347 match (*elem_decl).etype as u32 {
4348 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4349 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4350 let msg = format!(
4351 "Element {} was declared EMPTY this one has content\0",
4352 string::xmlstr_to_string((*(*state).node).name)
4353 );
4354 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4355 ret = 0;
4356 }
4357 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4358 }
4359 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4360 let bytes = core::slice::from_raw_parts(data, len as usize);
4361 for &b in bytes {
4362 if !is_blank_byte(b) {
4363 let msg = format!(
4364 "Element {} content does not follow the DTD, Text not allowed\0",
4365 string::xmlstr_to_string((*(*state).node).name)
4366 );
4367 vctxt_error_node(
4368 ctxt,
4369 (*state).node,
4370 msg.as_ptr() as *const c_char,
4371 );
4372 ret = 0;
4373 break;
4374 }
4375 }
4376 }
4377 _ => {}
4378 }
4379 }
4380 }
4381 ret
4382 }
4383}
4384
4385pub unsafe fn validate_pop_element(
4392 ctxt: *mut _xmlValidCtxt,
4393 _doc: *mut _xmlDoc,
4394 _elem: *mut _xmlNode,
4395 _qname: *const xmlChar,
4396) -> c_int {
4397 unsafe {
4398 let mut ret = 1;
4399 if ctxt.is_null() {
4400 return 0;
4401 }
4402 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4403 let state = (*ctxt).vstate as *mut ValidState;
4404 let elem_decl = (*state).elem_decl;
4405 if !elem_decl.is_null()
4406 && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int
4407 && !(*state).exec.is_null()
4408 {
4409 ret = content_exec_push((*state).exec, ptr::null());
4410 if ret <= 0 {
4411 let msg = format!(
4412 "Element {} content does not follow the DTD, Expecting more children\0",
4413 string::xmlstr_to_string((*(*state).node).name)
4414 );
4415 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4416 ret = 0;
4417 } else {
4418 ret = 1;
4419 }
4420 }
4421 let _ = vstate_vpop(ctxt);
4422 }
4423 ret
4424 }
4425}
4426
4427#[cfg(test)]
4432mod tests {
4433 use super::*;
4434 use crate::abi::allocator;
4435
4436 use crate::xml::dtd;
4437 use crate::xml::tree;
4438
4439 unsafe fn c_str(s: &str) -> *const xmlChar {
4443 let bytes = s.as_bytes();
4444 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4445 assert!(!ptr.is_null());
4446 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4447 *ptr.add(bytes.len()) = 0;
4448 ptr
4449 }
4450
4451 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4453 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4454 assert!(!doc.is_null());
4455
4456 let name = c_str("root");
4457 let ext_id = c_str("--//Test//DTD//EN");
4458 let sys_id = c_str("test.dtd");
4459 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4460 assert!(!dtd.is_null());
4461
4462 (doc, dtd)
4463 }
4464
4465 #[allow(unused)]
4467 unsafe fn add_elem_decl(
4468 dtd: *mut _xmlDtd,
4469 name: *const xmlChar,
4470 elem_type: c_int,
4471 content: *mut _xmlElementContent,
4472 ) -> *mut _xmlElement {
4473 dtd::add_element_decl(dtd, name, elem_type, content)
4474 }
4475
4476 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4478 let node = tree::new_node(ptr::null_mut(), name);
4479 assert!(!node.is_null());
4480 tree::add_child(doc as *mut _xmlNode, node);
4481 node
4482 }
4483
4484 #[allow(unused)]
4486 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4487 let node = tree::new_node(ptr::null_mut(), name);
4488 assert!(!node.is_null());
4489 tree::add_child(parent, node);
4490 node
4491 }
4492
4493 #[test]
4496 fn test_validate_name_null() {
4497 unsafe {
4498 assert_eq!(validate_name(ptr::null()), 0);
4499 }
4500 }
4501
4502 #[test]
4503 fn test_validate_name_empty() {
4504 unsafe {
4505 let s = b"\0" as *const u8 as *const xmlChar;
4506 assert_eq!(validate_name(s), 0);
4507 }
4508 }
4509
4510 #[test]
4511 fn test_validate_name_valid() {
4512 unsafe {
4513 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4514 for t in &tests {
4515 let s = c_str(t);
4516 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4517 allocator::xmlFreeImpl(s as *mut c_void);
4518 }
4519 }
4520 }
4521
4522 #[test]
4523 fn test_validate_name_invalid() {
4524 unsafe {
4525 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4526 for t in &tests {
4527 let s = c_str(t);
4528 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4529 allocator::xmlFreeImpl(s as *mut c_void);
4530 }
4531 }
4532 }
4533
4534 #[test]
4535 fn test_validate_names_valid() {
4536 unsafe {
4537 let s = c_str("foo bar baz");
4538 assert_eq!(validate_names(s), 1);
4539 allocator::xmlFreeImpl(s as *mut c_void);
4540 }
4541 }
4542
4543 #[test]
4544 fn test_validate_names_invalid() {
4545 unsafe {
4546 let s = c_str("foo 123bar baz");
4547 assert_eq!(validate_names(s), 0);
4548 allocator::xmlFreeImpl(s as *mut c_void);
4549 }
4550 }
4551
4552 #[test]
4555 fn test_validate_nmtoken_null() {
4556 unsafe {
4557 assert_eq!(validate_nmtoken(ptr::null()), 0);
4558 }
4559 }
4560
4561 #[test]
4562 fn test_validate_nmtoken_valid() {
4563 unsafe {
4564 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4565 for t in &tests {
4566 let s = c_str(t);
4567 assert_eq!(
4568 validate_nmtoken(s),
4569 1,
4570 "Expected '{}' to be a valid NMTOKEN",
4571 t
4572 );
4573 allocator::xmlFreeImpl(s as *mut c_void);
4574 }
4575 }
4576 }
4577
4578 #[test]
4579 fn test_validate_nmtoken_invalid() {
4580 unsafe {
4581 let s = c_str("foo bar");
4582 assert_eq!(validate_nmtoken(s), 0);
4583 allocator::xmlFreeImpl(s as *mut c_void);
4584 }
4585 }
4586
4587 #[test]
4588 fn test_validate_nmtokens_valid() {
4589 unsafe {
4590 let s = c_str("foo 123bar -baz");
4591 assert_eq!(validate_nmtokens(s), 1);
4592 allocator::xmlFreeImpl(s as *mut c_void);
4593 }
4594 }
4595
4596 #[test]
4599 fn test_validate_attribute_value_cdata() {
4600 unsafe {
4601 let s = c_str("anything goes here!@#$%^&*()");
4602 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4603 allocator::xmlFreeImpl(s as *mut c_void);
4604
4605 let empty = b"\0" as *const u8 as *const xmlChar;
4607 assert_eq!(
4608 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4609 1
4610 );
4611 }
4612 }
4613
4614 #[test]
4615 fn test_validate_attribute_value_id() {
4616 unsafe {
4617 let valid = c_str("myId");
4618 assert_eq!(
4619 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4620 1
4621 );
4622 allocator::xmlFreeImpl(valid as *mut c_void);
4623
4624 let invalid = c_str("123id");
4625 assert_eq!(
4626 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4627 0
4628 );
4629 allocator::xmlFreeImpl(invalid as *mut c_void);
4630 }
4631 }
4632
4633 #[test]
4634 fn test_validate_attribute_value_idref() {
4635 unsafe {
4636 let valid = c_str("someId");
4637 assert_eq!(
4638 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4639 1
4640 );
4641 allocator::xmlFreeImpl(valid as *mut c_void);
4642 }
4643 }
4644
4645 #[test]
4646 fn test_validate_attribute_value_idrefs() {
4647 unsafe {
4648 let valid = c_str("id1 id2 id3");
4649 assert_eq!(
4650 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4651 1
4652 );
4653 allocator::xmlFreeImpl(valid as *mut c_void);
4654
4655 let invalid = c_str("id1 123id");
4656 assert_eq!(
4657 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4658 0
4659 );
4660 allocator::xmlFreeImpl(invalid as *mut c_void);
4661 }
4662 }
4663
4664 #[test]
4665 fn test_validate_attribute_value_entity() {
4666 unsafe {
4667 let valid = c_str("myEntity");
4668 assert_eq!(
4669 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
4670 1
4671 );
4672 allocator::xmlFreeImpl(valid as *mut c_void);
4673 }
4674 }
4675
4676 #[test]
4677 fn test_validate_attribute_value_nmtoken() {
4678 unsafe {
4679 let valid = c_str("123abc");
4680 assert_eq!(
4681 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
4682 1
4683 );
4684 allocator::xmlFreeImpl(valid as *mut c_void);
4685
4686 let invalid = c_str("foo bar");
4687 assert_eq!(
4688 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
4689 0
4690 );
4691 allocator::xmlFreeImpl(invalid as *mut c_void);
4692 }
4693 }
4694
4695 #[test]
4696 fn test_validate_attribute_value_null() {
4697 unsafe {
4698 assert_eq!(
4702 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
4703 1
4704 );
4705 assert_eq!(
4706 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
4707 0
4708 );
4709 }
4710 }
4711
4712 #[test]
4715 fn test_validate_enumeration_valid() {
4716 unsafe {
4717 let ctxt = new_valid_ctxt();
4718 assert!(!ctxt.is_null());
4719
4720 let red = c_str("red");
4721 let green = c_str("green");
4722 let blue = c_str("blue");
4723
4724 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4725 (*e3).name = string::xml_strdup(blue);
4726 (*e3).next = ptr::null_mut();
4727
4728 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4729 (*e2).name = string::xml_strdup(green);
4730 (*e2).next = e3;
4731
4732 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4733 (*e1).name = string::xml_strdup(red);
4734 (*e1).next = e2;
4735
4736 let value = c_str("green");
4737 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
4738 assert_eq!((*ctxt).valid, 1);
4739
4740 allocator::xmlFreeImpl(value as *mut c_void);
4741 allocator::xmlFreeImpl(red as *mut c_void);
4742 allocator::xmlFreeImpl(green as *mut c_void);
4743 allocator::xmlFreeImpl(blue as *mut c_void);
4744 free_valid_ctxt(ctxt);
4745 }
4746 }
4747
4748 #[test]
4749 fn test_validate_enumeration_invalid() {
4750 unsafe {
4751 let ctxt = new_valid_ctxt();
4752 assert!(!ctxt.is_null());
4753
4754 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4755 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
4756 (*e1).next = ptr::null_mut();
4757
4758 let value = c_str("yellow");
4759 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
4760
4761 allocator::xmlFreeImpl(value as *mut c_void);
4762 free_valid_ctxt(ctxt);
4763 }
4764 }
4765
4766 #[test]
4769 fn test_validate_notation_use_valid() {
4770 unsafe {
4771 let (doc, dtd) = make_test_doc();
4772
4773 let notation_name = c_str("GIF");
4774 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
4775
4776 let ctxt = new_valid_ctxt();
4777 assert!(!ctxt.is_null());
4778
4779 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
4780
4781 free_valid_ctxt(ctxt);
4782 tree::free_doc(doc);
4783 }
4784 }
4785
4786 #[test]
4787 fn test_validate_notation_use_invalid() {
4788 unsafe {
4789 let (doc, _dtd) = make_test_doc();
4790
4791 let ctxt = new_valid_ctxt();
4792 assert!(!ctxt.is_null());
4793
4794 let notation_name = c_str("UNDECLARED");
4795 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
4796
4797 free_valid_ctxt(ctxt);
4798 allocator::xmlFreeImpl(notation_name as *mut c_void);
4799 tree::free_doc(doc);
4800 }
4801 }
4802
4803 #[test]
4806 fn test_new_free_valid_ctxt() {
4807 unsafe {
4808 let ctxt = new_valid_ctxt();
4809 assert!(!ctxt.is_null());
4810 assert_eq!((*ctxt).valid, 1);
4811 assert!((*ctxt).node.is_null());
4812 free_valid_ctxt(ctxt);
4813 }
4814 }
4815
4816 #[test]
4817 fn test_free_valid_ctxt_null() {
4818 unsafe {
4819 free_valid_ctxt(ptr::null_mut());
4820 }
4821 }
4822
4823 #[test]
4826 fn test_set_valid_errors_null() {
4827 unsafe {
4828 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
4829 }
4830 }
4831
4832 #[test]
4835 fn test_validate_element_no_dtd() {
4836 unsafe {
4837 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4838 assert!(!doc.is_null());
4839
4840 let root_name = c_str("root");
4841 let root = create_root_elem(doc, root_name);
4842
4843 let ctxt = new_valid_ctxt();
4844 assert!(!ctxt.is_null());
4845
4846 assert_eq!(validate_element(ctxt, doc, root), 1);
4848
4849 free_valid_ctxt(ctxt);
4850 tree::free_doc(doc);
4851 }
4852 }
4853
4854 #[test]
4855 fn test_validate_element_empty_valid() {
4856 unsafe {
4857 let (doc, dtd) = make_test_doc();
4858
4859 let root_name = c_str("root");
4860 add_elem_decl(
4861 dtd,
4862 root_name,
4863 XML_ELEMENT_TYPE_EMPTY as c_int,
4864 ptr::null_mut(),
4865 );
4866
4867 let root = create_root_elem(doc, root_name);
4868
4869 let ctxt = new_valid_ctxt();
4870 assert!(!ctxt.is_null());
4871
4872 assert_eq!(validate_element(ctxt, doc, root), 1);
4873
4874 free_valid_ctxt(ctxt);
4875 tree::free_doc(doc);
4876 }
4877 }
4878
4879 #[test]
4880 fn test_validate_element_undeclared() {
4881 unsafe {
4882 let (doc, _dtd) = make_test_doc();
4883
4884 let root_name = c_str("root");
4885 let root = create_root_elem(doc, root_name);
4886
4887 let ctxt = new_valid_ctxt();
4888 assert!(!ctxt.is_null());
4889
4890 assert_eq!(validate_element(ctxt, doc, root), 0);
4892
4893 free_valid_ctxt(ctxt);
4894 tree::free_doc(doc);
4895 }
4896 }
4897
4898 #[test]
4899 fn test_validate_element_with_content() {
4900 unsafe {
4901 let (doc, dtd) = make_test_doc();
4902
4903 let root_name = c_str("root");
4905 let child_name = c_str("child");
4906
4907 let child_content =
4909 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4910 assert!(!child_content.is_null());
4911 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4912
4913 add_elem_decl(
4914 dtd,
4915 root_name,
4916 XML_ELEMENT_TYPE_ELEMENT as c_int,
4917 child_content,
4918 );
4919 add_elem_decl(
4920 dtd,
4921 child_name,
4922 XML_ELEMENT_TYPE_EMPTY as c_int,
4923 ptr::null_mut(),
4924 );
4925
4926 let root = create_root_elem(doc, root_name);
4927 let _child = create_child_elem(root, child_name);
4928
4929 let ctxt = new_valid_ctxt();
4930 assert!(!ctxt.is_null());
4931
4932 assert_eq!(validate_element(ctxt, doc, root), 1);
4933
4934 free_valid_ctxt(ctxt);
4935 tree::free_doc(doc);
4936 }
4937 }
4938
4939 #[test]
4940 fn test_validate_element_invalid_content() {
4941 unsafe {
4942 let (doc, dtd) = make_test_doc();
4943
4944 let root_name = c_str("root");
4945 let child_name = c_str("child");
4946 let wrong_name = c_str("wrong");
4947
4948 let child_content =
4950 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4951 assert!(!child_content.is_null());
4952 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4953
4954 add_elem_decl(
4955 dtd,
4956 root_name,
4957 XML_ELEMENT_TYPE_ELEMENT as c_int,
4958 child_content,
4959 );
4960 add_elem_decl(
4961 dtd,
4962 child_name,
4963 XML_ELEMENT_TYPE_EMPTY as c_int,
4964 ptr::null_mut(),
4965 );
4966 add_elem_decl(
4967 dtd,
4968 wrong_name,
4969 XML_ELEMENT_TYPE_EMPTY as c_int,
4970 ptr::null_mut(),
4971 );
4972
4973 let root = create_root_elem(doc, root_name);
4974 create_child_elem(root, wrong_name);
4976
4977 let ctxt = new_valid_ctxt();
4978 assert!(!ctxt.is_null());
4979
4980 assert_eq!(validate_element(ctxt, doc, root), 0);
4981
4982 free_valid_ctxt(ctxt);
4983 tree::free_doc(doc);
4984 }
4985 }
4986
4987 #[test]
4990 fn test_validate_root_match() {
4991 unsafe {
4992 let (doc, dtd) = make_test_doc();
4993
4994 let root_name = c_str("root");
4995 add_elem_decl(
4996 dtd,
4997 root_name,
4998 XML_ELEMENT_TYPE_EMPTY as c_int,
4999 ptr::null_mut(),
5000 );
5001 create_root_elem(doc, root_name);
5002
5003 let ctxt = new_valid_ctxt();
5004 assert!(!ctxt.is_null());
5005
5006 assert_eq!(validate_root(ctxt, doc), 1);
5007
5008 free_valid_ctxt(ctxt);
5009 tree::free_doc(doc);
5010 }
5011 }
5012
5013 #[test]
5014 fn test_validate_root_no_dtd() {
5015 unsafe {
5016 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5017 assert!(!doc.is_null());
5018
5019 let root_name = c_str("root");
5020 create_root_elem(doc, root_name);
5021
5022 let ctxt = new_valid_ctxt();
5023 assert!(!ctxt.is_null());
5024
5025 assert_eq!(validate_root(ctxt, doc), 1);
5027
5028 free_valid_ctxt(ctxt);
5029 tree::free_doc(doc);
5030 }
5031 }
5032
5033 #[test]
5036 fn test_validate_document_valid() {
5037 unsafe {
5038 let (doc, dtd) = make_test_doc();
5039
5040 let root_name = c_str("root");
5041 add_elem_decl(
5042 dtd,
5043 root_name,
5044 XML_ELEMENT_TYPE_EMPTY as c_int,
5045 ptr::null_mut(),
5046 );
5047 create_root_elem(doc, root_name);
5048
5049 let ctxt = new_valid_ctxt();
5050 assert!(!ctxt.is_null());
5051
5052 assert_eq!(validate_document(ctxt, doc), 1);
5053
5054 free_valid_ctxt(ctxt);
5055 tree::free_doc(doc);
5056 }
5057 }
5058
5059 #[test]
5060 fn test_validate_document_no_root() {
5061 unsafe {
5062 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5063 assert!(!doc.is_null());
5064
5065 let ctxt = new_valid_ctxt();
5066 assert!(!ctxt.is_null());
5067
5068 assert_eq!(validate_document(ctxt, doc), 0);
5069
5070 free_valid_ctxt(ctxt);
5071 tree::free_doc(doc);
5072 }
5073 }
5074
5075 #[test]
5078 fn test_validate_content_valid() {
5079 unsafe {
5080 let (doc, dtd) = make_test_doc();
5081
5082 let root_name = c_str("root");
5083 let child_name = c_str("child");
5084
5085 let child_content =
5086 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5087 assert!(!child_content.is_null());
5088
5089 add_elem_decl(
5090 dtd,
5091 root_name,
5092 XML_ELEMENT_TYPE_ELEMENT as c_int,
5093 child_content,
5094 );
5095 add_elem_decl(
5096 dtd,
5097 child_name,
5098 XML_ELEMENT_TYPE_EMPTY as c_int,
5099 ptr::null_mut(),
5100 );
5101
5102 let root = create_root_elem(doc, root_name);
5103 create_child_elem(root, child_name);
5104
5105 let ctxt = new_valid_ctxt();
5106 assert!(!ctxt.is_null());
5107
5108 assert_eq!(validate_content(ctxt, root, doc), 1);
5109
5110 free_valid_ctxt(ctxt);
5111 tree::free_doc(doc);
5112 }
5113 }
5114
5115 #[test]
5118 fn test_is_mixed_element() {
5119 unsafe {
5120 let (doc, dtd) = make_test_doc();
5121 let name = c_str("mixedElem");
5122 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5123
5124 assert_eq!(is_mixed_element(doc, name), 1);
5125
5126 let other = c_str("other");
5127 assert_eq!(is_mixed_element(doc, other), 0);
5128
5129 allocator::xmlFreeImpl(other as *mut c_void);
5130 tree::free_doc(doc);
5131 }
5132 }
5133
5134 #[test]
5135 fn test_is_empty_element() {
5136 unsafe {
5137 let (doc, dtd) = make_test_doc();
5138 let name = c_str("emptyElem");
5139 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5140
5141 assert_eq!(is_empty_element(doc, name), 1);
5142
5143 let other = c_str("other");
5144 assert_eq!(is_empty_element(doc, other), 0);
5145
5146 allocator::xmlFreeImpl(other as *mut c_void);
5147 tree::free_doc(doc);
5148 }
5149 }
5150
5151 #[test]
5152 fn test_is_mixed_element_no_dtd() {
5153 unsafe {
5154 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5155 assert!(!doc.is_null());
5156
5157 let name = c_str("foo");
5158 assert_eq!(is_mixed_element(doc, name), 0);
5159
5160 allocator::xmlFreeImpl(name as *mut c_void);
5161 tree::free_doc(doc);
5162 }
5163 }
5164
5165 #[test]
5166 fn test_is_empty_element_no_dtd() {
5167 unsafe {
5168 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5169 assert!(!doc.is_null());
5170
5171 let name = c_str("foo");
5172 assert_eq!(is_empty_element(doc, name), 0);
5173
5174 allocator::xmlFreeImpl(name as *mut c_void);
5175 tree::free_doc(doc);
5176 }
5177 }
5178
5179 #[test]
5182 fn test_validate_dtd_null() {
5183 unsafe {
5184 let ctxt = new_valid_ctxt();
5185 assert!(!ctxt.is_null());
5186 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5187 free_valid_ctxt(ctxt);
5188 }
5189 }
5190
5191 #[test]
5194 fn test_validate_element_null() {
5195 unsafe {
5196 let (doc, _dtd) = make_test_doc();
5197 let ctxt = new_valid_ctxt();
5198 assert!(!ctxt.is_null());
5199
5200 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5201
5202 free_valid_ctxt(ctxt);
5203 tree::free_doc(doc);
5204 }
5205 }
5206
5207 #[test]
5208 fn test_validate_document_null() {
5209 unsafe {
5210 let ctxt = new_valid_ctxt();
5211 assert!(!ctxt.is_null());
5212
5213 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5214 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5215
5216 free_valid_ctxt(ctxt);
5217 }
5218 }
5219
5220 #[test]
5221 fn test_validate_document_final_null() {
5222 unsafe {
5223 let ctxt = new_valid_ctxt();
5224 assert!(!ctxt.is_null());
5225
5226 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5227 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5228
5229 free_valid_ctxt(ctxt);
5230 }
5231 }
5232
5233 #[test]
5234 fn test_validate_attribute_decl_null() {
5235 unsafe {
5236 let ctxt = new_valid_ctxt();
5237 assert!(!ctxt.is_null());
5238
5239 assert_eq!(
5240 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()),
5241 0
5242 );
5243
5244 free_valid_ctxt(ctxt);
5245 }
5246 }
5247
5248 #[test]
5249 fn test_validate_content_null() {
5250 unsafe {
5251 let ctxt = new_valid_ctxt();
5252 assert!(!ctxt.is_null());
5253
5254 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5255
5256 free_valid_ctxt(ctxt);
5257 }
5258 }
5259
5260 #[test]
5261 fn test_validate_root_null() {
5262 unsafe {
5263 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5264 }
5265 }
5266
5267 #[test]
5268 fn test_validate_enumeration_null() {
5269 unsafe {
5270 let ctxt = new_valid_ctxt();
5271 assert!(!ctxt.is_null());
5272
5273 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5274
5275 free_valid_ctxt(ctxt);
5276 }
5277 }
5278
5279 #[test]
5280 fn test_validate_notation_use_null() {
5281 unsafe {
5282 let ctxt = new_valid_ctxt();
5283 assert!(!ctxt.is_null());
5284
5285 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5286
5287 free_valid_ctxt(ctxt);
5288 }
5289 }
5290
5291 #[test]
5292 fn test_validate_name_start_characters() {
5293 unsafe {
5294 let name = c_str("\u{C0}lph\u{E0}");
5296 assert_eq!(validate_name(name), 1);
5297 allocator::xmlFreeImpl(name as *mut c_void);
5298 }
5299 }
5300
5301 #[test]
5302 fn test_validate_names_single() {
5303 unsafe {
5304 let s = c_str("singleName");
5305 assert_eq!(validate_names(s), 1);
5306 allocator::xmlFreeImpl(s as *mut c_void);
5307 }
5308 }
5309
5310 #[test]
5311 fn test_validate_nmtokens_single() {
5312 unsafe {
5313 let s = c_str("123abc");
5314 assert_eq!(validate_nmtokens(s), 1);
5315 allocator::xmlFreeImpl(s as *mut c_void);
5316 }
5317 }
5318
5319 #[test]
5320 fn test_validate_nmtokens_invalid() {
5321 unsafe {
5322 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5325
5326 let s2 = c_str("foo@bar");
5328 assert_eq!(validate_nmtokens(s2), 0);
5329 allocator::xmlFreeImpl(s2 as *mut c_void);
5330 }
5331 }
5332
5333 #[test]
5334 fn test_validate_attribute_value_empty_non_cdata() {
5335 unsafe {
5336 let empty = b"\0" as *const u8 as *const xmlChar;
5337 assert_eq!(
5338 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5339 0
5340 );
5341 assert_eq!(
5342 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5343 0
5344 );
5345 assert_eq!(
5346 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5347 0
5348 );
5349 }
5350 }
5351
5352 #[test]
5353 fn test_validate_attribute_value_unknown_type() {
5354 unsafe {
5355 let s = c_str("test");
5358 assert_eq!(validate_attribute_value(999, s), 1);
5359 allocator::xmlFreeImpl(s as *mut c_void);
5360 }
5361 }
5362
5363 #[test]
5364 fn test_validate_element_any_content() {
5365 unsafe {
5366 let (doc, dtd) = make_test_doc();
5367
5368 let root_name = c_str("root");
5369 add_elem_decl(
5370 dtd,
5371 root_name,
5372 XML_ELEMENT_TYPE_ANY as c_int,
5373 ptr::null_mut(),
5374 );
5375
5376 let child_name = c_str("child");
5377 add_elem_decl(
5378 dtd,
5379 child_name,
5380 XML_ELEMENT_TYPE_EMPTY as c_int,
5381 ptr::null_mut(),
5382 );
5383
5384 let root = create_root_elem(doc, root_name);
5385 create_child_elem(root, child_name);
5386
5387 let ctxt = new_valid_ctxt();
5388 assert!(!ctxt.is_null());
5389
5390 assert_eq!(validate_element(ctxt, doc, root), 1);
5392
5393 free_valid_ctxt(ctxt);
5394 tree::free_doc(doc);
5395 }
5396 }
5397
5398 #[test]
5399 fn test_validate_element_empty_with_child() {
5400 unsafe {
5401 let (doc, dtd) = make_test_doc();
5402
5403 let root_name = c_str("root");
5404 add_elem_decl(
5405 dtd,
5406 root_name,
5407 XML_ELEMENT_TYPE_EMPTY as c_int,
5408 ptr::null_mut(),
5409 );
5410
5411 let child_name = c_str("child");
5412 add_elem_decl(
5413 dtd,
5414 child_name,
5415 XML_ELEMENT_TYPE_EMPTY as c_int,
5416 ptr::null_mut(),
5417 );
5418
5419 let root = create_root_elem(doc, root_name);
5420 create_child_elem(root, child_name);
5421
5422 let ctxt = new_valid_ctxt();
5423 assert!(!ctxt.is_null());
5424
5425 assert_eq!(validate_element(ctxt, doc, root), 0);
5427
5428 free_valid_ctxt(ctxt);
5429 tree::free_doc(doc);
5430 }
5431 }
5432
5433 #[test]
5434 fn test_validate_dtd_final_null() {
5435 unsafe {
5436 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
5437 }
5438 }
5439}