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::callbacks::xmlHashDeallocator;
35use crate::abi::callbacks::xmlHashScannerFull;
36use crate::abi::structs::*;
37use crate::abi::types::xmlAttributeDefault::*;
38use crate::abi::types::xmlAttributeType::*;
39use crate::abi::types::xmlElementContentOccur::*;
40use crate::abi::types::xmlElementContentType::*;
41use crate::abi::types::xmlElementType::*;
42use crate::abi::types::xmlElementTypeVal::*;
43use crate::abi::types::xmlEntityType::*;
44use crate::abi::types::*;
45use crate::xml::dtd;
46use crate::xml::entities;
47use crate::xml::hash;
48use crate::xml::string;
49use crate::xml::tree;
50
51const VALID_CTXT_DEPTH_MAX: c_int = 256;
57
58pub unsafe fn new_valid_ctxt() -> *mut _xmlValidCtxt {
72 let ctxt = allocator::xmlMallocZero(size_of::<_xmlValidCtxt>() as usize) as *mut _xmlValidCtxt;
74 if ctxt.is_null() {
75 return ptr::null_mut();
76 }
77
78 unsafe {
79 (*ctxt).valid = 1;
80 (*ctxt).node = ptr::null_mut();
81 (*ctxt).doc = ptr::null_mut();
82 (*ctxt).nodeNr = 0;
83 (*ctxt).nodeMax = 0;
84 (*ctxt).nodeTab = ptr::null_mut();
85 (*ctxt).flags = 0;
86 (*ctxt).vstate = ptr::null_mut();
87 (*ctxt).vstateNr = 0;
88 (*ctxt).vstateMax = 0;
89 (*ctxt).vstateTab = ptr::null_mut();
90 (*ctxt).am = ptr::null_mut();
91 (*ctxt).state = ptr::null_mut();
92 (*ctxt).error = None;
93 (*ctxt).warning = None;
94 (*ctxt).userData = ptr::null_mut();
95 }
96
97 ctxt
98}
99
100pub unsafe fn free_valid_ctxt(ctxt: *mut _xmlValidCtxt) {
112 if ctxt.is_null() {
113 return;
114 }
115
116 unsafe {
117 let c = &mut *ctxt;
118
119 if !c.nodeTab.is_null() {
121 allocator::xmlFreeImpl(c.nodeTab as *mut c_void);
122 }
123
124 if !c.am.is_null() {
126 }
129
130 if !c.state.is_null() {
132 }
134
135 allocator::xmlFreeImpl(ctxt as *mut c_void);
136 }
137}
138
139pub unsafe fn set_valid_errors(
155 ctxt: *mut _xmlValidCtxt,
156 err: Option<xmlGenericErrorFunc>,
157 warn: Option<xmlGenericErrorFunc>,
158 data: *mut c_void,
159) {
160 if ctxt.is_null() {
161 return;
162 }
163
164 unsafe {
165 (*ctxt).error = err;
168 (*ctxt).warning = warn;
169 (*ctxt).userData = data;
170 }
171}
172
173unsafe fn vctxt_error(ctxt: *mut _xmlValidCtxt, msg: *const c_char) {
184 if ctxt.is_null() {
185 return;
186 }
187 unsafe {
188 let c = &mut *ctxt;
189 c.valid = 0;
190 if let Some(err) = c.error {
191 err(c.userData, msg);
192 }
193 }
194}
195
196unsafe fn vctxt_push_node(ctxt: *mut _xmlValidCtxt, node: *mut _xmlNode) -> c_int {
204 unsafe {
205 let c = &mut *ctxt;
206
207 if c.nodeNr >= c.nodeMax {
208 let new_max = if c.nodeMax == 0 { 4 } else { c.nodeMax * 2 };
209 let new_tab = allocator::xmlReallocImpl(
210 c.nodeTab as *mut c_void,
211 (new_max as usize) * size_of::<*mut _xmlNode>(),
212 ) as *mut *mut _xmlNode;
213 if new_tab.is_null() {
214 return -1;
215 }
216 c.nodeTab = new_tab;
217 c.nodeMax = new_max;
218 }
219
220 *c.nodeTab.add(c.nodeNr as usize) = node;
221 c.nodeNr += 1;
222 c.node = node;
223 }
224 0
225}
226
227unsafe fn vctxt_pop_node(ctxt: *mut _xmlValidCtxt) {
233 unsafe {
234 let c = &mut *ctxt;
235 if c.nodeNr > 0 {
236 c.nodeNr -= 1;
237 }
238 if c.nodeNr > 0 {
239 c.node = *c.nodeTab.add((c.nodeNr - 1) as usize);
240 } else {
241 c.node = ptr::null_mut();
242 }
243 }
244}
245
246unsafe fn get_valid_dtd(doc: *mut _xmlDoc) -> *mut _xmlDtd {
254 if doc.is_null() {
255 return ptr::null_mut();
256 }
257 unsafe {
258 let d = &*doc;
259 if !d.intSubset.is_null() {
260 d.intSubset
261 } else {
262 d.extSubset
263 }
264 }
265}
266
267pub(crate) fn is_xml_name_start(c: char) -> bool {
281 matches!(c,
282 'a'..='z' | 'A'..='Z' | '_' | ':' |
283 '\u{C0}'..='\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' |
284 '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' |
285 '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' |
286 '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' |
287 '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' |
288 '\u{10000}'..='\u{EFFFF}'
289 )
290}
291
292pub(crate) fn is_xml_name_char(c: char) -> bool {
299 is_xml_name_start(c)
300 || matches!(c,
301 '-' | '.' | '0'..='9' | '\u{B7}' |
302 '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}'
303 )
304}
305
306pub unsafe fn validate_name(value: *const xmlChar) -> c_int {
324 if value.is_null() {
325 return 0;
326 }
327
328 let s = unsafe { string::xmlstr_to_bytes(value) };
329 let s = core::str::from_utf8(s).unwrap_or("");
330
331 if s.is_empty() {
332 return 0;
333 }
334
335 let mut chars = s.chars();
336
337 match chars.next() {
339 Some(c) if is_xml_name_start(c) => {}
340 _ => return 0,
341 }
342
343 for c in chars {
345 if !is_xml_name_char(c) {
346 return 0;
347 }
348 }
349
350 1
351}
352
353pub unsafe fn validate_names(value: *const xmlChar) -> c_int {
367 if value.is_null() {
368 return 0;
369 }
370
371 let s = unsafe { string::xmlstr_to_bytes(value) };
372 let s = core::str::from_utf8(s).unwrap_or("");
373
374 if s.is_empty() {
375 return 0;
376 }
377
378 for token in s.split_whitespace() {
379 if token.is_empty() {
380 return 0;
381 }
382 let mut chars = token.chars();
383 match chars.next() {
384 Some(c) if is_xml_name_start(c) => {}
385 _ => return 0,
386 }
387 for c in chars {
388 if !is_xml_name_char(c) {
389 return 0;
390 }
391 }
392 }
393
394 1
395}
396
397pub unsafe fn validate_nmtoken(value: *const xmlChar) -> c_int {
416 if value.is_null() {
417 return 0;
418 }
419
420 let s = unsafe { string::xmlstr_to_bytes(value) };
421 let s = core::str::from_utf8(s).unwrap_or("");
422
423 if s.is_empty() {
424 return 0;
425 }
426
427 for c in s.chars() {
428 if !is_xml_name_char(c) {
429 return 0;
430 }
431 }
432
433 1
434}
435
436pub unsafe fn validate_nmtokens(value: *const xmlChar) -> c_int {
450 if value.is_null() {
451 return 0;
452 }
453
454 let s = unsafe { string::xmlstr_to_bytes(value) };
455 let s = core::str::from_utf8(s).unwrap_or("");
456
457 if s.is_empty() {
458 return 0;
459 }
460
461 for token in s.split_whitespace() {
462 if token.is_empty() {
463 return 0;
464 }
465 for c in token.chars() {
466 if !is_xml_name_char(c) {
467 return 0;
468 }
469 }
470 }
471
472 1
473}
474
475pub unsafe fn validate_attribute_value(atype: c_int, value: *const xmlChar) -> c_int {
493 match atype as u32 {
497 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
498 validate_values_internal(value, 0)
499 }
500 t if t == XML_ATTRIBUTE_ENTITY as u32
501 || t == XML_ATTRIBUTE_IDREF as u32
502 || t == XML_ATTRIBUTE_ID as u32
503 || t == XML_ATTRIBUTE_NOTATION as u32 =>
504 {
505 validate_value_internal(value, 0)
506 }
507 t if t == XML_ATTRIBUTE_NMTOKENS as u32 || t == XML_ATTRIBUTE_ENUMERATION as u32 => {
508 validate_values_internal(value, XML_SCAN_NMTOKEN)
509 }
510 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => validate_value_internal(value, XML_SCAN_NMTOKEN),
511 _ => 1, }
513}
514
515pub unsafe fn validate_enumeration(
537 ctxt: *mut _xmlValidCtxt,
538 value: *const xmlChar,
539 tree: *mut _xmlEnumeration,
540) -> c_int {
541 if value.is_null() || tree.is_null() {
542 return 0;
543 }
544
545 let mut cur = tree;
546 while !cur.is_null() {
547 unsafe {
548 if string::xml_strcmp(value, (*cur).name) == 0 {
549 return 1;
550 }
551 cur = (*cur).next;
552 }
553 }
554
555 unsafe {
557 let msg = string::xmlstr_to_string(value);
558 let err_msg = format!("Value '{}' is not a valid enumeration value\0", msg);
559 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
560 }
561 0
562}
563
564pub unsafe fn validate_notation_use(
584 ctxt: *mut _xmlValidCtxt,
585 doc: *mut _xmlDoc,
586 notation_name: *const xmlChar,
587) -> c_int {
588 if notation_name.is_null() {
589 return 0;
590 }
591
592 let dtd = unsafe { get_valid_dtd(doc) };
593 if dtd.is_null() {
594 unsafe {
595 vctxt_error(
596 ctxt,
597 b"No DTD available for notation validation\0" as *const u8 as *const c_char,
598 );
599 }
600 return 0;
601 }
602
603 unsafe {
605 let notations = (*dtd).notations;
606 if notations.is_null() {
607 vctxt_error(
608 ctxt,
609 b"No notations declared in DTD\0" as *const u8 as *const c_char,
610 );
611 return 0;
612 }
613
614 let notation = hash::hash_lookup(notations as *mut hash::HashTable, notation_name);
615 if notation.is_null() {
616 let msg = string::xmlstr_to_string(notation_name);
617 let err_msg = format!("Notation '{}' is not declared\0", msg);
618 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
619 return 0;
620 }
621 }
622
623 1
624}
625
626pub unsafe fn validate_id(
648 ctxt: *mut _xmlValidCtxt,
649 doc: *mut _xmlDoc,
650 node: *mut _xmlNode,
651 value: *const xmlChar,
652) -> c_int {
653 if value.is_null() || doc.is_null() {
654 return 0;
655 }
656
657 if unsafe { validate_name_value(value) } == 0 {
660 unsafe {
661 let msg = string::xmlstr_to_string(value);
662 let err_msg = format!("ID value '{}' is not a valid XML Name\0", msg);
663 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
664 }
665 return 0;
666 }
667
668 unsafe {
670 let doc_ref = &*doc;
671 if !doc_ref.ids.is_null() {
672 let existing = hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value);
673 if !existing.is_null() {
674 let msg = string::xmlstr_to_string(value);
675 let err_msg = format!("Duplicate ID value '{}'\0", msg);
676 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
677 return 0;
678 }
679 }
680 }
681
682 unsafe {
684 if (*doc).ids.is_null() {
685 (*doc).ids = hash::hash_create(16) as *mut c_void;
686 }
687 hash::hash_add_entry(
688 (*doc).ids as *mut hash::HashTable,
689 value,
690 node as *mut c_void,
691 );
692 }
693
694 1
695}
696
697pub unsafe fn validate_id_ref(
714 ctxt: *mut _xmlValidCtxt,
715 doc: *mut _xmlDoc,
716 node: *mut _xmlNode,
717 value: *const xmlChar,
718) -> c_int {
719 if value.is_null() || doc.is_null() {
720 return 0;
721 }
722
723 if unsafe { validate_name_value(value) } == 0 {
726 unsafe {
727 let msg = string::xmlstr_to_string(value);
728 let err_msg = format!("IDREF value '{}' is not a valid XML Name\0", msg);
729 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
730 }
731 return 0;
732 }
733
734 unsafe {
736 let doc_ref = &*doc;
737 if doc_ref.ids.is_null()
738 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, value).is_null()
739 {
740 let msg = string::xmlstr_to_string(value);
744 let err_msg = format!("IDREF '{}' references an unknown ID\0", msg);
745 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
746 return 0;
747 }
748 }
749
750 1
751}
752
753pub unsafe fn validate_id_refs(
770 ctxt: *mut _xmlValidCtxt,
771 doc: *mut _xmlDoc,
772 node: *mut _xmlNode,
773 value: *const xmlChar,
774) -> c_int {
775 if value.is_null() || doc.is_null() {
776 return 0;
777 }
778
779 let s = unsafe { string::xmlstr_to_bytes(value) };
780 let s = core::str::from_utf8(s).unwrap_or("");
781
782 if s.is_empty() {
783 return 0;
784 }
785
786 let mut valid = 1;
787 for token in s.split_whitespace() {
788 if token.is_empty() {
789 continue;
790 }
791 let token_ptr = unsafe { string::bytes_to_xmlstr(token.as_bytes()) };
793 if token_ptr.is_null() {
794 valid = 0;
795 break;
796 }
797 let result = unsafe { validate_id_ref(ctxt, doc, node, token_ptr) };
798 unsafe {
799 allocator::xmlFreeImpl(token_ptr as *mut c_void);
800 }
801 if result == 0 {
802 valid = 0;
803 }
804 }
805
806 valid
807}
808
809pub unsafe fn validate_attribute_decl(
836 ctxt: *mut _xmlValidCtxt,
837 doc: *mut _xmlDoc,
838 elem: *mut _xmlNode,
839 attr: *mut _xmlAttribute,
840) -> c_int {
841 if attr.is_null() {
842 return 0;
843 }
844
845 unsafe {
846 let a = &*attr;
847 let atype = a.atype as c_int;
848
849 if !a.defaultValue.is_null() {
851 if validate_attribute_value(atype, a.defaultValue) == 0 {
852 let name_str = string::xmlstr_to_string(a.name);
853 let val_str = string::xmlstr_to_string(a.defaultValue);
854 let err_msg = format!(
855 "Default value '{}' for attribute '{}' is not valid for its type\0",
856 val_str, name_str
857 );
858 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
859 return 0;
860 }
861 }
862
863 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !a.tree.is_null() {
865 let mut cur = a.tree;
867 while !cur.is_null() {
868 if !(*cur).name.is_null() {
869 if validate_nmtoken_value((*cur).name) == 0 {
870 let val_str = string::xmlstr_to_string((*cur).name);
871 let err_msg =
872 format!("Enumeration value '{}' is not a valid NMTOKEN\0", val_str);
873 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
874 return 0;
875 }
876 }
877 cur = (*cur).next;
878 }
879 }
880
881 if atype == XML_ATTRIBUTE_NOTATION as c_int && !a.tree.is_null() {
883 let mut cur = a.tree;
884 while !cur.is_null() {
885 if !(*cur).name.is_null() {
886 if validate_notation_use(ctxt, doc, (*cur).name) == 0 {
887 let val_str = string::xmlstr_to_string((*cur).name);
888 let err_msg = format!(
889 "NOTATION value '{}' references undeclared notation\0",
890 val_str
891 );
892 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
893 return 0;
894 }
895 }
896 cur = (*cur).next;
897 }
898 }
899
900 1
901 }
902}
903
904pub unsafe fn validate_element(
933 ctxt: *mut _xmlValidCtxt,
934 doc: *mut _xmlDoc,
935 elem: *mut _xmlNode,
936) -> c_int {
937 if elem.is_null() || doc.is_null() || ctxt.is_null() {
938 return 0;
939 }
940
941 unsafe {
942 let e = &*elem;
943
944 if e.type_ != XML_ELEMENT_NODE as c_int {
946 return 1;
947 }
948
949 if vctxt_push_node(ctxt, elem) != 0 {
951 return 0;
952 }
953
954 let mut valid = 1;
955
956 let dtd = get_valid_dtd(doc);
958 if dtd.is_null() {
959 vctxt_pop_node(ctxt);
962 return 1;
963 }
964
965 let dtd_ref = &*dtd;
966
967 let elem_name = e.name;
969 let elem_decl = if !dtd_ref.elements.is_null() {
970 hash::hash_lookup(dtd_ref.elements as *mut hash::HashTable, elem_name)
971 } else {
972 ptr::null_mut()
973 };
974
975 if elem_decl.is_null() {
976 let name_str = string::xmlstr_to_string(elem_name);
977 let err_msg = format!("No declaration for element {}\0", name_str);
978 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
979 vctxt_pop_node(ctxt);
980 return 0;
981 }
982
983 let elem_decl_ref = &*(elem_decl as *mut _xmlElement);
984
985 let elem_type = elem_decl_ref.etype as u32;
987
988 if elem_type == XML_ELEMENT_TYPE_EMPTY as u32 {
989 let mut child = e.children;
991 while !child.is_null() {
992 let child_type = (*child).type_ as u32;
993 if child_type != XML_TEXT_NODE as u32 && child_type != XML_CDATA_SECTION_NODE as u32
994 {
995 valid = 0;
996 let name_str = string::xmlstr_to_string(elem_name);
997 let err_msg = format!(
998 "Element '{}' is declared EMPTY but has child elements\0",
999 name_str
1000 );
1001 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1002 break;
1003 }
1004 child = (*child).next;
1005 }
1006 } else if elem_type == XML_ELEMENT_TYPE_ANY as u32 {
1007 } else if elem_type == XML_ELEMENT_TYPE_MIXED as u32 {
1009 let mut child = e.children;
1011 while !child.is_null() {
1012 let child_type = (*child).type_ as u32;
1013 if child_type == XML_ELEMENT_NODE as u32 {
1014 let child_name = (*child).name;
1016 let result = dtd::valid_content_model(elem_decl_ref.content, &[child_name]);
1017 if result != dtd::ContentModelResult::Valid {
1018 let cname_str = string::xmlstr_to_string(child_name);
1019 let ename_str = string::xmlstr_to_string(elem_name);
1020 let err_msg = format!(
1021 "Element '{}' is not allowed in mixed content of '{}'\0",
1022 cname_str, ename_str
1023 );
1024 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1025 valid = 0;
1026 }
1027 }
1028 child = (*child).next;
1029 }
1030 } else if elem_type == XML_ELEMENT_TYPE_ELEMENT as u32 {
1031 let mut child_names: Vec<*const xmlChar> = Vec::new();
1033 let mut child = e.children;
1034 while !child.is_null() {
1035 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1036 child_names.push((*child).name);
1037 }
1038 child = (*child).next;
1039 }
1040
1041 let result = dtd::valid_content_model(elem_decl_ref.content, &child_names);
1042 if result != dtd::ContentModelResult::Valid {
1043 let ename_str = string::xmlstr_to_string(elem_name);
1044 let err_msg = format!(
1045 "Content model validation failed for element '{}'\0",
1046 ename_str
1047 );
1048 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1049 valid = 0;
1050 }
1051 }
1052
1053 if !dtd_ref.attributes.is_null() {
1055 let mut attr_prop = e.properties;
1057 while !attr_prop.is_null() {
1058 let attr_ref = &*attr_prop;
1059 let attr_name = attr_ref.name;
1060
1061 let attr_decl = hash::hash_lookup3(
1064 dtd_ref.attributes as *mut hash::HashTable,
1065 attr_name,
1066 ptr::null(),
1067 elem_name,
1068 );
1069
1070 if attr_decl.is_null() {
1071 attr_prop = attr_ref.next;
1076 continue;
1077 }
1078
1079 let attr_decl_ref = &*(attr_decl as *mut _xmlAttribute);
1080 let atype = attr_decl_ref.atype as c_int;
1081
1082 let attr_value = if !attr_ref.children.is_null() {
1084 let text_node = attr_ref.children;
1086 if (*text_node).type_ == XML_TEXT_NODE as c_int
1087 || (*text_node).type_ == XML_CDATA_SECTION_NODE as c_int
1088 {
1089 (*text_node).content
1090 } else {
1091 ptr::null()
1092 }
1093 } else {
1094 ptr::null()
1095 };
1096
1097 if !attr_value.is_null() {
1099 if atype == XML_ATTRIBUTE_ENUMERATION as c_int && !attr_decl_ref.tree.is_null()
1100 {
1101 if validate_enumeration(ctxt, attr_value, attr_decl_ref.tree) == 0 {
1102 let aname_str = string::xmlstr_to_string(attr_name);
1103 let aval_str = string::xmlstr_to_string(attr_value);
1104 let err_msg = format!(
1105 "Attribute '{}' has value '{}' not in enumeration\0",
1106 aname_str, aval_str
1107 );
1108 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1109 valid = 0;
1110 }
1111 } else if atype == XML_ATTRIBUTE_NOTATION as c_int {
1112 if validate_notation_use(ctxt, doc, attr_value) == 0 {
1113 let aname_str = string::xmlstr_to_string(attr_name);
1114 let aval_str = string::xmlstr_to_string(attr_value);
1115 let err_msg = format!(
1116 "Attribute '{}' references undeclared notation '{}'\0",
1117 aname_str, aval_str
1118 );
1119 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1120 valid = 0;
1121 }
1122 } else if validate_attribute_value(atype, attr_value) == 0 {
1123 let aname_str = string::xmlstr_to_string(attr_name);
1124 let aval_str = string::xmlstr_to_string(attr_value);
1125 let err_msg = format!(
1126 "Attribute '{}' has invalid value '{}' for its type\0",
1127 aname_str, aval_str
1128 );
1129 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1130 valid = 0;
1131 }
1132
1133 if atype == XML_ATTRIBUTE_ID as c_int {
1135 if validate_id(ctxt, doc, elem, attr_value) == 0 {
1136 valid = 0;
1137 }
1138 } else if atype == XML_ATTRIBUTE_IDREF as c_int {
1139 if validate_id_ref(ctxt, doc, elem, attr_value) == 0 {
1140 valid = 0;
1141 }
1142 } else if atype == XML_ATTRIBUTE_IDREFS as c_int {
1143 if validate_id_refs(ctxt, doc, elem, attr_value) == 0 {
1144 valid = 0;
1145 }
1146 }
1147 }
1148
1149 attr_prop = attr_ref.next;
1150 }
1151
1152 struct RequiredAttrCheck {
1154 ctxt: *mut _xmlValidCtxt,
1155 elem_name: *const xmlChar,
1156 elem_props: *mut _xmlAttr,
1157 valid: *mut c_int,
1158 }
1159
1160 extern "C" fn check_required_attr(
1161 payload: *mut c_void,
1162 data: *mut c_void,
1163 name: *const xmlChar,
1164 name2: *const xmlChar,
1165 _name3: *const xmlChar,
1166 ) {
1167 if payload.is_null() || data.is_null() || name2.is_null() {
1168 return;
1169 }
1170
1171 let check = unsafe { &*(data as *mut RequiredAttrCheck) };
1173 unsafe {
1174 if string::xml_strcmp(name, check.elem_name) != 0 {
1176 return;
1177 }
1178
1179 let attr_decl = &*(payload as *mut _xmlAttribute);
1180
1181 if attr_decl.def == XML_ATTRIBUTE_REQUIRED as c_int {
1183 let mut found = 0;
1185 let mut prop = check.elem_props;
1186 while !prop.is_null() {
1187 if string::xml_strcmp((*prop).name, name2) == 0 {
1188 found = 1;
1189 break;
1190 }
1191 prop = (*prop).next;
1192 }
1193
1194 if found == 0 {
1195 let aname_str = string::xmlstr_to_string(name2);
1196 let ename_str = string::xmlstr_to_string(check.elem_name);
1197 let err_msg = format!(
1198 "Required attribute '{}' missing on element '{}'\0",
1199 aname_str, ename_str
1200 );
1201 vctxt_error(check.ctxt, err_msg.as_ptr() as *const c_char);
1202 *(check.valid) = 0;
1203 }
1204 }
1205 }
1206 }
1207
1208 let mut required_valid = valid;
1209 let check = RequiredAttrCheck {
1210 ctxt,
1211 elem_name,
1212 elem_props: e.properties,
1213 valid: &mut required_valid,
1214 };
1215
1216 hash::hash_scan_full(
1217 dtd_ref.attributes as *mut hash::HashTable,
1218 Some(check_required_attr),
1219 &check as *const RequiredAttrCheck as *mut c_void,
1220 );
1221
1222 valid = required_valid;
1223 }
1224
1225 let mut child = e.children;
1227 while !child.is_null() {
1228 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1229 if validate_element(ctxt, doc, child) == 0 {
1230 valid = 0;
1231 }
1232 }
1233 child = (*child).next;
1234 }
1235
1236 vctxt_pop_node(ctxt);
1237 valid
1238 }
1239}
1240
1241pub unsafe fn validate_document(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1261 if ctxt.is_null() || doc.is_null() {
1262 return 0;
1263 }
1264
1265 unsafe {
1266 let c = &mut *ctxt;
1267 c.doc = doc;
1268 c.valid = 1;
1269
1270 let d = &*doc;
1271
1272 if d.intSubset.is_null() && d.extSubset.is_null() {
1282 vctxt_error(ctxt, b"no DTD found!\0" as *const u8 as *const c_char);
1283 return 0;
1284 }
1285
1286 let mut root = d.children;
1288 while !root.is_null() {
1289 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1290 break;
1291 }
1292 root = (*root).next;
1293 }
1294
1295 if root.is_null() {
1296 vctxt_error(
1297 ctxt,
1298 b"No root element found in document\0" as *const u8 as *const c_char,
1299 );
1300 return 0;
1301 }
1302
1303 if validate_element(ctxt, doc, root) == 0 {
1305 return 0;
1306 }
1307
1308 c.valid
1309 }
1310}
1311
1312pub unsafe fn validate_document_final(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1334 if ctxt.is_null() || doc.is_null() {
1335 return 0;
1336 }
1337
1338 unsafe {
1339 let c = &mut *ctxt;
1340 c.doc = doc;
1341
1342 let d = &*doc;
1343
1344 if d.refs.is_null() {
1346 return c.valid;
1347 }
1348
1349 struct IdRefCheckContext {
1351 ctxt: *mut _xmlValidCtxt,
1352 doc: *mut _xmlDoc,
1353 }
1354
1355 extern "C" fn check_idref(
1356 _payload: *mut c_void,
1357 data: *mut c_void,
1358 _name: *const xmlChar,
1359 name2: *const xmlChar,
1360 _name3: *const xmlChar,
1361 ) {
1362 if data.is_null() || name2.is_null() {
1363 return;
1364 }
1365
1366 let cx = unsafe { &*(data as *mut IdRefCheckContext) };
1368 unsafe {
1369 let doc_ref = &*cx.doc;
1370
1371 if doc_ref.ids.is_null()
1373 || hash::hash_lookup(doc_ref.ids as *mut hash::HashTable, name2).is_null()
1374 {
1375 let ref_str = string::xmlstr_to_string(name2);
1376 let err_msg = format!("IDREF '{}' does not reference a declared ID\0", ref_str);
1377 vctxt_error(cx.ctxt, err_msg.as_ptr() as *const c_char);
1378 }
1379 }
1380 }
1381
1382 let ctx = IdRefCheckContext { ctxt, doc };
1383 hash::hash_scan_full(
1384 d.refs as *mut hash::HashTable,
1385 Some(check_idref),
1386 &ctx as *const IdRefCheckContext as *mut c_void,
1387 );
1388
1389 c.valid
1390 }
1391}
1392
1393pub unsafe fn validate_root(ctxt: *mut _xmlValidCtxt, doc: *mut _xmlDoc) -> c_int {
1411 if ctxt.is_null() || doc.is_null() {
1412 return 0;
1413 }
1414
1415 unsafe {
1416 let c = &mut *ctxt;
1417 c.doc = doc;
1418 c.valid = 1;
1419
1420 let d = &*doc;
1421
1422 let mut root = d.children;
1424 while !root.is_null() {
1425 if (*root).type_ == XML_ELEMENT_NODE as c_int {
1426 break;
1427 }
1428 root = (*root).next;
1429 }
1430
1431 if root.is_null() {
1432 vctxt_error(
1433 ctxt,
1434 b"No root element found\0" as *const u8 as *const c_char,
1435 );
1436 return 0;
1437 }
1438
1439 let dtd = get_valid_dtd(doc);
1441 if dtd.is_null() {
1442 return 1;
1444 }
1445
1446 let dtd_ref = &*dtd;
1449 if !dtd_ref.name.is_null() {
1450 if string::xml_strcmp((*root).name, dtd_ref.name) != 0 {
1451 let root_str = string::xmlstr_to_string((*root).name);
1452 let dtd_str = string::xmlstr_to_string(dtd_ref.name);
1453 let err_msg = format!(
1454 "Root element '{}' does not match DTD root '{}'\0",
1455 root_str, dtd_str
1456 );
1457 vctxt_error(ctxt, err_msg.as_ptr() as *const c_char);
1458 return 0;
1459 }
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; fn is_blank_byte(b: u8) -> bool {
1857 b == b' ' || b == b'\t' || b == b'\n' || b == b'\r'
1858}
1859
1860fn 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
2439unsafe 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 unsafe { 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 unsafe fn validate_notation_decl(
3044 _ctxt: *mut _xmlValidCtxt,
3045 _doc: *mut _xmlDoc,
3046 _nota: *mut _xmlNotation,
3047) -> c_int {
3048 1
3049}
3050
3051pub unsafe fn validate_one_attribute(
3061 ctxt: *mut _xmlValidCtxt,
3062 doc: *mut _xmlDoc,
3063 elem: *mut _xmlNode,
3064 attr: *mut _xmlAttr,
3065 value: *const xmlChar,
3066) -> c_int {
3067 unsafe {
3068 if doc.is_null() {
3069 return 0;
3070 }
3071 if elem.is_null() || (*elem).name.is_null() {
3072 return 0;
3073 }
3074 if attr.is_null() || (*attr).name.is_null() {
3075 return 0;
3076 }
3077 let mut ret = 1;
3078
3079 let aprefix = if !(*attr).ns.is_null() {
3080 (*(*attr).ns).prefix
3081 } else {
3082 ptr::null()
3083 };
3084
3085 let mut attr_decl = ptr::null_mut();
3086 if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3087 let fullname =
3088 string::build_qname((*elem).name, (*(*elem).ns).prefix, ptr::null_mut(), 0);
3089 if fullname.is_null() {
3090 vctxt_error(
3091 ctxt,
3092 b"Memory allocation failed : xmlValidateOneAttribute\0" as *const u8
3093 as *const c_char,
3094 );
3095 return 0;
3096 }
3097 attr_decl = get_dtd_qattr_desc((*doc).intSubset, fullname, (*attr).name, aprefix);
3098 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3099 attr_decl = get_dtd_qattr_desc((*doc).extSubset, fullname, (*attr).name, aprefix);
3100 }
3101 if fullname != (*elem).name as *mut xmlChar {
3102 allocator::xmlFreeImpl(fullname as *mut c_void);
3103 }
3104 }
3105 if attr_decl.is_null() {
3106 attr_decl = get_dtd_qattr_desc((*doc).intSubset, (*elem).name, (*attr).name, aprefix);
3107 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3108 attr_decl =
3109 get_dtd_qattr_desc((*doc).extSubset, (*elem).name, (*attr).name, aprefix);
3110 }
3111 }
3112
3113 if attr_decl.is_null() {
3115 let msg = format!(
3116 "No declaration for attribute {} of element {}\0",
3117 string::xmlstr_to_string((*attr).name),
3118 string::xmlstr_to_string((*elem).name)
3119 );
3120 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3121 return 0;
3122 }
3123 if !(*attr).id.is_null() {
3124 remove_id(doc, attr);
3125 }
3126 (*attr).atype = (*attr_decl).atype;
3127
3128 let val = if (*doc).properties & crate::abi::types::xmlDocProperties::XML_DOC_OLD10 as c_int
3130 != 0
3131 {
3132 match (*attr_decl).atype as u32 {
3135 t if t == XML_ATTRIBUTE_ENTITIES as u32 || t == XML_ATTRIBUTE_IDREFS as u32 => {
3136 validate_values_internal(value, 0)
3137 }
3138 t if t == XML_ATTRIBUTE_ENTITY as u32
3139 || t == XML_ATTRIBUTE_IDREF as u32
3140 || t == XML_ATTRIBUTE_ID as u32
3141 || t == XML_ATTRIBUTE_NOTATION as u32 =>
3142 {
3143 validate_value_internal(value, 0)
3144 }
3145 t if t == XML_ATTRIBUTE_NMTOKENS as u32
3146 || t == XML_ATTRIBUTE_ENUMERATION as u32 =>
3147 {
3148 validate_values_internal(value, XML_SCAN_NMTOKEN)
3149 }
3150 t if t == XML_ATTRIBUTE_NMTOKEN as u32 => {
3151 validate_value_internal(value, XML_SCAN_NMTOKEN)
3152 }
3153 _ => 1,
3154 }
3155 } else {
3156 validate_attribute_value((*attr_decl).atype, value)
3157 };
3158 if val == 0 {
3159 let msg = format!(
3160 "Syntax of value for attribute {} of {} is not valid\0",
3161 string::xmlstr_to_string((*attr).name),
3162 string::xmlstr_to_string((*elem).name)
3163 );
3164 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3165 ret = 0;
3166 }
3167
3168 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int {
3170 if string::xml_strcmp(value, (*attr_decl).defaultValue) != 0 {
3171 let msg = format!(
3172 "Value for attribute {} of {} is different from default \"{}\n\0",
3173 string::xmlstr_to_string((*attr).name),
3174 string::xmlstr_to_string((*elem).name),
3175 string::xmlstr_to_string((*attr_decl).defaultValue)
3176 );
3177 let msg = format!(
3179 "Value for attribute {} of {} is different from default \"{}\"\0",
3180 string::xmlstr_to_string((*attr).name),
3181 string::xmlstr_to_string((*elem).name),
3182 string::xmlstr_to_string((*attr_decl).defaultValue)
3183 );
3184 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3185 ret = 0;
3186 }
3187 }
3188
3189 const XML_VCTXT_IN_ENTITY: c_uint = 4; if (*attr_decl).atype == XML_ATTRIBUTE_ID as c_int
3192 && (ctxt.is_null() || (*ctxt).flags & XML_VCTXT_IN_ENTITY == 0)
3193 {
3194 if add_id(ctxt, doc, value, attr).is_null() {
3195 ret = 0;
3196 }
3197 }
3198 if (*attr_decl).atype == XML_ATTRIBUTE_IDREF as c_int
3199 || (*attr_decl).atype == XML_ATTRIBUTE_IDREFS as c_int
3200 {
3201 if add_ref(ctxt, doc, value, attr).is_null() {
3202 ret = 0;
3203 }
3204 }
3205
3206 if (*attr_decl).atype == XML_ATTRIBUTE_NOTATION as c_int {
3208 let mut nota = get_dtd_notation_desc((*doc).intSubset, value);
3209 if nota.is_null() {
3210 nota = get_dtd_notation_desc((*doc).extSubset, value);
3211 }
3212 if nota.is_null() {
3213 let msg = format!(
3214 "Value \"{}\" for attribute {} of {} is not a declared Notation\0",
3215 string::xmlstr_to_string(value),
3216 string::xmlstr_to_string((*attr).name),
3217 string::xmlstr_to_string((*elem).name)
3218 );
3219 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3220 ret = 0;
3221 }
3222 let mut tree = (*attr_decl).tree;
3223 while !tree.is_null() {
3224 if string::xml_strcmp((*tree).name, value) == 0 {
3225 break;
3226 }
3227 tree = (*tree).next;
3228 }
3229 if tree.is_null() {
3230 let msg = format!(
3231 "Value \"{}\" for attribute {} of {} is not among the enumerated notations\0",
3232 string::xmlstr_to_string(value),
3233 string::xmlstr_to_string((*attr).name),
3234 string::xmlstr_to_string((*elem).name)
3235 );
3236 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3237 ret = 0;
3238 }
3239 }
3240
3241 if (*attr_decl).atype == XML_ATTRIBUTE_ENUMERATION as c_int {
3243 let mut tree = (*attr_decl).tree;
3244 while !tree.is_null() {
3245 if string::xml_strcmp((*tree).name, value) == 0 {
3246 break;
3247 }
3248 tree = (*tree).next;
3249 }
3250 if tree.is_null() {
3251 let msg = format!(
3252 "Value \"{}\" for attribute {} of {} is not among the enumerated set\0",
3253 string::xmlstr_to_string(value),
3254 string::xmlstr_to_string((*attr).name),
3255 string::xmlstr_to_string((*elem).name)
3256 );
3257 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3258 ret = 0;
3259 }
3260 }
3261
3262 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3264 && string::xml_strcmp((*attr_decl).defaultValue, value) != 0
3265 {
3266 let msg = format!(
3267 "Value for attribute {} of {} must be \"{}\"\0",
3268 string::xmlstr_to_string((*attr).name),
3269 string::xmlstr_to_string((*elem).name),
3270 string::xmlstr_to_string((*attr_decl).defaultValue)
3271 );
3272 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3273 ret = 0;
3274 }
3275
3276 if (*attr_decl).atype == XML_ATTRIBUTE_ENTITY as c_int {
3278 let ent = tree::get_doc_entity(doc, value);
3279 if ent.is_null() {
3280 let msg = format!(
3281 "ENTITY attribute {} reference an unknown entity \"{}\"\0",
3282 string::xmlstr_to_string((*attr).name),
3283 string::xmlstr_to_string(value)
3284 );
3285 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3286 ret = 0;
3287 } else if (*ent).etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3288 let msg = format!(
3289 "ENTITY attribute {} reference an entity \"{}\" of wrong type\0",
3290 string::xmlstr_to_string((*attr).name),
3291 string::xmlstr_to_string(value)
3292 );
3293 vctxt_error_node(ctxt, doc as *mut _xmlNode, msg.as_ptr() as *const c_char);
3294 ret = 0;
3295 }
3296 }
3297 ret
3298 }
3299}
3300
3301pub unsafe fn validate_one_namespace(
3308 ctxt: *mut _xmlValidCtxt,
3309 doc: *mut _xmlDoc,
3310 elem: *mut _xmlNode,
3311 prefix: *const xmlChar,
3312 ns: *mut _xmlNs,
3313 value: *const xmlChar,
3314) -> c_int {
3315 unsafe {
3316 if doc.is_null() {
3317 return 0;
3318 }
3319 if elem.is_null() || (*elem).name.is_null() {
3320 return 0;
3321 }
3322 if ns.is_null() || (*ns).href.is_null() {
3323 return 0;
3324 }
3325 let mut ret = 1;
3326
3327 let mut attr_decl = ptr::null_mut();
3328 if !prefix.is_null() {
3329 let fullname = string::build_qname((*elem).name, prefix, ptr::null_mut(), 0);
3330 if fullname.is_null() {
3331 vctxt_error(
3332 ctxt,
3333 b"Memory allocation failed : xmlValidateOneNamespace\0" as *const u8
3334 as *const c_char,
3335 );
3336 return 0;
3337 }
3338 if !(*ns).prefix.is_null() {
3339 attr_decl = get_dtd_qattr_desc(
3340 (*doc).intSubset,
3341 fullname,
3342 (*ns).prefix,
3343 b"xmlns\0" as *const u8 as *const xmlChar,
3344 );
3345 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3346 attr_decl = get_dtd_qattr_desc(
3347 (*doc).extSubset,
3348 fullname,
3349 (*ns).prefix,
3350 b"xmlns\0" as *const u8 as *const xmlChar,
3351 );
3352 }
3353 } else {
3354 attr_decl = get_dtd_qattr_desc(
3355 (*doc).intSubset,
3356 fullname,
3357 b"xmlns\0" as *const u8 as *const xmlChar,
3358 ptr::null(),
3359 );
3360 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3361 attr_decl = get_dtd_qattr_desc(
3362 (*doc).extSubset,
3363 fullname,
3364 b"xmlns\0" as *const u8 as *const xmlChar,
3365 ptr::null(),
3366 );
3367 }
3368 }
3369 if fullname != (*elem).name as *mut xmlChar {
3370 allocator::xmlFreeImpl(fullname as *mut c_void);
3371 }
3372 }
3373 if attr_decl.is_null() {
3374 if !(*ns).prefix.is_null() {
3375 attr_decl = get_dtd_qattr_desc(
3376 (*doc).intSubset,
3377 (*elem).name,
3378 (*ns).prefix,
3379 b"xmlns\0" as *const u8 as *const xmlChar,
3380 );
3381 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3382 attr_decl = get_dtd_qattr_desc(
3383 (*doc).extSubset,
3384 (*elem).name,
3385 (*ns).prefix,
3386 b"xmlns\0" as *const u8 as *const xmlChar,
3387 );
3388 }
3389 } else {
3390 attr_decl = get_dtd_qattr_desc(
3391 (*doc).intSubset,
3392 (*elem).name,
3393 b"xmlns\0" as *const u8 as *const xmlChar,
3394 ptr::null(),
3395 );
3396 if attr_decl.is_null() && !(*doc).extSubset.is_null() {
3397 attr_decl = get_dtd_qattr_desc(
3398 (*doc).extSubset,
3399 (*elem).name,
3400 b"xmlns\0" as *const u8 as *const xmlChar,
3401 ptr::null(),
3402 );
3403 }
3404 }
3405 }
3406
3407 if attr_decl.is_null() {
3409 let msg = if !(*ns).prefix.is_null() {
3410 format!(
3411 "No declaration for attribute xmlns:{} of element {}\0",
3412 string::xmlstr_to_string((*ns).prefix),
3413 string::xmlstr_to_string((*elem).name)
3414 )
3415 } else {
3416 format!(
3417 "No declaration for attribute xmlns of element {}\0",
3418 string::xmlstr_to_string((*elem).name)
3419 )
3420 };
3421 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3422 return 0;
3423 }
3424
3425 let val = validate_attribute_value((*attr_decl).atype, value);
3426 if val == 0 {
3427 let msg = if !(*ns).prefix.is_null() {
3428 format!(
3429 "Syntax of value for attribute xmlns:{} of {} is not valid\0",
3430 string::xmlstr_to_string((*ns).prefix),
3431 string::xmlstr_to_string((*elem).name)
3432 )
3433 } else {
3434 format!(
3435 "Syntax of value for attribute xmlns of {} is not valid\0",
3436 string::xmlstr_to_string((*elem).name)
3437 )
3438 };
3439 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3440 ret = 0;
3441 }
3442
3443 if (*attr_decl).def == XML_ATTRIBUTE_FIXED as c_int
3445 && string::xml_strcmp(value, (*attr_decl).defaultValue) != 0
3446 {
3447 let msg = if !(*ns).prefix.is_null() {
3448 format!(
3449 "Value for attribute xmlns:{} of {} is different from default \"{}\"\0",
3450 string::xmlstr_to_string((*ns).prefix),
3451 string::xmlstr_to_string((*elem).name),
3452 string::xmlstr_to_string((*attr_decl).defaultValue)
3453 )
3454 } else {
3455 format!(
3456 "Value for attribute xmlns of {} is different from default \"{}\"\0",
3457 string::xmlstr_to_string((*elem).name),
3458 string::xmlstr_to_string((*attr_decl).defaultValue)
3459 )
3460 };
3461 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3462 ret = 0;
3463 }
3464 ret
3465 }
3466}
3467
3468pub unsafe fn validate_one_element(
3476 ctxt: *mut _xmlValidCtxt,
3477 doc: *mut _xmlDoc,
3478 elem: *mut _xmlNode,
3479) -> c_int {
3480 unsafe {
3481 if doc.is_null() {
3482 return 0;
3483 }
3484 if elem.is_null() {
3485 return 0;
3486 }
3487 match (*elem).type_ {
3488 t if t == XML_TEXT_NODE as c_int
3489 || t == XML_CDATA_SECTION_NODE as c_int
3490 || t == XML_ENTITY_REF_NODE as c_int
3491 || t == XML_PI_NODE as c_int
3492 || t == XML_COMMENT_NODE as c_int
3493 || t == XML_XINCLUDE_START as c_int
3494 || t == XML_XINCLUDE_END as c_int =>
3495 {
3496 return 1;
3497 }
3498 t if t == XML_ELEMENT_NODE as c_int => {}
3499 _ => {
3500 vctxt_error_node(
3501 ctxt,
3502 elem,
3503 b"unexpected element type\0" as *const u8 as *const c_char,
3504 );
3505 return 0;
3506 }
3507 }
3508
3509 let mut ret = 1;
3510 let mut extsubset = 0;
3511 let elem_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
3512 if elem_decl.is_null() {
3513 return 0;
3514 }
3515
3516 if (*ctxt).vstateNr == 0 {
3519 match (*elem_decl).etype as u32 {
3520 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => {
3521 let msg = format!(
3522 "No declaration for element {}\0",
3523 string::xmlstr_to_string((*elem).name)
3524 );
3525 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3526 return 0;
3527 }
3528 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
3529 if !(*elem).children.is_null() {
3530 let msg = format!(
3531 "Element {} was declared EMPTY this one has content\0",
3532 string::xmlstr_to_string((*elem).name)
3533 );
3534 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3535 ret = 0;
3536 }
3537 }
3538 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
3539 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
3540 if !(*elem_decl).content.is_null()
3541 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
3542 {
3543 let mut child = (*elem).children;
3545 while !child.is_null() {
3546 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3547 let msg = format!(
3548 "Element {} was declared #PCDATA but contains non text nodes\0",
3549 string::xmlstr_to_string((*elem).name)
3550 );
3551 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3552 ret = 0;
3553 break;
3554 }
3555 child = (*child).next;
3556 }
3557 } else {
3558 let mut child = (*elem).children;
3560 while !child.is_null() {
3561 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3562 let mut fullname = (*child).name;
3563 let mut own = false;
3564 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3565 let fnp = string::build_qname(
3566 (*child).name,
3567 (*(*child).ns).prefix,
3568 ptr::null_mut(),
3569 0,
3570 );
3571 if fnp.is_null() {
3572 vctxt_error(
3573 ctxt,
3574 b"Memory allocation failed : xmlValidateOneElement\0"
3575 as *const u8
3576 as *const c_char,
3577 );
3578 return 0;
3579 }
3580 fullname = fnp;
3581 own = true;
3582 }
3583 if validate_check_mixed(ctxt, (*elem_decl).content, fullname) != 1 {
3584 let msg = format!(
3585 "Element {} is not declared in {} list of possible children\0",
3586 string::xmlstr_to_string(fullname),
3587 string::xmlstr_to_string((*elem).name)
3588 );
3589 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3590 ret = 0;
3591 }
3592 if own {
3593 allocator::xmlFreeImpl(fullname as *mut c_void);
3594 }
3595 }
3596 child = (*child).next;
3597 }
3598 }
3599 }
3600 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
3601 let mut names: Vec<*const xmlChar> = Vec::new();
3604 let mut owned: Vec<*mut xmlChar> = Vec::new();
3605 let mut child = (*elem).children;
3606 while !child.is_null() {
3607 if (*child).type_ == XML_ELEMENT_NODE as c_int {
3608 let mut fullname = (*child).name;
3609 if !(*child).ns.is_null() && !(*(*child).ns).prefix.is_null() {
3610 let fnp = string::build_qname(
3611 (*child).name,
3612 (*(*child).ns).prefix,
3613 ptr::null_mut(),
3614 0,
3615 );
3616 if !fnp.is_null() {
3617 fullname = fnp;
3618 owned.push(fnp);
3619 }
3620 }
3621 names.push(fullname);
3622 }
3623 child = (*child).next;
3624 }
3625 let result = dtd::valid_content_model((*elem_decl).content, &names);
3626 for n in owned {
3627 allocator::xmlFreeImpl(n as *mut c_void);
3628 }
3629 if result != dtd::ContentModelResult::Valid {
3630 let msg = format!(
3631 "Element {} content does not follow the DTD\0",
3632 string::xmlstr_to_string((*elem).name)
3633 );
3634 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3635 ret = 0;
3636 }
3637 }
3638 _ => {}
3639 }
3640
3641 let mut attr = (*elem).properties;
3643 while !attr.is_null() {
3644 let aval = if !(*attr).children.is_null() {
3645 (*(*attr).children).content
3646 } else {
3647 ptr::null()
3648 };
3649 if validate_one_attribute(ctxt, doc, elem, attr, aval) == 0 {
3650 ret = 0;
3651 }
3652 attr = (*attr).next;
3653 }
3654 }
3655 ret
3656 }
3657}
3658
3659#[repr(C)]
3674struct ValidState {
3675 elem_decl: *mut _xmlElement,
3676 node: *mut _xmlNode,
3677 exec: *mut ContentModelExec,
3678}
3679
3680unsafe fn valid_get_elem_decl(
3683 ctxt: *mut _xmlValidCtxt,
3684 doc: *mut _xmlDoc,
3685 elem: *mut _xmlNode,
3686 extsubset: *mut c_int,
3687) -> *mut _xmlElement {
3688 unsafe {
3689 if ctxt.is_null() || doc.is_null() || elem.is_null() || (*elem).name.is_null() {
3690 return ptr::null_mut();
3691 }
3692 if !extsubset.is_null() {
3693 *extsubset = 0;
3694 }
3695 let mut elem_decl = ptr::null_mut();
3696
3697 let prefix = if !(*elem).ns.is_null() && !(*(*elem).ns).prefix.is_null() {
3698 (*(*elem).ns).prefix
3699 } else {
3700 ptr::null()
3701 };
3702 if !prefix.is_null() {
3703 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, prefix);
3704 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3705 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, prefix);
3706 if !elem_decl.is_null() && !extsubset.is_null() {
3707 *extsubset = 1;
3708 }
3709 }
3710 }
3711 if elem_decl.is_null() {
3712 elem_decl = get_dtd_qelement_desc((*doc).intSubset, (*elem).name, ptr::null());
3714 if elem_decl.is_null() && !(*doc).extSubset.is_null() {
3715 elem_decl = get_dtd_qelement_desc((*doc).extSubset, (*elem).name, ptr::null());
3716 if !elem_decl.is_null() && !extsubset.is_null() {
3717 *extsubset = 1;
3718 }
3719 }
3720 }
3721 if elem_decl.is_null() {
3722 let msg = format!(
3723 "No declaration for element {}\0",
3724 string::xmlstr_to_string((*elem).name)
3725 );
3726 vctxt_error_node(ctxt, elem, msg.as_ptr() as *const c_char);
3727 }
3728 elem_decl
3729 }
3730}
3731
3732unsafe fn validate_check_mixed(
3734 ctxt: *mut _xmlValidCtxt,
3735 cont: *mut _xmlElementContent,
3736 qname: *const xmlChar,
3737) -> c_int {
3738 unsafe {
3739 let mut plen: c_int = 0;
3740 let has_colon = string::split_qname3(qname, &mut plen) != 0;
3741 let local = if has_colon {
3745 qname.add(plen as usize + 1)
3746 } else {
3747 ptr::null()
3748 };
3749 let mut cur = cont;
3750 if local.is_null() {
3751 while !cur.is_null() {
3752 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3753 if (*cur).prefix.is_null() && string::xml_strcmp((*cur).name, qname) == 0 {
3754 return 1;
3755 }
3756 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3757 && !(*cur).c1.is_null()
3758 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3759 {
3760 if (*(*cur).c1).prefix.is_null()
3761 && string::xml_strcmp((*(*cur).c1).name, qname) == 0
3762 {
3763 return 1;
3764 }
3765 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3766 || (*cur).c1.is_null()
3767 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3768 {
3769 vctxt_error(
3770 ctxt,
3771 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3772 );
3773 break;
3774 }
3775 cur = (*cur).c2;
3776 }
3777 } else {
3778 while !cur.is_null() {
3779 if (*cur).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int {
3780 if !(*cur).prefix.is_null()
3781 && prefix_matches((*cur).prefix, qname, plen)
3782 && string::xml_strcmp((*cur).name, local) == 0
3783 {
3784 return 1;
3785 }
3786 } else if (*cur).type_ == XML_ELEMENT_CONTENT_OR as c_int
3787 && !(*cur).c1.is_null()
3788 && (*(*cur).c1).type_ == XML_ELEMENT_CONTENT_ELEMENT as c_int
3789 {
3790 if !(*(*cur).c1).prefix.is_null()
3791 && prefix_matches((*(*cur).c1).prefix, qname, plen)
3792 && string::xml_strcmp((*(*cur).c1).name, local) == 0
3793 {
3794 return 1;
3795 }
3796 } else if (*cur).type_ != XML_ELEMENT_CONTENT_OR as c_int
3797 || (*cur).c1.is_null()
3798 || (*(*cur).c1).type_ != XML_ELEMENT_CONTENT_PCDATA as c_int
3799 {
3800 vctxt_error(
3801 ctxt,
3802 b"Internal: MIXED struct corrupted\0" as *const u8 as *const c_char,
3803 );
3804 break;
3805 }
3806 cur = (*cur).c2;
3807 }
3808 }
3809 0
3810 }
3811}
3812
3813unsafe fn prefix_matches(prefix: *const xmlChar, qname: *const xmlChar, len: c_int) -> bool {
3816 unsafe {
3817 let p = string::xmlstr_to_bytes(prefix);
3818 let q = string::xmlstr_to_bytes(qname);
3819 p.len() == len as usize && q.len() >= len as usize && p[..len as usize] == q[..len as usize]
3820 }
3821}
3822
3823#[repr(C)]
3832pub struct ContentModelNfa {
3833 transitions: Vec<(u32, *const xmlChar, u32)>,
3835 start: u32,
3837 accept: Vec<u32>,
3839}
3840
3841#[repr(C)]
3843pub struct ContentModelExec {
3844 nfa: *mut ContentModelNfa,
3846 current: Vec<u32>,
3848}
3849
3850struct NfaBuilder {
3852 transitions: Vec<(u32, *const xmlChar, u32)>,
3853 n_states: u32,
3854}
3855
3856impl NfaBuilder {
3857 fn new() -> Self {
3858 NfaBuilder {
3859 transitions: Vec::new(),
3860 n_states: 0,
3861 }
3862 }
3863 fn new_state(&mut self) -> u32 {
3864 let s = self.n_states;
3865 self.n_states += 1;
3866 s
3867 }
3868 fn eps(&mut self, from: u32, to: u32) {
3869 self.transitions.push((from, ptr::null(), to));
3870 }
3871 fn name_trans(&mut self, from: u32, name: *const xmlChar, to: u32) {
3872 self.transitions.push((from, name, to));
3873 }
3874}
3875
3876unsafe fn compile_content_sub(
3881 b: &mut NfaBuilder,
3882 model: *mut _xmlElementContent,
3883) -> (u32, Vec<u32>) {
3884 if model.is_null() {
3885 let s = b.new_state();
3886 return (s, vec![s]);
3887 }
3888 let m = unsafe { &*model };
3889 let (mut in_s, mut outs) = match m.type_ as u32 {
3890 t if t == XML_ELEMENT_CONTENT_ELEMENT as u32 => {
3891 let s = b.new_state();
3892 let to = b.new_state();
3893 b.name_trans(s, m.name, to);
3894 (s, vec![to])
3895 }
3896 t if t == XML_ELEMENT_CONTENT_SEQ as u32 => {
3897 let (in1, out1) = compile_content_sub(b, m.c1);
3898 let (in2, out2) = compile_content_sub(b, m.c2);
3899 for &o in &out1 {
3900 b.eps(o, in2);
3901 }
3902 (in1, out2)
3903 }
3904 t if t == XML_ELEMENT_CONTENT_OR as u32 => {
3905 let (in1, out1) = compile_content_sub(b, m.c1);
3906 let (in2, out2) = compile_content_sub(b, m.c2);
3907 let s = b.new_state();
3908 b.eps(s, in1);
3909 b.eps(s, in2);
3910 let mut all = out1;
3911 all.extend(out2);
3912 (s, all)
3913 }
3914 _ => {
3919 let s = b.new_state();
3920 (s, vec![s])
3921 }
3922 };
3923 match m.ocur as u32 {
3924 o if o == XML_ELEMENT_CONTENT_OPT as u32 => {
3925 let s = b.new_state();
3926 b.eps(s, in_s);
3927 for &o2 in &outs {
3928 b.eps(s, o2);
3929 }
3930 in_s = s;
3931 }
3932 o if o == XML_ELEMENT_CONTENT_MULT as u32 => {
3933 let s = b.new_state();
3934 b.eps(s, in_s);
3935 for &o2 in &outs {
3936 b.eps(s, o2);
3937 b.eps(o2, s);
3938 }
3939 in_s = s;
3940 }
3941 o if o == XML_ELEMENT_CONTENT_PLUS as u32 => {
3942 let s = b.new_state();
3943 b.eps(s, in_s);
3944 for &o2 in &outs {
3945 b.eps(o2, s);
3946 }
3947 in_s = s;
3948 }
3949 _ => {}
3950 }
3951 (in_s, outs)
3952}
3953
3954unsafe fn content_has_pcdata(model: *mut _xmlElementContent) -> bool {
3956 if model.is_null() {
3957 return false;
3958 }
3959 unsafe {
3960 let m = &*model;
3961 if m.type_ == XML_ELEMENT_CONTENT_PCDATA as c_int {
3962 return true;
3963 }
3964 content_has_pcdata(m.c1) || content_has_pcdata(m.c2)
3965 }
3966}
3967
3968unsafe fn build_content_nfa(content: *mut _xmlElementContent) -> *mut ContentModelNfa {
3974 unsafe {
3975 if content.is_null() {
3976 return ptr::null_mut();
3977 }
3978 let mut b = NfaBuilder::new();
3979 let (start, outs) = compile_content_sub(&mut b, content);
3980 let nfa = Box::new(ContentModelNfa {
3981 transitions: b.transitions,
3982 start,
3983 accept: outs,
3984 });
3985 Box::into_raw(nfa)
3986 }
3987}
3988
3989pub unsafe fn free_content_model_nfa(nfa: *mut ContentModelNfa) {
3995 if nfa.is_null() {
3996 return;
3997 }
3998 unsafe {
3999 ptr::drop_in_place(nfa);
4000 allocator::xmlFreeImpl(nfa as *mut c_void);
4001 }
4002}
4003
4004unsafe fn eps_closure(nfa: &ContentModelNfa, states: &[u32]) -> Vec<u32> {
4006 let mut out = states.to_vec();
4007 let mut stack = states.to_vec();
4008 while let Some(s) = stack.pop() {
4009 for &(from, name, to) in &nfa.transitions {
4010 if from == s && name.is_null() && !out.contains(&to) {
4011 out.push(to);
4012 stack.push(to);
4013 }
4014 }
4015 }
4016 out.sort_unstable();
4017 out.dedup();
4018 out
4019}
4020
4021unsafe fn new_content_exec(nfa: *mut ContentModelNfa) -> *mut ContentModelExec {
4023 unsafe {
4024 let exec = allocator::xmlMallocImpl(size_of::<ContentModelExec>()) as *mut ContentModelExec;
4025 if exec.is_null() {
4026 return ptr::null_mut();
4027 }
4028 let cur = eps_closure(&*nfa, &[(*nfa).start]);
4029 ptr::write(&mut (*exec).nfa, nfa);
4030 ptr::write(&mut (*exec).current, cur);
4031 exec
4032 }
4033}
4034
4035unsafe fn free_content_exec(exec: *mut ContentModelExec) {
4037 if exec.is_null() {
4038 return;
4039 }
4040 unsafe {
4041 ptr::drop_in_place(&mut (*exec).current);
4042 allocator::xmlFreeImpl(exec as *mut c_void);
4043 }
4044}
4045
4046unsafe fn content_exec_push(exec: *mut ContentModelExec, value: *const xmlChar) -> c_int {
4051 unsafe {
4052 if exec.is_null() {
4053 return -1;
4054 }
4055 let nfa = &*(*exec).nfa;
4056 if value.is_null() {
4057 let cur = eps_closure(nfa, &(*exec).current);
4058 return if cur.iter().any(|&s| nfa.accept.contains(&s)) {
4059 1
4060 } else {
4061 0
4062 };
4063 }
4064 let mut next: Vec<u32> = Vec::new();
4065 for &s in &(*exec).current {
4066 for &(from, name, to) in &nfa.transitions {
4067 if from == s && !name.is_null() && string::xml_strcmp(name, value) == 0 {
4068 next.push(to);
4069 }
4070 }
4071 }
4072 next.sort_unstable();
4073 next.dedup();
4074 if next.is_empty() {
4075 return -1;
4076 }
4077 let closed = eps_closure(nfa, &next);
4078 (*exec).current = closed;
4079 if (*exec).current.iter().any(|&s| nfa.accept.contains(&s)) {
4080 1
4081 } else {
4082 0
4083 }
4084 }
4085}
4086
4087unsafe fn vstate_vpush(
4089 ctxt: *mut _xmlValidCtxt,
4090 elem_decl: *mut _xmlElement,
4091 node: *mut _xmlNode,
4092) -> c_int {
4093 unsafe {
4094 if (*ctxt).vstateNr >= (*ctxt).vstateMax {
4095 let new_max = if (*ctxt).vstateMax == 0 {
4096 10
4097 } else {
4098 (*ctxt).vstateMax * 2
4099 };
4100 let new_tab = allocator::xmlReallocImpl(
4101 (*ctxt).vstateTab as *mut c_void,
4102 (new_max as usize) * size_of::<ValidState>(),
4103 ) as *mut ValidState;
4104 if new_tab.is_null() {
4105 vctxt_error(
4106 ctxt,
4107 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4108 );
4109 return -1;
4110 }
4111 (*ctxt).vstateTab = new_tab as *mut c_void;
4112 (*ctxt).vstateMax = new_max;
4113 }
4114 let idx = (*ctxt).vstateNr as usize;
4115 let tab = (*ctxt).vstateTab as *mut ValidState;
4116 (*tab.add(idx)).elem_decl = elem_decl;
4117 (*tab.add(idx)).node = node;
4118 (*tab.add(idx)).exec = ptr::null_mut();
4119 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4120 if (*elem_decl).cont_model.is_null() {
4121 validate_build_content_model(ctxt, elem_decl);
4122 }
4123 if !(*elem_decl).cont_model.is_null() {
4124 let exec = new_content_exec((*elem_decl).cont_model as *mut ContentModelNfa);
4125 if exec.is_null() {
4126 vctxt_error(
4127 ctxt,
4128 b"Memory allocation failed : xmlValidCtxt\0" as *const u8 as *const c_char,
4129 );
4130 return -1;
4131 }
4132 (*tab.add(idx)).exec = exec;
4133 } else {
4134 let msg = format!(
4135 "Failed to build content model regexp for {}\0",
4136 string::xmlstr_to_string((*elem_decl).name)
4137 );
4138 vctxt_error_node(ctxt, node, msg.as_ptr() as *const c_char);
4139 }
4140 }
4141 (*ctxt).vstate = tab.add(idx) as *mut c_void;
4142 (*ctxt).vstateNr += 1;
4143 0
4144 }
4145}
4146
4147unsafe fn vstate_vpop(ctxt: *mut _xmlValidCtxt) -> c_int {
4149 unsafe {
4150 if (*ctxt).vstateNr < 1 {
4151 return -1;
4152 }
4153 (*ctxt).vstateNr -= 1;
4154 let idx = (*ctxt).vstateNr as usize;
4155 let tab = (*ctxt).vstateTab as *mut ValidState;
4156 let elem_decl = (*tab.add(idx)).elem_decl;
4157 (*tab.add(idx)).elem_decl = ptr::null_mut();
4158 (*tab.add(idx)).node = ptr::null_mut();
4159 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4160 if !(*tab.add(idx)).exec.is_null() {
4161 free_content_exec((*tab.add(idx)).exec);
4162 }
4163 }
4164 (*tab.add(idx)).exec = ptr::null_mut();
4165 if (*ctxt).vstateNr >= 1 {
4166 (*ctxt).vstate = tab.add((*ctxt).vstateNr as usize - 1) as *mut c_void;
4167 } else {
4168 (*ctxt).vstate = ptr::null_mut();
4169 }
4170 0
4171 }
4172}
4173
4174pub unsafe fn validate_build_content_model(
4182 ctxt: *mut _xmlValidCtxt,
4183 elem: *mut _xmlElement,
4184) -> c_int {
4185 unsafe {
4186 if ctxt.is_null() {
4187 return 0;
4188 }
4189 if (*elem).type_ != XML_ELEMENT_DECL as c_int {
4190 return 0;
4191 }
4192 if (*elem).etype != XML_ELEMENT_TYPE_ELEMENT as c_int {
4193 return 1;
4194 }
4195 if !(*elem).cont_model.is_null() {
4196 return 1;
4197 }
4198 if (*elem).content.is_null() {
4199 return 1;
4200 }
4201 if content_has_pcdata((*elem).content) {
4202 let msg = format!(
4203 "Found PCDATA in content model of {}\0",
4204 string::xmlstr_to_string((*elem).name)
4205 );
4206 vctxt_error_node(ctxt, elem as *mut _xmlNode, msg.as_ptr() as *const c_char);
4207 return 0;
4208 }
4209 let nfa = build_content_nfa((*elem).content);
4210 if nfa.is_null() {
4211 vctxt_error(
4212 ctxt,
4213 b"Memory allocation failed : xmlValidBuildContentModel\0" as *const u8
4214 as *const c_char,
4215 );
4216 return 0;
4217 }
4218 (*elem).cont_model = nfa as *mut c_void;
4219 1
4220 }
4221}
4222
4223pub unsafe fn validate_push_element(
4231 ctxt: *mut _xmlValidCtxt,
4232 doc: *mut _xmlDoc,
4233 elem: *mut _xmlNode,
4234 qname: *const xmlChar,
4235) -> c_int {
4236 unsafe {
4237 let mut ret = 1;
4238 if ctxt.is_null() {
4239 return 0;
4240 }
4241 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4242 let state = (*ctxt).vstate as *mut ValidState;
4243 let elem_decl = (*state).elem_decl;
4244 if !elem_decl.is_null() {
4245 match (*elem_decl).etype as u32 {
4246 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4247 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4248 let msg = format!(
4249 "Element {} was declared EMPTY this one has content\0",
4250 string::xmlstr_to_string((*(*state).node).name)
4251 );
4252 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4253 ret = 0;
4254 }
4255 t if t == XML_ELEMENT_TYPE_ANY as u32 => {}
4256 t if t == XML_ELEMENT_TYPE_MIXED as u32 => {
4257 if !(*elem_decl).content.is_null()
4258 && (*(*elem_decl).content).type_ == XML_ELEMENT_CONTENT_PCDATA as c_int
4259 {
4260 let msg = format!(
4261 "Element {} was declared #PCDATA but contains non text nodes\0",
4262 string::xmlstr_to_string((*(*state).node).name)
4263 );
4264 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4265 ret = 0;
4266 } else {
4267 ret = validate_check_mixed(ctxt, (*elem_decl).content, qname);
4268 if ret != 1 {
4269 let msg = format!(
4270 "Element {} is not declared in {} list of possible children\0",
4271 string::xmlstr_to_string(qname),
4272 string::xmlstr_to_string((*(*state).node).name)
4273 );
4274 vctxt_error_node(
4275 ctxt,
4276 (*state).node,
4277 msg.as_ptr() as *const c_char,
4278 );
4279 }
4280 }
4281 }
4282 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4283 if !(*state).exec.is_null() {
4284 ret = content_exec_push((*state).exec, qname);
4285 if ret < 0 {
4286 let msg = format!(
4287 "Element {} content does not follow the DTD, Misplaced {}\0",
4288 string::xmlstr_to_string((*(*state).node).name),
4289 string::xmlstr_to_string(qname)
4290 );
4291 vctxt_error_node(
4292 ctxt,
4293 (*state).node,
4294 msg.as_ptr() as *const c_char,
4295 );
4296 ret = 0;
4297 } else {
4298 ret = 1;
4299 }
4300 }
4301 }
4302 _ => {}
4303 }
4304 }
4305 }
4306 let mut extsubset = 0;
4307 let e_decl = valid_get_elem_decl(ctxt, doc, elem, &mut extsubset);
4308 let _ = vstate_vpush(ctxt, e_decl, elem);
4310 ret
4311 }
4312}
4313
4314pub unsafe fn validate_push_cdata(
4321 ctxt: *mut _xmlValidCtxt,
4322 data: *const xmlChar,
4323 len: c_int,
4324) -> c_int {
4325 unsafe {
4326 let mut ret = 1;
4327 if ctxt.is_null() {
4328 return 0;
4329 }
4330 if len <= 0 {
4331 return 1;
4332 }
4333 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4334 let state = (*ctxt).vstate as *mut ValidState;
4335 let elem_decl = (*state).elem_decl;
4336 if !elem_decl.is_null() {
4337 match (*elem_decl).etype as u32 {
4338 t if t == XML_ELEMENT_TYPE_UNDEFINED as u32 => ret = 0,
4339 t if t == XML_ELEMENT_TYPE_EMPTY as u32 => {
4340 let msg = format!(
4341 "Element {} was declared EMPTY this one has content\0",
4342 string::xmlstr_to_string((*(*state).node).name)
4343 );
4344 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4345 ret = 0;
4346 }
4347 t if t == XML_ELEMENT_TYPE_ANY as u32 || t == XML_ELEMENT_TYPE_MIXED as u32 => {
4348 }
4349 t if t == XML_ELEMENT_TYPE_ELEMENT as u32 => {
4350 let bytes = core::slice::from_raw_parts(data, len as usize);
4351 for &b in bytes {
4352 if !is_blank_byte(b) {
4353 let msg = format!(
4354 "Element {} content does not follow the DTD, Text not allowed\0",
4355 string::xmlstr_to_string((*(*state).node).name)
4356 );
4357 vctxt_error_node(
4358 ctxt,
4359 (*state).node,
4360 msg.as_ptr() as *const c_char,
4361 );
4362 ret = 0;
4363 break;
4364 }
4365 }
4366 }
4367 _ => {}
4368 }
4369 }
4370 }
4371 ret
4372 }
4373}
4374
4375pub unsafe fn validate_pop_element(
4382 ctxt: *mut _xmlValidCtxt,
4383 _doc: *mut _xmlDoc,
4384 _elem: *mut _xmlNode,
4385 _qname: *const xmlChar,
4386) -> c_int {
4387 unsafe {
4388 let mut ret = 1;
4389 if ctxt.is_null() {
4390 return 0;
4391 }
4392 if (*ctxt).vstateNr > 0 && !(*ctxt).vstate.is_null() {
4393 let state = (*ctxt).vstate as *mut ValidState;
4394 let elem_decl = (*state).elem_decl;
4395 if !elem_decl.is_null() && (*elem_decl).etype == XML_ELEMENT_TYPE_ELEMENT as c_int {
4396 if !(*state).exec.is_null() {
4397 ret = content_exec_push((*state).exec, ptr::null());
4398 if ret <= 0 {
4399 let msg = format!(
4400 "Element {} content does not follow the DTD, Expecting more children\0",
4401 string::xmlstr_to_string((*(*state).node).name)
4402 );
4403 vctxt_error_node(ctxt, (*state).node, msg.as_ptr() as *const c_char);
4404 ret = 0;
4405 } else {
4406 ret = 1;
4407 }
4408 }
4409 }
4410 let _ = vstate_vpop(ctxt);
4411 }
4412 ret
4413 }
4414}
4415
4416#[cfg(test)]
4421mod tests {
4422 use super::*;
4423 use crate::abi::allocator;
4424 use crate::abi::types::xmlElementTypeVal::*;
4425 use crate::xml::dtd;
4426 use crate::xml::tree;
4427
4428 unsafe fn c_str(s: &str) -> *const xmlChar {
4432 let bytes = s.as_bytes();
4433 let ptr = allocator::xmlMallocImpl(bytes.len() + 1) as *mut xmlChar;
4434 assert!(!ptr.is_null());
4435 std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
4436 *ptr.add(bytes.len()) = 0;
4437 ptr
4438 }
4439
4440 unsafe fn make_test_doc() -> (*mut _xmlDoc, *mut _xmlDtd) {
4442 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4443 assert!(!doc.is_null());
4444
4445 let name = c_str("root");
4446 let ext_id = c_str("--//Test//DTD//EN");
4447 let sys_id = c_str("test.dtd");
4448 let dtd = dtd::create_int_subset(doc, name, ext_id, sys_id);
4449 assert!(!dtd.is_null());
4450
4451 (doc, dtd)
4452 }
4453
4454 #[allow(unused)]
4456 unsafe fn add_elem_decl(
4457 dtd: *mut _xmlDtd,
4458 name: *const xmlChar,
4459 elem_type: c_int,
4460 content: *mut _xmlElementContent,
4461 ) -> *mut _xmlElement {
4462 let result = dtd::add_element_decl(dtd, name, elem_type, content);
4463 result
4464 }
4465
4466 unsafe fn create_root_elem(doc: *mut _xmlDoc, name: *const xmlChar) -> *mut _xmlNode {
4468 let node = tree::new_node(ptr::null_mut(), name);
4469 assert!(!node.is_null());
4470 tree::add_child(doc as *mut _xmlNode, node);
4471 node
4472 }
4473
4474 #[allow(unused)]
4476 unsafe fn create_child_elem(parent: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlNode {
4477 let node = tree::new_node(ptr::null_mut(), name);
4478 assert!(!node.is_null());
4479 tree::add_child(parent, node);
4480 node
4481 }
4482
4483 #[test]
4486 fn test_validate_name_null() {
4487 unsafe {
4488 assert_eq!(validate_name(ptr::null()), 0);
4489 }
4490 }
4491
4492 #[test]
4493 fn test_validate_name_empty() {
4494 unsafe {
4495 let s = b"\0" as *const u8 as *const xmlChar;
4496 assert_eq!(validate_name(s), 0);
4497 }
4498 }
4499
4500 #[test]
4501 fn test_validate_name_valid() {
4502 unsafe {
4503 let tests = ["foo", "_bar", ":baz", "hello-world", "ns:elem", "a123"];
4504 for t in &tests {
4505 let s = c_str(t);
4506 assert_eq!(validate_name(s), 1, "Expected '{}' to be a valid Name", t);
4507 allocator::xmlFreeImpl(s as *mut c_void);
4508 }
4509 }
4510 }
4511
4512 #[test]
4513 fn test_validate_name_invalid() {
4514 unsafe {
4515 let tests = ["123abc", "-foo", ".bar", "foo bar", "a b"];
4516 for t in &tests {
4517 let s = c_str(t);
4518 assert_eq!(validate_name(s), 0, "Expected '{}' to be invalid", t);
4519 allocator::xmlFreeImpl(s as *mut c_void);
4520 }
4521 }
4522 }
4523
4524 #[test]
4525 fn test_validate_names_valid() {
4526 unsafe {
4527 let s = c_str("foo bar baz");
4528 assert_eq!(validate_names(s), 1);
4529 allocator::xmlFreeImpl(s as *mut c_void);
4530 }
4531 }
4532
4533 #[test]
4534 fn test_validate_names_invalid() {
4535 unsafe {
4536 let s = c_str("foo 123bar baz");
4537 assert_eq!(validate_names(s), 0);
4538 allocator::xmlFreeImpl(s as *mut c_void);
4539 }
4540 }
4541
4542 #[test]
4545 fn test_validate_nmtoken_null() {
4546 unsafe {
4547 assert_eq!(validate_nmtoken(ptr::null()), 0);
4548 }
4549 }
4550
4551 #[test]
4552 fn test_validate_nmtoken_valid() {
4553 unsafe {
4554 let tests = ["foo", "123abc", "-foo", ".bar", "_test", ":ns"];
4555 for t in &tests {
4556 let s = c_str(t);
4557 assert_eq!(
4558 validate_nmtoken(s),
4559 1,
4560 "Expected '{}' to be a valid NMTOKEN",
4561 t
4562 );
4563 allocator::xmlFreeImpl(s as *mut c_void);
4564 }
4565 }
4566 }
4567
4568 #[test]
4569 fn test_validate_nmtoken_invalid() {
4570 unsafe {
4571 let s = c_str("foo bar");
4572 assert_eq!(validate_nmtoken(s), 0);
4573 allocator::xmlFreeImpl(s as *mut c_void);
4574 }
4575 }
4576
4577 #[test]
4578 fn test_validate_nmtokens_valid() {
4579 unsafe {
4580 let s = c_str("foo 123bar -baz");
4581 assert_eq!(validate_nmtokens(s), 1);
4582 allocator::xmlFreeImpl(s as *mut c_void);
4583 }
4584 }
4585
4586 #[test]
4589 fn test_validate_attribute_value_cdata() {
4590 unsafe {
4591 let s = c_str("anything goes here!@#$%^&*()");
4592 assert_eq!(validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, s), 1);
4593 allocator::xmlFreeImpl(s as *mut c_void);
4594
4595 let empty = b"\0" as *const u8 as *const xmlChar;
4597 assert_eq!(
4598 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, empty),
4599 1
4600 );
4601 }
4602 }
4603
4604 #[test]
4605 fn test_validate_attribute_value_id() {
4606 unsafe {
4607 let valid = c_str("myId");
4608 assert_eq!(
4609 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, valid),
4610 1
4611 );
4612 allocator::xmlFreeImpl(valid as *mut c_void);
4613
4614 let invalid = c_str("123id");
4615 assert_eq!(
4616 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, invalid),
4617 0
4618 );
4619 allocator::xmlFreeImpl(invalid as *mut c_void);
4620 }
4621 }
4622
4623 #[test]
4624 fn test_validate_attribute_value_idref() {
4625 unsafe {
4626 let valid = c_str("someId");
4627 assert_eq!(
4628 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, valid),
4629 1
4630 );
4631 allocator::xmlFreeImpl(valid as *mut c_void);
4632 }
4633 }
4634
4635 #[test]
4636 fn test_validate_attribute_value_idrefs() {
4637 unsafe {
4638 let valid = c_str("id1 id2 id3");
4639 assert_eq!(
4640 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, valid),
4641 1
4642 );
4643 allocator::xmlFreeImpl(valid as *mut c_void);
4644
4645 let invalid = c_str("id1 123id");
4646 assert_eq!(
4647 validate_attribute_value(XML_ATTRIBUTE_IDREFS as c_int, invalid),
4648 0
4649 );
4650 allocator::xmlFreeImpl(invalid as *mut c_void);
4651 }
4652 }
4653
4654 #[test]
4655 fn test_validate_attribute_value_entity() {
4656 unsafe {
4657 let valid = c_str("myEntity");
4658 assert_eq!(
4659 validate_attribute_value(XML_ATTRIBUTE_ENTITY as c_int, valid),
4660 1
4661 );
4662 allocator::xmlFreeImpl(valid as *mut c_void);
4663 }
4664 }
4665
4666 #[test]
4667 fn test_validate_attribute_value_nmtoken() {
4668 unsafe {
4669 let valid = c_str("123abc");
4670 assert_eq!(
4671 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, valid),
4672 1
4673 );
4674 allocator::xmlFreeImpl(valid as *mut c_void);
4675
4676 let invalid = c_str("foo bar");
4677 assert_eq!(
4678 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, invalid),
4679 0
4680 );
4681 allocator::xmlFreeImpl(invalid as *mut c_void);
4682 }
4683 }
4684
4685 #[test]
4686 fn test_validate_attribute_value_null() {
4687 unsafe {
4688 assert_eq!(
4692 validate_attribute_value(XML_ATTRIBUTE_CDATA as c_int, ptr::null()),
4693 1
4694 );
4695 assert_eq!(
4696 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, ptr::null()),
4697 0
4698 );
4699 }
4700 }
4701
4702 #[test]
4705 fn test_validate_enumeration_valid() {
4706 unsafe {
4707 let ctxt = new_valid_ctxt();
4708 assert!(!ctxt.is_null());
4709
4710 let red = c_str("red");
4711 let green = c_str("green");
4712 let blue = c_str("blue");
4713
4714 let e3 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4715 (*e3).name = string::xml_strdup(blue);
4716 (*e3).next = ptr::null_mut();
4717
4718 let e2 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4719 (*e2).name = string::xml_strdup(green);
4720 (*e2).next = e3;
4721
4722 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4723 (*e1).name = string::xml_strdup(red);
4724 (*e1).next = e2;
4725
4726 let value = c_str("green");
4727 assert_eq!(validate_enumeration(ctxt, value, e1), 1);
4728 assert_eq!((*ctxt).valid, 1);
4729
4730 allocator::xmlFreeImpl(value as *mut c_void);
4731 allocator::xmlFreeImpl(red as *mut c_void);
4732 allocator::xmlFreeImpl(green as *mut c_void);
4733 allocator::xmlFreeImpl(blue as *mut c_void);
4734 free_valid_ctxt(ctxt);
4735 }
4736 }
4737
4738 #[test]
4739 fn test_validate_enumeration_invalid() {
4740 unsafe {
4741 let ctxt = new_valid_ctxt();
4742 assert!(!ctxt.is_null());
4743
4744 let e1 = allocator::xmlMallocZero(size_of::<_xmlEnumeration>()) as *mut _xmlEnumeration;
4745 (*e1).name = string::xml_strdup(b"red\0" as *const u8 as *const xmlChar);
4746 (*e1).next = ptr::null_mut();
4747
4748 let value = c_str("yellow");
4749 assert_eq!(validate_enumeration(ctxt, value, e1), 0);
4750
4751 allocator::xmlFreeImpl(value as *mut c_void);
4752 free_valid_ctxt(ctxt);
4753 }
4754 }
4755
4756 #[test]
4759 fn test_validate_notation_use_valid() {
4760 unsafe {
4761 let (doc, dtd) = make_test_doc();
4762
4763 let notation_name = c_str("GIF");
4764 dtd::add_notation_decl(dtd, notation_name, ptr::null(), ptr::null());
4765
4766 let ctxt = new_valid_ctxt();
4767 assert!(!ctxt.is_null());
4768
4769 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 1);
4770
4771 free_valid_ctxt(ctxt);
4772 tree::free_doc(doc);
4773 }
4774 }
4775
4776 #[test]
4777 fn test_validate_notation_use_invalid() {
4778 unsafe {
4779 let (doc, _dtd) = make_test_doc();
4780
4781 let ctxt = new_valid_ctxt();
4782 assert!(!ctxt.is_null());
4783
4784 let notation_name = c_str("UNDECLARED");
4785 assert_eq!(validate_notation_use(ctxt, doc, notation_name), 0);
4786
4787 free_valid_ctxt(ctxt);
4788 allocator::xmlFreeImpl(notation_name as *mut c_void);
4789 tree::free_doc(doc);
4790 }
4791 }
4792
4793 #[test]
4796 fn test_new_free_valid_ctxt() {
4797 unsafe {
4798 let ctxt = new_valid_ctxt();
4799 assert!(!ctxt.is_null());
4800 assert_eq!((*ctxt).valid, 1);
4801 assert!((*ctxt).node.is_null());
4802 free_valid_ctxt(ctxt);
4803 }
4804 }
4805
4806 #[test]
4807 fn test_free_valid_ctxt_null() {
4808 unsafe {
4809 free_valid_ctxt(ptr::null_mut());
4810 }
4811 }
4812
4813 #[test]
4816 fn test_set_valid_errors_null() {
4817 unsafe {
4818 set_valid_errors(ptr::null_mut(), None, None, ptr::null_mut());
4819 }
4820 }
4821
4822 #[test]
4825 fn test_validate_element_no_dtd() {
4826 unsafe {
4827 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
4828 assert!(!doc.is_null());
4829
4830 let root_name = c_str("root");
4831 let root = create_root_elem(doc, root_name);
4832
4833 let ctxt = new_valid_ctxt();
4834 assert!(!ctxt.is_null());
4835
4836 assert_eq!(validate_element(ctxt, doc, root), 1);
4838
4839 free_valid_ctxt(ctxt);
4840 tree::free_doc(doc);
4841 }
4842 }
4843
4844 #[test]
4845 fn test_validate_element_empty_valid() {
4846 unsafe {
4847 let (doc, dtd) = make_test_doc();
4848
4849 let root_name = c_str("root");
4850 add_elem_decl(
4851 dtd,
4852 root_name,
4853 XML_ELEMENT_TYPE_EMPTY as c_int,
4854 ptr::null_mut(),
4855 );
4856
4857 let root = create_root_elem(doc, root_name);
4858
4859 let ctxt = new_valid_ctxt();
4860 assert!(!ctxt.is_null());
4861
4862 assert_eq!(validate_element(ctxt, doc, root), 1);
4863
4864 free_valid_ctxt(ctxt);
4865 tree::free_doc(doc);
4866 }
4867 }
4868
4869 #[test]
4870 fn test_validate_element_undeclared() {
4871 unsafe {
4872 let (doc, _dtd) = make_test_doc();
4873
4874 let root_name = c_str("root");
4875 let root = create_root_elem(doc, root_name);
4876
4877 let ctxt = new_valid_ctxt();
4878 assert!(!ctxt.is_null());
4879
4880 assert_eq!(validate_element(ctxt, doc, root), 0);
4882
4883 free_valid_ctxt(ctxt);
4884 tree::free_doc(doc);
4885 }
4886 }
4887
4888 #[test]
4889 fn test_validate_element_with_content() {
4890 unsafe {
4891 let (doc, dtd) = make_test_doc();
4892
4893 let root_name = c_str("root");
4895 let child_name = c_str("child");
4896
4897 let child_content =
4899 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4900 assert!(!child_content.is_null());
4901 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4902
4903 add_elem_decl(
4904 dtd,
4905 root_name,
4906 XML_ELEMENT_TYPE_ELEMENT as c_int,
4907 child_content,
4908 );
4909 add_elem_decl(
4910 dtd,
4911 child_name,
4912 XML_ELEMENT_TYPE_EMPTY as c_int,
4913 ptr::null_mut(),
4914 );
4915
4916 let root = create_root_elem(doc, root_name);
4917 let _child = create_child_elem(root, child_name);
4918
4919 let ctxt = new_valid_ctxt();
4920 assert!(!ctxt.is_null());
4921
4922 assert_eq!(validate_element(ctxt, doc, root), 1);
4923
4924 free_valid_ctxt(ctxt);
4925 tree::free_doc(doc);
4926 }
4927 }
4928
4929 #[test]
4930 fn test_validate_element_invalid_content() {
4931 unsafe {
4932 let (doc, dtd) = make_test_doc();
4933
4934 let root_name = c_str("root");
4935 let child_name = c_str("child");
4936 let wrong_name = c_str("wrong");
4937
4938 let child_content =
4940 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
4941 assert!(!child_content.is_null());
4942 (*child_content).ocur = XML_ELEMENT_CONTENT_PLUS as c_int;
4943
4944 add_elem_decl(
4945 dtd,
4946 root_name,
4947 XML_ELEMENT_TYPE_ELEMENT as c_int,
4948 child_content,
4949 );
4950 add_elem_decl(
4951 dtd,
4952 child_name,
4953 XML_ELEMENT_TYPE_EMPTY as c_int,
4954 ptr::null_mut(),
4955 );
4956 add_elem_decl(
4957 dtd,
4958 wrong_name,
4959 XML_ELEMENT_TYPE_EMPTY as c_int,
4960 ptr::null_mut(),
4961 );
4962
4963 let root = create_root_elem(doc, root_name);
4964 create_child_elem(root, wrong_name);
4966
4967 let ctxt = new_valid_ctxt();
4968 assert!(!ctxt.is_null());
4969
4970 assert_eq!(validate_element(ctxt, doc, root), 0);
4971
4972 free_valid_ctxt(ctxt);
4973 tree::free_doc(doc);
4974 }
4975 }
4976
4977 #[test]
4980 fn test_validate_root_match() {
4981 unsafe {
4982 let (doc, dtd) = make_test_doc();
4983
4984 let root_name = c_str("root");
4985 add_elem_decl(
4986 dtd,
4987 root_name,
4988 XML_ELEMENT_TYPE_EMPTY as c_int,
4989 ptr::null_mut(),
4990 );
4991 create_root_elem(doc, root_name);
4992
4993 let ctxt = new_valid_ctxt();
4994 assert!(!ctxt.is_null());
4995
4996 assert_eq!(validate_root(ctxt, doc), 1);
4997
4998 free_valid_ctxt(ctxt);
4999 tree::free_doc(doc);
5000 }
5001 }
5002
5003 #[test]
5004 fn test_validate_root_no_dtd() {
5005 unsafe {
5006 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5007 assert!(!doc.is_null());
5008
5009 let root_name = c_str("root");
5010 create_root_elem(doc, root_name);
5011
5012 let ctxt = new_valid_ctxt();
5013 assert!(!ctxt.is_null());
5014
5015 assert_eq!(validate_root(ctxt, doc), 1);
5017
5018 free_valid_ctxt(ctxt);
5019 tree::free_doc(doc);
5020 }
5021 }
5022
5023 #[test]
5026 fn test_validate_document_valid() {
5027 unsafe {
5028 let (doc, dtd) = make_test_doc();
5029
5030 let root_name = c_str("root");
5031 add_elem_decl(
5032 dtd,
5033 root_name,
5034 XML_ELEMENT_TYPE_EMPTY as c_int,
5035 ptr::null_mut(),
5036 );
5037 create_root_elem(doc, root_name);
5038
5039 let ctxt = new_valid_ctxt();
5040 assert!(!ctxt.is_null());
5041
5042 assert_eq!(validate_document(ctxt, doc), 1);
5043
5044 free_valid_ctxt(ctxt);
5045 tree::free_doc(doc);
5046 }
5047 }
5048
5049 #[test]
5050 fn test_validate_document_no_root() {
5051 unsafe {
5052 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5053 assert!(!doc.is_null());
5054
5055 let ctxt = new_valid_ctxt();
5056 assert!(!ctxt.is_null());
5057
5058 assert_eq!(validate_document(ctxt, doc), 0);
5059
5060 free_valid_ctxt(ctxt);
5061 tree::free_doc(doc);
5062 }
5063 }
5064
5065 #[test]
5068 fn test_validate_content_valid() {
5069 unsafe {
5070 let (doc, dtd) = make_test_doc();
5071
5072 let root_name = c_str("root");
5073 let child_name = c_str("child");
5074
5075 let child_content =
5076 dtd::create_content_model(child_name, XML_ELEMENT_CONTENT_ELEMENT as c_int);
5077 assert!(!child_content.is_null());
5078
5079 add_elem_decl(
5080 dtd,
5081 root_name,
5082 XML_ELEMENT_TYPE_ELEMENT as c_int,
5083 child_content,
5084 );
5085 add_elem_decl(
5086 dtd,
5087 child_name,
5088 XML_ELEMENT_TYPE_EMPTY as c_int,
5089 ptr::null_mut(),
5090 );
5091
5092 let root = create_root_elem(doc, root_name);
5093 create_child_elem(root, child_name);
5094
5095 let ctxt = new_valid_ctxt();
5096 assert!(!ctxt.is_null());
5097
5098 assert_eq!(validate_content(ctxt, root, doc), 1);
5099
5100 free_valid_ctxt(ctxt);
5101 tree::free_doc(doc);
5102 }
5103 }
5104
5105 #[test]
5108 fn test_is_mixed_element() {
5109 unsafe {
5110 let (doc, dtd) = make_test_doc();
5111 let name = c_str("mixedElem");
5112 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_MIXED as c_int, ptr::null_mut());
5113
5114 assert_eq!(is_mixed_element(doc, name), 1);
5115
5116 let other = c_str("other");
5117 assert_eq!(is_mixed_element(doc, other), 0);
5118
5119 allocator::xmlFreeImpl(other as *mut c_void);
5120 tree::free_doc(doc);
5121 }
5122 }
5123
5124 #[test]
5125 fn test_is_empty_element() {
5126 unsafe {
5127 let (doc, dtd) = make_test_doc();
5128 let name = c_str("emptyElem");
5129 add_elem_decl(dtd, name, XML_ELEMENT_TYPE_EMPTY as c_int, ptr::null_mut());
5130
5131 assert_eq!(is_empty_element(doc, name), 1);
5132
5133 let other = c_str("other");
5134 assert_eq!(is_empty_element(doc, other), 0);
5135
5136 allocator::xmlFreeImpl(other as *mut c_void);
5137 tree::free_doc(doc);
5138 }
5139 }
5140
5141 #[test]
5142 fn test_is_mixed_element_no_dtd() {
5143 unsafe {
5144 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5145 assert!(!doc.is_null());
5146
5147 let name = c_str("foo");
5148 assert_eq!(is_mixed_element(doc, name), 0);
5149
5150 allocator::xmlFreeImpl(name as *mut c_void);
5151 tree::free_doc(doc);
5152 }
5153 }
5154
5155 #[test]
5156 fn test_is_empty_element_no_dtd() {
5157 unsafe {
5158 let doc = tree::new_doc(b"1.0\0" as *const u8 as *const xmlChar);
5159 assert!(!doc.is_null());
5160
5161 let name = c_str("foo");
5162 assert_eq!(is_empty_element(doc, name), 0);
5163
5164 allocator::xmlFreeImpl(name as *mut c_void);
5165 tree::free_doc(doc);
5166 }
5167 }
5168
5169 #[test]
5172 fn test_validate_dtd_null() {
5173 unsafe {
5174 let ctxt = new_valid_ctxt();
5175 assert!(!ctxt.is_null());
5176 assert_eq!(validate_dtd(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5177 free_valid_ctxt(ctxt);
5178 }
5179 }
5180
5181 #[test]
5184 fn test_validate_element_null() {
5185 unsafe {
5186 let (doc, _dtd) = make_test_doc();
5187 let ctxt = new_valid_ctxt();
5188 assert!(!ctxt.is_null());
5189
5190 assert_eq!(validate_element(ctxt, doc, ptr::null_mut()), 0);
5191
5192 free_valid_ctxt(ctxt);
5193 tree::free_doc(doc);
5194 }
5195 }
5196
5197 #[test]
5198 fn test_validate_document_null() {
5199 unsafe {
5200 let ctxt = new_valid_ctxt();
5201 assert!(!ctxt.is_null());
5202
5203 assert_eq!(validate_document(ctxt, ptr::null_mut()), 0);
5204 assert_eq!(validate_document(ptr::null_mut(), ptr::null_mut()), 0);
5205
5206 free_valid_ctxt(ctxt);
5207 }
5208 }
5209
5210 #[test]
5211 fn test_validate_document_final_null() {
5212 unsafe {
5213 let ctxt = new_valid_ctxt();
5214 assert!(!ctxt.is_null());
5215
5216 assert_eq!(validate_document_final(ctxt, ptr::null_mut()), 0);
5217 assert_eq!(validate_document_final(ptr::null_mut(), ptr::null_mut()), 0);
5218
5219 free_valid_ctxt(ctxt);
5220 }
5221 }
5222
5223 #[test]
5224 fn test_validate_attribute_decl_null() {
5225 unsafe {
5226 let ctxt = new_valid_ctxt();
5227 assert!(!ctxt.is_null());
5228
5229 assert_eq!(
5230 validate_attribute_decl(ctxt, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()),
5231 0
5232 );
5233
5234 free_valid_ctxt(ctxt);
5235 }
5236 }
5237
5238 #[test]
5239 fn test_validate_content_null() {
5240 unsafe {
5241 let ctxt = new_valid_ctxt();
5242 assert!(!ctxt.is_null());
5243
5244 assert_eq!(validate_content(ctxt, ptr::null_mut(), ptr::null_mut()), 0);
5245
5246 free_valid_ctxt(ctxt);
5247 }
5248 }
5249
5250 #[test]
5251 fn test_validate_root_null() {
5252 unsafe {
5253 assert_eq!(validate_root(ptr::null_mut(), ptr::null_mut()), 0);
5254 }
5255 }
5256
5257 #[test]
5258 fn test_validate_enumeration_null() {
5259 unsafe {
5260 let ctxt = new_valid_ctxt();
5261 assert!(!ctxt.is_null());
5262
5263 assert_eq!(validate_enumeration(ctxt, ptr::null(), ptr::null_mut()), 0);
5264
5265 free_valid_ctxt(ctxt);
5266 }
5267 }
5268
5269 #[test]
5270 fn test_validate_notation_use_null() {
5271 unsafe {
5272 let ctxt = new_valid_ctxt();
5273 assert!(!ctxt.is_null());
5274
5275 assert_eq!(validate_notation_use(ctxt, ptr::null_mut(), ptr::null()), 0);
5276
5277 free_valid_ctxt(ctxt);
5278 }
5279 }
5280
5281 #[test]
5282 fn test_validate_name_start_characters() {
5283 unsafe {
5284 let name = c_str("\u{C0}lph\u{E0}");
5286 assert_eq!(validate_name(name), 1);
5287 allocator::xmlFreeImpl(name as *mut c_void);
5288 }
5289 }
5290
5291 #[test]
5292 fn test_validate_names_single() {
5293 unsafe {
5294 let s = c_str("singleName");
5295 assert_eq!(validate_names(s), 1);
5296 allocator::xmlFreeImpl(s as *mut c_void);
5297 }
5298 }
5299
5300 #[test]
5301 fn test_validate_nmtokens_single() {
5302 unsafe {
5303 let s = c_str("123abc");
5304 assert_eq!(validate_nmtokens(s), 1);
5305 allocator::xmlFreeImpl(s as *mut c_void);
5306 }
5307 }
5308
5309 #[test]
5310 fn test_validate_nmtokens_invalid() {
5311 unsafe {
5312 let s = c_str("foo\tbar"); assert_eq!(validate_nmtokens(s), 1); allocator::xmlFreeImpl(s as *mut c_void);
5315
5316 let s2 = c_str("foo@bar");
5318 assert_eq!(validate_nmtokens(s2), 0);
5319 allocator::xmlFreeImpl(s2 as *mut c_void);
5320 }
5321 }
5322
5323 #[test]
5324 fn test_validate_attribute_value_empty_non_cdata() {
5325 unsafe {
5326 let empty = b"\0" as *const u8 as *const xmlChar;
5327 assert_eq!(
5328 validate_attribute_value(XML_ATTRIBUTE_ID as c_int, empty),
5329 0
5330 );
5331 assert_eq!(
5332 validate_attribute_value(XML_ATTRIBUTE_IDREF as c_int, empty),
5333 0
5334 );
5335 assert_eq!(
5336 validate_attribute_value(XML_ATTRIBUTE_NMTOKEN as c_int, empty),
5337 0
5338 );
5339 }
5340 }
5341
5342 #[test]
5343 fn test_validate_attribute_value_unknown_type() {
5344 unsafe {
5345 let s = c_str("test");
5348 assert_eq!(validate_attribute_value(999, s), 1);
5349 allocator::xmlFreeImpl(s as *mut c_void);
5350 }
5351 }
5352
5353 #[test]
5354 fn test_validate_element_any_content() {
5355 unsafe {
5356 let (doc, dtd) = make_test_doc();
5357
5358 let root_name = c_str("root");
5359 add_elem_decl(
5360 dtd,
5361 root_name,
5362 XML_ELEMENT_TYPE_ANY as c_int,
5363 ptr::null_mut(),
5364 );
5365
5366 let child_name = c_str("child");
5367 add_elem_decl(
5368 dtd,
5369 child_name,
5370 XML_ELEMENT_TYPE_EMPTY as c_int,
5371 ptr::null_mut(),
5372 );
5373
5374 let root = create_root_elem(doc, root_name);
5375 create_child_elem(root, child_name);
5376
5377 let ctxt = new_valid_ctxt();
5378 assert!(!ctxt.is_null());
5379
5380 assert_eq!(validate_element(ctxt, doc, root), 1);
5382
5383 free_valid_ctxt(ctxt);
5384 tree::free_doc(doc);
5385 }
5386 }
5387
5388 #[test]
5389 fn test_validate_element_empty_with_child() {
5390 unsafe {
5391 let (doc, dtd) = make_test_doc();
5392
5393 let root_name = c_str("root");
5394 add_elem_decl(
5395 dtd,
5396 root_name,
5397 XML_ELEMENT_TYPE_EMPTY as c_int,
5398 ptr::null_mut(),
5399 );
5400
5401 let child_name = c_str("child");
5402 add_elem_decl(
5403 dtd,
5404 child_name,
5405 XML_ELEMENT_TYPE_EMPTY as c_int,
5406 ptr::null_mut(),
5407 );
5408
5409 let root = create_root_elem(doc, root_name);
5410 create_child_elem(root, child_name);
5411
5412 let ctxt = new_valid_ctxt();
5413 assert!(!ctxt.is_null());
5414
5415 assert_eq!(validate_element(ctxt, doc, root), 0);
5417
5418 free_valid_ctxt(ctxt);
5419 tree::free_doc(doc);
5420 }
5421 }
5422
5423 #[test]
5424 fn test_validate_dtd_final_null() {
5425 unsafe {
5426 assert_eq!(validate_dtd_final(ptr::null_mut(), ptr::null_mut()), 0);
5427 }
5428 }
5429}