1use core::ffi::c_void;
17use core::ptr;
18use std::collections::HashMap;
19use std::os::raw::{c_char, c_int};
20
21use crate::abi::allocator;
22use crate::abi::structs::*;
23use crate::abi::types::xmlElementType::*;
24use crate::abi::types::*;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum XsdComponentType {
37 Schema,
38 Element,
39 Attribute,
40 ComplexType,
41 SimpleType,
42 SimpleContent,
43 ComplexContent,
44 Sequence,
45 Choice,
46 All,
47 Restriction,
48 Extension,
49 List,
50 Union,
51 Annotation,
52 Any,
53 AnyAttribute,
54 Group,
55 AttributeGroup,
56 Notation,
57 Unique,
58 Key,
59 KeyRef,
60 Selector,
61 Field,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
75pub enum XsdDatatypeKind {
76 String,
78 Boolean,
79 Decimal,
80 Float,
81 Double,
82 Duration,
83 DateTime,
84 Time,
85 Date,
86 GYearMonth,
87 GYear,
88 GMonthDay,
89 GDay,
90 GMonth,
91 HexBinary,
92 Base64Binary,
93 AnyURI,
94 QName,
95 Notation,
96 NormalizedString,
98 Token,
99 Language,
100 Nmtoken,
101 Nmtokens,
102 Name,
103 NCName,
104 Id,
105 Idref,
106 Idrefs,
107 Entity,
108 Entities,
109 Integer,
111 NonPositiveInteger,
112 NegativeInteger,
113 Long,
114 Int,
115 Short,
116 Byte,
117 NonNegativeInteger,
118 UnsignedLong,
119 UnsignedInt,
120 UnsignedShort,
121 UnsignedByte,
122 PositiveInteger,
123 FacetPattern,
125 FacetEnumeration,
126 FacetMinInclusive,
127 FacetMaxInclusive,
128 FacetMinExclusive,
129 FacetMaxExclusive,
130 FacetMinLength,
131 FacetMaxLength,
132 FacetLength,
133 FacetWhiteSpace,
134 FacetFractionDigits,
135 FacetTotalDigits,
136}
137
138#[derive(Debug, Clone)]
147pub struct XsdComponent {
148 pub component_type: XsdComponentType,
149 pub name: Option<String>,
150 pub target_namespace: Option<String>,
151 pub children: Vec<XsdComponent>,
152 pub attributes: Vec<XsdComponent>,
153 pub datatype: Option<XsdDatatypeKind>,
154 pub facets: Vec<(XsdDatatypeKind, String)>,
155 pub base: Option<String>,
156 pub min_occurs: i32,
157 pub max_occurs: i32, pub ref_name: Option<String>,
159 pub substitution_group: Option<String>,
160 pub is_abstract: bool,
161 pub is_final: bool,
162 pub block: Vec<String>,
163 pub mixed: bool,
164 pub form: Option<String>,
165}
166
167impl XsdComponent {
168 pub fn new(component_type: XsdComponentType) -> Self {
169 Self {
170 component_type,
171 name: None,
172 target_namespace: None,
173 children: Vec::new(),
174 attributes: Vec::new(),
175 datatype: None,
176 facets: Vec::new(),
177 base: None,
178 min_occurs: 1,
179 max_occurs: 1,
180 ref_name: None,
181 substitution_group: None,
182 is_abstract: false,
183 is_final: false,
184 block: Vec::new(),
185 mixed: false,
186 form: None,
187 }
188 }
189}
190
191#[derive(Debug, Clone)]
199pub struct XsdSchema {
200 pub components: Vec<XsdComponent>,
201 pub target_namespace: Option<String>,
202 pub element_form_default: Option<String>,
203 pub attribute_form_default: Option<String>,
204 pub errors: Vec<String>,
205}
206
207impl XsdSchema {
208 pub fn new() -> Self {
209 Self {
210 components: Vec::new(),
211 target_namespace: None,
212 element_form_default: None,
213 attribute_form_default: None,
214 errors: Vec::new(),
215 }
216 }
217}
218
219impl Default for XsdSchema {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225#[derive(Debug)]
234pub struct XsdValidCtxt {
235 pub schema: Option<XsdSchema>,
236 pub errors: Vec<String>,
237 pub nb_errors: i32,
238}
239
240impl XsdValidCtxt {
241 pub fn new() -> Self {
242 Self {
243 schema: None,
244 errors: Vec::new(),
245 nb_errors: 0,
246 }
247 }
248}
249
250impl Default for XsdValidCtxt {
251 fn default() -> Self {
252 Self::new()
253 }
254}
255
256unsafe fn get_node_text(node: *mut _xmlNode) -> String {
266 if node.is_null() {
267 return String::new();
268 }
269 let mut result = String::new();
270 unsafe {
271 let mut child = (*node).children;
272 while !child.is_null() {
273 if (*child).type_ == XML_TEXT_NODE as c_int
274 || (*child).type_ == XML_CDATA_SECTION_NODE as c_int
275 {
276 if !(*child).content.is_null() {
277 let content = (*child).content;
278 let mut len = 0;
279 while *content.add(len) != 0 {
280 len += 1;
281 }
282 let slice = std::slice::from_raw_parts(content, len);
283 result.push_str(&String::from_utf8_lossy(slice));
284 }
285 }
286 child = (*child).next;
287 }
288 }
289 result
290}
291
292unsafe fn get_attr(node: *mut _xmlNode, name: &str) -> Option<String> {
298 if node.is_null() {
299 return None;
300 }
301 unsafe {
302 let mut prop = (*node).properties;
303 while !prop.is_null() {
304 let prop_name = (*prop).name;
305 if !prop_name.is_null() {
306 let mut len = 0;
307 while *prop_name.add(len) != 0 {
308 len += 1;
309 }
310 let slice = std::slice::from_raw_parts(prop_name, len);
311 if let Ok(s) = std::str::from_utf8(slice) {
312 if s == name {
313 return Some(get_node_text(prop as *mut _xmlNode));
314 }
315 }
316 }
317 prop = (*prop).next;
318 }
319 }
320 None
321}
322
323unsafe fn get_attr_bool(node: *mut _xmlNode, name: &str) -> bool {
329 unsafe {
330 match get_attr(node, name) {
331 Some(v) => v == "true" || v == "1",
332 None => false,
333 }
334 }
335}
336
337unsafe fn get_attr_int(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
343 unsafe {
344 match get_attr(node, name) {
345 Some(v) => v.parse::<i32>().unwrap_or(default),
346 None => default,
347 }
348 }
349}
350
351unsafe fn get_attr_occurs(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
357 unsafe {
358 match get_attr(node, name) {
359 Some(v) => {
360 if v == "unbounded" {
361 -1
362 } else {
363 v.parse::<i32>().unwrap_or(default)
364 }
365 }
366 None => default,
367 }
368 }
369}
370
371unsafe fn node_is(node: *mut _xmlNode, local_name: &str) -> bool {
377 if node.is_null() {
378 return false;
379 }
380 unsafe {
381 let name = (*node).name;
382 if name.is_null() {
383 return false;
384 }
385 let mut len = 0;
386 while *name.add(len) != 0 {
387 len += 1;
388 }
389 let slice = std::slice::from_raw_parts(name, len);
390 if let Ok(s) = std::str::from_utf8(slice) {
391 let local = if let Some(pos) = s.find(':') {
393 &s[pos + 1..]
394 } else {
395 s
396 };
397 return local == local_name;
398 }
399 }
400 false
401}
402
403fn parse_datatype_kind(name: &str) -> Option<XsdDatatypeKind> {
405 let local = if let Some(pos) = name.find(':') {
407 &name[pos + 1..]
408 } else {
409 name
410 };
411
412 match local {
413 "string" => Some(XsdDatatypeKind::String),
414 "boolean" => Some(XsdDatatypeKind::Boolean),
415 "decimal" => Some(XsdDatatypeKind::Decimal),
416 "float" => Some(XsdDatatypeKind::Float),
417 "double" => Some(XsdDatatypeKind::Double),
418 "duration" => Some(XsdDatatypeKind::Duration),
419 "dateTime" => Some(XsdDatatypeKind::DateTime),
420 "time" => Some(XsdDatatypeKind::Time),
421 "date" => Some(XsdDatatypeKind::Date),
422 "gYearMonth" => Some(XsdDatatypeKind::GYearMonth),
423 "gYear" => Some(XsdDatatypeKind::GYear),
424 "gMonthDay" => Some(XsdDatatypeKind::GMonthDay),
425 "gDay" => Some(XsdDatatypeKind::GDay),
426 "gMonth" => Some(XsdDatatypeKind::GMonth),
427 "hexBinary" => Some(XsdDatatypeKind::HexBinary),
428 "base64Binary" => Some(XsdDatatypeKind::Base64Binary),
429 "anyURI" => Some(XsdDatatypeKind::AnyURI),
430 "QName" => Some(XsdDatatypeKind::QName),
431 "NOTATION" => Some(XsdDatatypeKind::Notation),
432 "normalizedString" => Some(XsdDatatypeKind::NormalizedString),
433 "token" => Some(XsdDatatypeKind::Token),
434 "language" => Some(XsdDatatypeKind::Language),
435 "NMTOKEN" => Some(XsdDatatypeKind::Nmtoken),
436 "NMTOKENS" => Some(XsdDatatypeKind::Nmtokens),
437 "Name" => Some(XsdDatatypeKind::Name),
438 "NCName" => Some(XsdDatatypeKind::NCName),
439 "ID" => Some(XsdDatatypeKind::Id),
440 "IDREF" => Some(XsdDatatypeKind::Idref),
441 "IDREFS" => Some(XsdDatatypeKind::Idrefs),
442 "ENTITY" => Some(XsdDatatypeKind::Entity),
443 "ENTITIES" => Some(XsdDatatypeKind::Entities),
444 "integer" => Some(XsdDatatypeKind::Integer),
445 "nonPositiveInteger" => Some(XsdDatatypeKind::NonPositiveInteger),
446 "negativeInteger" => Some(XsdDatatypeKind::NegativeInteger),
447 "long" => Some(XsdDatatypeKind::Long),
448 "int" => Some(XsdDatatypeKind::Int),
449 "short" => Some(XsdDatatypeKind::Short),
450 "byte" => Some(XsdDatatypeKind::Byte),
451 "nonNegativeInteger" => Some(XsdDatatypeKind::NonNegativeInteger),
452 "unsignedLong" => Some(XsdDatatypeKind::UnsignedLong),
453 "unsignedInt" => Some(XsdDatatypeKind::UnsignedInt),
454 "unsignedShort" => Some(XsdDatatypeKind::UnsignedShort),
455 "unsignedByte" => Some(XsdDatatypeKind::UnsignedByte),
456 "positiveInteger" => Some(XsdDatatypeKind::PositiveInteger),
457 _ => None,
458 }
459}
460
461fn parse_facet_kind(name: &str) -> Option<XsdDatatypeKind> {
463 match name {
464 "pattern" => Some(XsdDatatypeKind::FacetPattern),
465 "enumeration" => Some(XsdDatatypeKind::FacetEnumeration),
466 "minInclusive" => Some(XsdDatatypeKind::FacetMinInclusive),
467 "maxInclusive" => Some(XsdDatatypeKind::FacetMaxInclusive),
468 "minExclusive" => Some(XsdDatatypeKind::FacetMinExclusive),
469 "maxExclusive" => Some(XsdDatatypeKind::FacetMaxExclusive),
470 "minLength" => Some(XsdDatatypeKind::FacetMinLength),
471 "maxLength" => Some(XsdDatatypeKind::FacetMaxLength),
472 "length" => Some(XsdDatatypeKind::FacetLength),
473 "whiteSpace" => Some(XsdDatatypeKind::FacetWhiteSpace),
474 "fractionDigits" => Some(XsdDatatypeKind::FacetFractionDigits),
475 "totalDigits" => Some(XsdDatatypeKind::FacetTotalDigits),
476 _ => None,
477 }
478}
479
480pub fn xsd_parse(xml_doc: &str) -> Result<XsdSchema, String> {
492 let doc_ptr = unsafe {
494 crate::abi::exports_xml2::xmlReadMemory(
495 xml_doc.as_ptr() as *const c_char,
496 xml_doc.len() as c_int,
497 b"schema.xsd\0".as_ptr() as *const c_char,
498 ptr::null(),
499 0,
500 )
501 };
502
503 if doc_ptr.is_null() {
504 return Err("Failed to parse schema XML document".to_string());
505 }
506
507 let result = unsafe { xsd_parse_schema_doc(doc_ptr) };
508 unsafe {
509 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
510 }
511 result
512}
513
514unsafe fn xsd_parse_schema_doc(doc: *mut _xmlDoc) -> Result<XsdSchema, String> {
520 unsafe {
521 let root = (*doc).children;
522 if root.is_null() {
523 return Err("Schema document has no root element".to_string());
524 }
525
526 let mut schema_node = root;
528 while !schema_node.is_null() && !node_is(schema_node, "schema") {
529 schema_node = (*schema_node).next;
530 }
531
532 if schema_node.is_null() {
533 return Err("Schema document root is not <schema>".to_string());
534 }
535
536 Ok(xsd_parse_schema_node(schema_node))
537 }
538}
539
540unsafe fn xsd_parse_schema_node(node: *mut _xmlNode) -> XsdSchema {
546 unsafe {
547 let mut schema = XsdSchema::new();
548 schema.target_namespace = get_attr(node, "targetNamespace");
549 schema.element_form_default = get_attr(node, "elementFormDefault");
550 schema.attribute_form_default = get_attr(node, "attributeFormDefault");
551
552 let mut child = (*node).children;
554 while !child.is_null() {
555 if (*child).type_ == XML_ELEMENT_NODE as c_int {
556 let comp = xsd_parse_component(child, &schema);
557 if comp.component_type != XsdComponentType::Annotation {
558 schema.components.push(comp);
559 }
560 }
561 child = (*child).next;
562 }
563
564 schema
565 }
566}
567
568unsafe fn xsd_parse_component(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
574 unsafe {
575 let name_str = if !(*node).name.is_null() {
577 let mut len = 0;
578 while *(*node).name.add(len) != 0 {
579 len += 1;
580 }
581 let slice = std::slice::from_raw_parts((*node).name, len);
582 if let Ok(s) = std::str::from_utf8(slice) {
583 if let Some(pos) = s.find(':') {
584 s[pos + 1..].to_string()
585 } else {
586 s.to_string()
587 }
588 } else {
589 String::new()
590 }
591 } else {
592 String::new()
593 };
594
595 match name_str.as_str() {
596 "element" => xsd_parse_element(node, schema),
597 "attribute" => xsd_parse_attribute_node(node, schema),
598 "complexType" => xsd_parse_complex_type(node, schema),
599 "simpleType" => xsd_parse_simple_type(node, schema),
600 "sequence" => xsd_parse_model_group(node, XsdComponentType::Sequence, schema),
601 "choice" => xsd_parse_model_group(node, XsdComponentType::Choice, schema),
602 "all" => xsd_parse_model_group(node, XsdComponentType::All, schema),
603 "restriction" => xsd_parse_restriction(node, schema),
604 "extension" => xsd_parse_extension(node, schema),
605 "list" => xsd_parse_list(node, schema),
606 "union" => xsd_parse_union(node, schema),
607 "annotation" => xsd_parse_annotation(node),
608 "any" => xsd_parse_any(node, schema),
609 "anyAttribute" => {
610 let mut comp = XsdComponent::new(XsdComponentType::AnyAttribute);
611 comp
612 }
613 "group" => xsd_parse_group(node, schema),
614 "attributeGroup" => xsd_parse_attribute_group(node, schema),
615 "unique" => xsd_parse_identity_constraint(node, XsdComponentType::Unique, schema),
616 "key" => xsd_parse_identity_constraint(node, XsdComponentType::Key, schema),
617 "keyref" => xsd_parse_identity_constraint(node, XsdComponentType::KeyRef, schema),
618 "pattern" | "enumeration" | "minInclusive" | "maxInclusive" | "minExclusive"
620 | "maxExclusive" | "minLength" | "maxLength" | "length" | "whiteSpace"
621 | "fractionDigits" | "totalDigits" => xsd_parse_facet(node),
622 "simpleContent" => xsd_parse_simple_content(node, schema),
624 "complexContent" => xsd_parse_complex_content(node, schema),
625 _ => {
626 let mut comp = XsdComponent::new(XsdComponentType::Schema);
628 if let Ok(s) = std::str::from_utf8(std::slice::from_raw_parts((*node).name, {
629 let mut len = 0;
630 while *(*node).name.add(len) != 0 {
631 len += 1;
632 }
633 len
634 })) {
635 comp.name = Some(s.to_string());
636 }
637 comp
638 }
639 }
640 }
641}
642
643unsafe fn xsd_parse_element(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
649 unsafe {
650 let mut comp = XsdComponent::new(XsdComponentType::Element);
651 comp.name = get_attr(node, "name");
652 comp.ref_name = get_attr(node, "ref");
653 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
654 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
655 comp.is_abstract = get_attr_bool(node, "abstract");
656 comp.is_final = get_attr_bool(node, "final");
657 comp.substitution_group = get_attr(node, "substitutionGroup");
658 comp.form = get_attr(node, "form");
659
660 if let Some(type_name) = get_attr(node, "type") {
662 comp.datatype = parse_datatype_kind(&type_name);
663 if comp.datatype.is_none() {
665 comp.base = Some(type_name);
666 }
667 }
668
669 let _default = get_attr(node, "default");
671 let _fixed = get_attr(node, "fixed");
672
673 let mut child = (*node).children;
675 while !child.is_null() {
676 if (*child).type_ == XML_ELEMENT_NODE as c_int {
677 let child_comp = xsd_parse_component(child, schema);
678 match child_comp.component_type {
679 XsdComponentType::ComplexType | XsdComponentType::SimpleType => {
680 if let Some(ref name) = child_comp.name {
682 comp.base = Some(name.clone());
683 }
684 comp.children.push(child_comp);
685 }
686 XsdComponentType::Annotation => {
687 }
689 _ => {
690 comp.children.push(child_comp);
691 }
692 }
693 }
694 child = (*child).next;
695 }
696
697 comp
698 }
699}
700
701unsafe fn xsd_parse_attribute_node(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
707 unsafe {
708 let mut comp = XsdComponent::new(XsdComponentType::Attribute);
709 comp.name = get_attr(node, "name");
710 comp.ref_name = get_attr(node, "ref");
711 comp.form = get_attr(node, "form");
712
713 if let Some(type_name) = get_attr(node, "type") {
715 comp.datatype = parse_datatype_kind(&type_name);
716 if comp.datatype.is_none() {
717 comp.base = Some(type_name);
718 }
719 }
720
721 let use_attr = get_attr(node, "use");
723 if let Some(ref use_val) = use_attr {
724 if use_val == "required" {
725 comp.min_occurs = 1;
726 } else if use_val == "prohibited" {
727 comp.min_occurs = 0;
728 comp.max_occurs = 0;
729 } else {
730 comp.min_occurs = 0;
732 }
733 } else {
734 comp.min_occurs = 0; }
736
737 let _default = get_attr(node, "default");
738 let _fixed = get_attr(node, "fixed");
739
740 let mut child = (*node).children;
742 while !child.is_null() {
743 if (*child).type_ == XML_ELEMENT_NODE as c_int {
744 let child_comp = xsd_parse_component(child, schema);
745 match child_comp.component_type {
746 XsdComponentType::SimpleType => {
747 if let Some(ref name) = child_comp.name {
748 comp.base = Some(name.clone());
749 }
750 comp.children.push(child_comp);
751 }
752 _ => {}
753 }
754 }
755 child = (*child).next;
756 }
757
758 comp
759 }
760}
761
762unsafe fn xsd_parse_complex_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
768 unsafe {
769 let mut comp = XsdComponent::new(XsdComponentType::ComplexType);
770 comp.name = get_attr(node, "name");
771 comp.mixed = get_attr_bool(node, "mixed");
772 comp.is_abstract = get_attr_bool(node, "abstract");
773 comp.is_final = get_attr_bool(node, "final");
774
775 let mut child = (*node).children;
777 while !child.is_null() {
778 if (*child).type_ == XML_ELEMENT_NODE as c_int {
779 let child_comp = xsd_parse_component(child, schema);
780 match child_comp.component_type {
781 XsdComponentType::SimpleContent
782 | XsdComponentType::ComplexContent
783 | XsdComponentType::Sequence
784 | XsdComponentType::Choice
785 | XsdComponentType::All
786 | XsdComponentType::Group
787 | XsdComponentType::Any
788 | XsdComponentType::Annotation => {
789 if child_comp.component_type == XsdComponentType::SimpleContent {
790 comp.children.extend(child_comp.children);
792 } else if child_comp.component_type == XsdComponentType::ComplexContent {
793 comp.children.extend(child_comp.children);
795 } else {
796 comp.children.push(child_comp);
797 }
798 }
799 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
800 comp.attributes.push(child_comp);
801 }
802 _ => {
803 comp.children.push(child_comp);
804 }
805 }
806 }
807 child = (*child).next;
808 }
809
810 comp
811 }
812}
813
814unsafe fn xsd_parse_simple_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
820 unsafe {
821 let mut comp = XsdComponent::new(XsdComponentType::SimpleType);
822 comp.name = get_attr(node, "name");
823
824 let mut child = (*node).children;
826 while !child.is_null() {
827 if (*child).type_ == XML_ELEMENT_NODE as c_int {
828 let child_comp = xsd_parse_component(child, schema);
829 match child_comp.component_type {
830 XsdComponentType::Restriction
831 | XsdComponentType::List
832 | XsdComponentType::Union => {
833 comp.datatype = child_comp.datatype;
834 comp.base = child_comp.base;
835 comp.facets = child_comp.facets;
836 comp.children.extend(child_comp.children);
837 }
838 _ => {}
839 }
840 }
841 child = (*child).next;
842 }
843
844 comp
845 }
846}
847
848unsafe fn xsd_parse_model_group(
854 node: *mut _xmlNode,
855 ctype: XsdComponentType,
856 schema: &XsdSchema,
857) -> XsdComponent {
858 unsafe {
859 let mut comp = XsdComponent::new(ctype);
860 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
861 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
862
863 let mut child = (*node).children;
864 while !child.is_null() {
865 if (*child).type_ == XML_ELEMENT_NODE as c_int {
866 let child_comp = xsd_parse_component(child, schema);
867 match child_comp.component_type {
868 XsdComponentType::Annotation => {}
869 _ => {
870 comp.children.push(child_comp);
871 }
872 }
873 }
874 child = (*child).next;
875 }
876
877 comp
878 }
879}
880
881unsafe fn xsd_parse_restriction(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
887 unsafe {
888 let mut comp = XsdComponent::new(XsdComponentType::Restriction);
889 comp.base = get_attr(node, "base");
890
891 if let Some(ref base_name) = comp.base {
893 comp.datatype = parse_datatype_kind(base_name);
894 }
895
896 let mut child = (*node).children;
898 while !child.is_null() {
899 if (*child).type_ == XML_ELEMENT_NODE as c_int {
900 let child_comp = xsd_parse_component(child, schema);
901 match child_comp.component_type {
902 XsdComponentType::Sequence
903 | XsdComponentType::Choice
904 | XsdComponentType::All
905 | XsdComponentType::Group
906 | XsdComponentType::Any
907 | XsdComponentType::Annotation => {
908 comp.children.push(child_comp);
909 }
910 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
911 comp.attributes.push(child_comp);
912 }
913 XsdComponentType::SimpleType => {
914 comp.children.push(child_comp);
916 }
917 _ => {
918 if let Some(facet_kind) =
920 parse_facet_kind(&format!("{:?}", child_comp.component_type))
921 {
922 if let Some(val) = get_attr(child, "value") {
924 comp.facets.push((facet_kind, val));
925 }
926 }
927 let name_str = if !(*child).name.is_null() {
929 let mut len = 0;
930 while *(*child).name.add(len) != 0 {
931 len += 1;
932 }
933 let slice = std::slice::from_raw_parts((*child).name, len);
934 std::str::from_utf8(slice)
935 .ok()
936 .map(|s| {
937 if let Some(pos) = s.find(':') {
938 s[pos + 1..].to_string()
939 } else {
940 s.to_string()
941 }
942 })
943 .unwrap_or_default()
944 } else {
945 String::new()
946 };
947 if !name_str.is_empty() {
948 if let Some(facet_kind) = parse_facet_kind(&name_str) {
949 if let Some(val) = get_attr(child, "value") {
950 comp.facets.push((facet_kind, val));
951 }
952 }
953 }
954 }
955 }
956 }
957 child = (*child).next;
958 }
959
960 comp
961 }
962}
963
964unsafe fn xsd_parse_extension(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
970 unsafe {
971 let mut comp = XsdComponent::new(XsdComponentType::Extension);
972 comp.base = get_attr(node, "base");
973
974 if let Some(ref base_name) = comp.base {
975 comp.datatype = parse_datatype_kind(base_name);
976 }
977
978 let mut child = (*node).children;
980 while !child.is_null() {
981 if (*child).type_ == XML_ELEMENT_NODE as c_int {
982 let child_comp = xsd_parse_component(child, schema);
983 match child_comp.component_type {
984 XsdComponentType::Sequence
985 | XsdComponentType::Choice
986 | XsdComponentType::All
987 | XsdComponentType::Group
988 | XsdComponentType::Any
989 | XsdComponentType::Annotation => {
990 comp.children.push(child_comp);
991 }
992 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
993 comp.attributes.push(child_comp);
994 }
995 _ => {}
996 }
997 }
998 child = (*child).next;
999 }
1000
1001 comp
1002 }
1003}
1004
1005unsafe fn xsd_parse_list(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1011 unsafe {
1012 let mut comp = XsdComponent::new(XsdComponentType::List);
1013
1014 if let Some(item_type) = get_attr(node, "itemType") {
1015 comp.base = Some(item_type.clone());
1016 comp.datatype = parse_datatype_kind(&item_type);
1017 }
1018
1019 let mut child = (*node).children;
1021 while !child.is_null() {
1022 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1023 let child_comp = xsd_parse_component(child, schema);
1024 match child_comp.component_type {
1025 XsdComponentType::SimpleType => {
1026 comp.datatype = child_comp.datatype;
1027 comp.base = child_comp.base;
1028 comp.facets = child_comp.facets;
1029 }
1030 _ => {}
1031 }
1032 }
1033 child = (*child).next;
1034 }
1035
1036 comp
1037 }
1038}
1039
1040unsafe fn xsd_parse_union(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1046 unsafe {
1047 let mut comp = XsdComponent::new(XsdComponentType::Union);
1048
1049 if let Some(member_types) = get_attr(node, "memberTypes") {
1050 comp.base = Some(member_types);
1051 }
1052
1053 let mut child = (*node).children;
1054 while !child.is_null() {
1055 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1056 let child_comp = xsd_parse_component(child, schema);
1057 match child_comp.component_type {
1058 XsdComponentType::SimpleType => {
1059 comp.children.push(child_comp);
1060 }
1061 _ => {}
1062 }
1063 }
1064 child = (*child).next;
1065 }
1066
1067 comp
1068 }
1069}
1070
1071unsafe fn xsd_parse_annotation(node: *mut _xmlNode) -> XsdComponent {
1077 unsafe {
1078 let mut comp = XsdComponent::new(XsdComponentType::Annotation);
1079
1080 let mut child = (*node).children;
1081 while !child.is_null() {
1082 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1083 if node_is(child, "documentation") || node_is(child, "appinfo") {
1084 let text = get_node_text(child);
1085 if !text.is_empty() {
1086 comp.facets.push((XsdDatatypeKind::String, text));
1087 }
1088 }
1089 }
1090 child = (*child).next;
1091 }
1092
1093 comp
1094 }
1095}
1096
1097unsafe fn xsd_parse_any(node: *mut _xmlNode, _schema: &XsdSchema) -> XsdComponent {
1103 unsafe {
1104 let mut comp = XsdComponent::new(XsdComponentType::Any);
1105 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1106 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1107
1108 let namespace_attr = get_attr(node, "namespace");
1109 if let Some(ref ns) = namespace_attr {
1110 if ns != "##any" {
1111 comp.target_namespace = Some(ns.clone());
1112 }
1113 }
1114
1115 comp
1116 }
1117}
1118
1119unsafe fn xsd_parse_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1125 unsafe {
1126 let mut comp = XsdComponent::new(XsdComponentType::Group);
1127 comp.name = get_attr(node, "name");
1128 comp.ref_name = get_attr(node, "ref");
1129 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1130 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1131
1132 let mut child = (*node).children;
1133 while !child.is_null() {
1134 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1135 let child_comp = xsd_parse_component(child, schema);
1136 match child_comp.component_type {
1137 XsdComponentType::Annotation => {}
1138 _ => {
1139 comp.children.push(child_comp);
1140 }
1141 }
1142 }
1143 child = (*child).next;
1144 }
1145
1146 comp
1147 }
1148}
1149
1150unsafe fn xsd_parse_attribute_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1156 unsafe {
1157 let mut comp = XsdComponent::new(XsdComponentType::AttributeGroup);
1158 comp.name = get_attr(node, "name");
1159 comp.ref_name = get_attr(node, "ref");
1160
1161 let mut child = (*node).children;
1162 while !child.is_null() {
1163 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1164 let child_comp = xsd_parse_component(child, schema);
1165 match child_comp.component_type {
1166 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1167 comp.attributes.push(child_comp);
1168 }
1169 _ => {}
1170 }
1171 }
1172 child = (*child).next;
1173 }
1174
1175 comp
1176 }
1177}
1178
1179unsafe fn xsd_parse_facet(node: *mut _xmlNode) -> XsdComponent {
1185 unsafe {
1186 let name_str = if !(*node).name.is_null() {
1187 let mut len = 0;
1188 while *(*node).name.add(len) != 0 {
1189 len += 1;
1190 }
1191 let slice = std::slice::from_raw_parts((*node).name, len);
1192 std::str::from_utf8(slice)
1193 .ok()
1194 .map(|s| {
1195 if let Some(pos) = s.find(':') {
1196 s[pos + 1..].to_string()
1197 } else {
1198 s.to_string()
1199 }
1200 })
1201 .unwrap_or_default()
1202 } else {
1203 String::new()
1204 };
1205
1206 let facet_kind = parse_facet_kind(&name_str).unwrap_or(XsdDatatypeKind::String);
1207 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1208 let val = get_attr(node, "value").unwrap_or_default();
1209 comp.facets.push((facet_kind, val));
1210 comp.datatype = Some(facet_kind);
1211
1212 comp
1213 }
1214}
1215
1216unsafe fn xsd_parse_simple_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1222 unsafe {
1223 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1224
1225 let mut child = (*node).children;
1226 while !child.is_null() {
1227 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1228 let child_comp = xsd_parse_component(child, schema);
1229 match child_comp.component_type {
1230 XsdComponentType::Restriction | XsdComponentType::Extension => {
1231 comp.children.push(child_comp);
1232 }
1233 _ => {}
1234 }
1235 }
1236 child = (*child).next;
1237 }
1238
1239 comp
1240 }
1241}
1242
1243unsafe fn xsd_parse_complex_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1249 unsafe {
1250 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1251
1252 let mut child = (*node).children;
1253 while !child.is_null() {
1254 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1255 let child_comp = xsd_parse_component(child, schema);
1256 match child_comp.component_type {
1257 XsdComponentType::Restriction | XsdComponentType::Extension => {
1258 comp.children.push(child_comp);
1259 }
1260 _ => {}
1261 }
1262 }
1263 child = (*child).next;
1264 }
1265
1266 comp
1267 }
1268}
1269
1270unsafe fn xsd_parse_identity_constraint(
1276 node: *mut _xmlNode,
1277 ctype: XsdComponentType,
1278 schema: &XsdSchema,
1279) -> XsdComponent {
1280 unsafe {
1281 let mut comp = XsdComponent::new(ctype);
1282 comp.name = get_attr(node, "name");
1283
1284 if ctype == XsdComponentType::KeyRef {
1285 comp.ref_name = get_attr(node, "refer");
1286 }
1287
1288 let mut child = (*node).children;
1289 while !child.is_null() {
1290 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1291 let child_comp = xsd_parse_component(child, schema);
1292 match child_comp.component_type {
1293 XsdComponentType::Selector | XsdComponentType::Field => {
1294 comp.children.push(child_comp);
1295 }
1296 _ => {}
1297 }
1298 }
1299 child = (*child).next;
1300 }
1301
1302 comp
1303 }
1304}
1305
1306pub fn xsd_validate_datatype(
1316 kind: &XsdDatatypeKind,
1317 value: &str,
1318 facets: &[(XsdDatatypeKind, String)],
1319) -> bool {
1320 if !validate_base_type(kind, value) {
1322 return false;
1323 }
1324
1325 let mut has_enumeration = false;
1330 let mut enumeration_match = false;
1331
1332 for (facet_kind, facet_value) in facets {
1333 if *facet_kind == XsdDatatypeKind::FacetEnumeration {
1334 has_enumeration = true;
1335 if xsd_validate_facet(kind, value, facet_kind, facet_value) {
1336 enumeration_match = true;
1337 }
1338 } else if !xsd_validate_facet(kind, value, facet_kind, facet_value) {
1339 return false;
1340 }
1341 }
1342
1343 if has_enumeration && !enumeration_match {
1345 return false;
1346 }
1347
1348 true
1349}
1350
1351pub fn xsd_validate_facet(
1353 _kind: &XsdDatatypeKind,
1354 value: &str,
1355 facet_kind: &XsdDatatypeKind,
1356 facet_value: &str,
1357) -> bool {
1358 match facet_kind {
1359 XsdDatatypeKind::FacetPattern => {
1360 match facet_value {
1363 r"\d+" => value.chars().all(|c| c.is_ascii_digit()),
1364 r"\d*" => value.is_empty() || value.chars().all(|c| c.is_ascii_digit()),
1365 r"[a-zA-Z]+" => value.chars().all(|c| c.is_ascii_alphabetic()),
1366 r"[a-zA-Z]*" => value.is_empty() || value.chars().all(|c| c.is_ascii_alphabetic()),
1367 r"[a-zA-Z0-9]+" => value.chars().all(|c| c.is_ascii_alphanumeric()),
1368 r"[a-zA-Z0-9_\-]+" => value
1369 .chars()
1370 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
1371 r"[a-zA-Z_][a-zA-Z0-9_\-\.]*" => {
1372 if value.is_empty() {
1373 return false;
1374 }
1375 let first = value.chars().next().unwrap();
1376 if !first.is_ascii_alphabetic() && first != '_' {
1377 return false;
1378 }
1379 value
1380 .chars()
1381 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1382 }
1383 r"[a-zA-Z_][\w\-\.]*" => {
1384 if value.is_empty() {
1385 return false;
1386 }
1387 let first = value.chars().next().unwrap();
1388 if !first.is_ascii_alphabetic() && first != '_' {
1389 return false;
1390 }
1391 value
1392 .chars()
1393 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1394 }
1395 r"\i\c*" => {
1396 if value.is_empty() {
1398 return false;
1399 }
1400 let first = value.chars().next().unwrap();
1401 if !is_name_start_char(first) {
1402 return false;
1403 }
1404 value.chars().skip(1).all(is_name_char)
1405 }
1406 r"\c+" => {
1407 if value.is_empty() {
1408 return false;
1409 }
1410 value.chars().all(is_name_char)
1411 }
1412 _ => {
1414 if facet_value.starts_with('^') && facet_value.ends_with('$') {
1415 let inner = &facet_value[1..facet_value.len() - 1];
1416 simple_glob_match(inner, value)
1417 } else {
1418 true
1420 }
1421 }
1422 }
1423 }
1424 XsdDatatypeKind::FacetEnumeration => {
1425 value == facet_value
1427 }
1428 XsdDatatypeKind::FacetMinInclusive => {
1429 compare_strings(value, facet_value) != std::cmp::Ordering::Less
1430 }
1431 XsdDatatypeKind::FacetMaxInclusive => {
1432 compare_strings(value, facet_value) != std::cmp::Ordering::Greater
1433 }
1434 XsdDatatypeKind::FacetMinExclusive => {
1435 compare_strings(value, facet_value) == std::cmp::Ordering::Greater
1436 }
1437 XsdDatatypeKind::FacetMaxExclusive => {
1438 compare_strings(value, facet_value) == std::cmp::Ordering::Less
1439 }
1440 XsdDatatypeKind::FacetMinLength => {
1441 let min = facet_value.parse::<usize>().unwrap_or(0);
1442 value.chars().count() >= min
1443 }
1444 XsdDatatypeKind::FacetMaxLength => {
1445 let max = facet_value.parse::<usize>().unwrap_or(usize::MAX);
1446 value.chars().count() <= max
1447 }
1448 XsdDatatypeKind::FacetLength => {
1449 let len = facet_value.parse::<usize>().unwrap_or(0);
1450 value.chars().count() == len
1451 }
1452 XsdDatatypeKind::FacetWhiteSpace => {
1453 match facet_value {
1455 "replace" => {
1456 true
1459 }
1460 "collapse" => {
1461 true
1463 }
1464 _ => true,
1465 }
1466 }
1467 XsdDatatypeKind::FacetFractionDigits | XsdDatatypeKind::FacetTotalDigits => {
1468 value.parse::<f64>().is_ok()
1470 }
1471 _ => true,
1472 }
1473}
1474
1475fn simple_glob_match(pattern: &str, value: &str) -> bool {
1477 let pattern_chars: Vec<char> = pattern.chars().collect();
1478 let value_chars: Vec<char> = value.chars().collect();
1479
1480 let mut pi = 0;
1481 let mut vi = 0;
1482 let mut backtrack_p = None;
1483 let mut backtrack_v = 0;
1484
1485 while vi < value_chars.len() {
1486 if pi < pattern_chars.len()
1487 && (pattern_chars[pi] == value_chars[vi] || pattern_chars[pi] == '.')
1488 {
1489 pi += 1;
1490 vi += 1;
1491 } else if pi < pattern_chars.len() && pattern_chars[pi] == '*' {
1492 backtrack_p = Some(pi);
1493 backtrack_v = vi + 1;
1494 pi += 1;
1495 } else if pi < pattern_chars.len() && pattern_chars[pi] == '+' {
1496 if pi + 1 < pattern_chars.len() && pattern_chars[pi + 1] == value_chars[vi] {
1498 pi += 1;
1499 vi += 1;
1500 while vi < value_chars.len() && value_chars[vi] == pattern_chars[pi] {
1502 vi += 1;
1503 }
1504 pi += 1;
1505 } else {
1506 return false;
1507 }
1508 } else if let Some(bp) = backtrack_p {
1509 pi = bp + 1;
1510 vi = backtrack_v;
1511 backtrack_v += 1;
1512 } else {
1513 return false;
1514 }
1515 }
1516
1517 while pi < pattern_chars.len() && (pattern_chars[pi] == '*' || pattern_chars[pi] == '+') {
1519 if pattern_chars[pi] == '+' && vi == value_chars.len() {
1520 return false; }
1522 pi += 1;
1523 }
1524
1525 pi == pattern_chars.len()
1526}
1527
1528fn is_name_start_char(c: char) -> bool {
1530 c.is_ascii_alphabetic()
1531 || c == '_'
1532 || c == ':'
1533 || (c >= '\u{00C0}' && c <= '\u{00D6}')
1534 || (c >= '\u{00D8}' && c <= '\u{00F6}')
1535 || (c >= '\u{00F8}' && c <= '\u{02FF}')
1536 || (c >= '\u{0370}' && c <= '\u{037D}')
1537 || (c >= '\u{037F}' && c <= '\u{1FFF}')
1538 || (c >= '\u{200C}' && c <= '\u{200D}')
1539 || (c >= '\u{2070}' && c <= '\u{218F}')
1540 || (c >= '\u{2C00}' && c <= '\u{2FEF}')
1541 || (c >= '\u{3001}' && c <= '\u{D7FF}')
1542 || (c >= '\u{F900}' && c <= '\u{FDCF}')
1543 || (c >= '\u{FDF0}' && c <= '\u{FFFD}')
1544}
1545
1546fn is_name_char(c: char) -> bool {
1548 is_name_start_char(c)
1549 || c.is_ascii_digit()
1550 || c == '-'
1551 || c == '.'
1552 || c == '\u{00B7}'
1553 || (c >= '\u{0300}' && c <= '\u{036F}')
1554 || (c >= '\u{203F}' && c <= '\u{2040}')
1555}
1556
1557fn compare_strings(a: &str, b: &str) -> std::cmp::Ordering {
1559 if let (Ok(na), Ok(nb)) = (a.parse::<f64>(), b.parse::<f64>()) {
1561 return na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal);
1562 }
1563 if let (Ok(na), Ok(nb)) = (a.parse::<i64>(), b.parse::<i64>()) {
1565 return na.cmp(&nb);
1566 }
1567 a.cmp(b)
1569}
1570
1571fn validate_base_type(kind: &XsdDatatypeKind, value: &str) -> bool {
1573 match kind {
1574 XsdDatatypeKind::String => true,
1575 XsdDatatypeKind::NormalizedString => {
1576 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1578 }
1579 XsdDatatypeKind::Token => {
1580 if value.is_empty() {
1582 return true;
1583 }
1584 if value.starts_with(' ') || value.ends_with(' ') {
1585 return false;
1586 }
1587 !value.contains(" ")
1588 && !value.contains('\t')
1589 && !value.contains('\n')
1590 && !value.contains('\r')
1591 }
1592 XsdDatatypeKind::Language => {
1593 if value.is_empty() {
1596 return false;
1597 }
1598 let segments: Vec<&str> = value.split('-').collect();
1599 if segments.is_empty() {
1600 return false;
1601 }
1602 if segments[0].is_empty() || !segments[0].chars().all(|c| c.is_ascii_alphabetic()) {
1604 return false;
1605 }
1606 if segments[0].len() > 8 {
1607 return false;
1608 }
1609 for seg in &segments[1..] {
1611 if seg.is_empty() || seg.len() > 8 {
1612 return false;
1613 }
1614 if !seg.chars().all(|c| c.is_ascii_alphanumeric()) {
1615 return false;
1616 }
1617 }
1618 true
1619 }
1620 XsdDatatypeKind::Name => {
1621 if value.is_empty() {
1622 return false;
1623 }
1624 let mut chars = value.chars();
1625 let first = chars.next().unwrap();
1626 if !is_name_start_char(first) {
1627 return false;
1628 }
1629 chars.all(is_name_char)
1630 }
1631 XsdDatatypeKind::NCName
1632 | XsdDatatypeKind::Id
1633 | XsdDatatypeKind::Idref
1634 | XsdDatatypeKind::Entity => {
1635 if value.is_empty() || value.contains(':') {
1637 return false;
1638 }
1639 let mut chars = value.chars();
1640 let first = chars.next().unwrap();
1641 if !is_name_start_char(first) {
1642 return false;
1643 }
1644 chars.all(is_name_char)
1645 }
1646 XsdDatatypeKind::Boolean => {
1647 matches!(value, "true" | "false" | "1" | "0")
1648 }
1649 XsdDatatypeKind::Decimal
1650 | XsdDatatypeKind::Integer
1651 | XsdDatatypeKind::NonPositiveInteger
1652 | XsdDatatypeKind::NegativeInteger
1653 | XsdDatatypeKind::Long
1654 | XsdDatatypeKind::Int
1655 | XsdDatatypeKind::Short
1656 | XsdDatatypeKind::Byte
1657 | XsdDatatypeKind::NonNegativeInteger
1658 | XsdDatatypeKind::UnsignedLong
1659 | XsdDatatypeKind::UnsignedInt
1660 | XsdDatatypeKind::UnsignedShort
1661 | XsdDatatypeKind::UnsignedByte
1662 | XsdDatatypeKind::PositiveInteger => {
1663 if value.is_empty() {
1665 return false;
1666 }
1667 let mut chars = value.chars().peekable();
1668 if *chars.peek().unwrap_or(&'\0') == '-' || *chars.peek().unwrap_or(&'\0') == '+' {
1669 chars.next();
1670 }
1671 let mut has_dot = false;
1672 let mut has_digit = false;
1673 for c in chars {
1674 if c == '.' {
1675 if has_dot {
1676 return false;
1677 }
1678 has_dot = true;
1679 } else if c.is_ascii_digit() {
1680 has_digit = true;
1681 } else {
1682 return false;
1683 }
1684 }
1685 if !has_digit {
1686 return false;
1687 }
1688
1689 if has_dot && *kind != XsdDatatypeKind::Decimal {
1692 return false;
1693 }
1694
1695 match kind {
1696 XsdDatatypeKind::NonPositiveInteger => {
1697 if let Ok(v) = value.parse::<i64>() {
1698 v <= 0
1699 } else {
1700 false
1701 }
1702 }
1703 XsdDatatypeKind::NegativeInteger => {
1704 if let Ok(v) = value.parse::<i64>() {
1705 v < 0
1706 } else {
1707 false
1708 }
1709 }
1710 XsdDatatypeKind::NonNegativeInteger => {
1711 if let Ok(v) = value.parse::<i64>() {
1712 v >= 0
1713 } else {
1714 false
1715 }
1716 }
1717 XsdDatatypeKind::PositiveInteger => {
1718 if let Ok(v) = value.parse::<i64>() {
1719 v > 0
1720 } else {
1721 false
1722 }
1723 }
1724 XsdDatatypeKind::UnsignedLong
1725 | XsdDatatypeKind::UnsignedInt
1726 | XsdDatatypeKind::UnsignedShort
1727 | XsdDatatypeKind::UnsignedByte => {
1728 if let Ok(v) = value.parse::<u64>() {
1729 match kind {
1730 XsdDatatypeKind::UnsignedInt => v <= u64::from(u32::MAX),
1731 XsdDatatypeKind::UnsignedShort => v <= u64::from(u16::MAX),
1732 XsdDatatypeKind::UnsignedByte => v <= u64::from(u8::MAX),
1733 _ => true,
1734 }
1735 } else {
1736 false
1737 }
1738 }
1739 XsdDatatypeKind::Long => value.parse::<i64>().is_ok(),
1740 XsdDatatypeKind::Int => value.parse::<i32>().is_ok(),
1741 XsdDatatypeKind::Short => value.parse::<i16>().is_ok(),
1742 XsdDatatypeKind::Byte => value.parse::<i8>().is_ok(),
1743 _ => true,
1744 }
1745 }
1746 XsdDatatypeKind::Float | XsdDatatypeKind::Double => {
1747 matches!(value, "INF" | "-INF" | "NaN") || value.parse::<f64>().is_ok()
1749 }
1750 XsdDatatypeKind::Duration => {
1751 if !value.starts_with('-') && !value.starts_with('P') {
1753 return false;
1754 }
1755 let dur = if value.starts_with('-') {
1756 &value[1..]
1757 } else {
1758 value
1759 };
1760 if !dur.starts_with('P') {
1761 return false;
1762 }
1763 let rest = &dur[1..];
1764 if rest.is_empty() {
1765 return false;
1766 }
1767 let has_t = rest.contains('T');
1768 let date_part = if has_t {
1769 &rest[..rest.find('T').unwrap()]
1770 } else {
1771 rest
1772 };
1773 if has_t {
1774 let time_part = &rest[rest.find('T').unwrap() + 1..];
1775 if time_part.is_empty() {
1776 return false;
1777 }
1778 }
1779 true
1780 }
1781 XsdDatatypeKind::DateTime => {
1782 if value.len() < 19 {
1784 return false;
1785 }
1786 let chars: Vec<char> = value.chars().collect();
1787 chars[4] == '-'
1788 && chars[7] == '-'
1789 && chars[10] == 'T'
1790 && chars[13] == ':'
1791 && chars[16] == ':'
1792 }
1793 XsdDatatypeKind::Date => {
1794 if value.len() < 10 {
1796 return false;
1797 }
1798 let chars: Vec<char> = value.chars().collect();
1799 chars[4] == '-' && chars[7] == '-'
1800 }
1801 XsdDatatypeKind::Time => {
1802 if value.len() < 8 {
1804 return false;
1805 }
1806 let chars: Vec<char> = value.chars().collect();
1807 chars[2] == ':' && chars[5] == ':'
1808 }
1809 XsdDatatypeKind::GYear => {
1810 if value.len() < 4 {
1812 return false;
1813 }
1814 value.chars().take(4).all(|c| c.is_ascii_digit())
1815 }
1816 XsdDatatypeKind::GYearMonth => {
1817 if value.len() < 7 {
1819 return false;
1820 }
1821 let chars: Vec<char> = value.chars().collect();
1822 chars[4] == '-'
1823 }
1824 XsdDatatypeKind::GMonthDay => {
1825 if value.len() < 6 || !value.starts_with("--") {
1827 return false;
1828 }
1829 let chars: Vec<char> = value.chars().collect();
1830 chars[4] == '-'
1831 }
1832 XsdDatatypeKind::GDay => {
1833 value.starts_with("---") && value.len() >= 4
1835 }
1836 XsdDatatypeKind::GMonth => {
1837 value.starts_with("--") && value.len() >= 3
1839 }
1840 XsdDatatypeKind::HexBinary => {
1841 if value.len() % 2 != 0 {
1842 return false;
1843 }
1844 value.chars().all(|c| c.is_ascii_hexdigit())
1845 }
1846 XsdDatatypeKind::Base64Binary => {
1847 if value.is_empty() {
1849 return true;
1850 }
1851 let valid_chars =
1852 |c: char| c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=';
1853 value.chars().all(valid_chars)
1854 }
1855 XsdDatatypeKind::AnyURI => {
1856 !value.is_empty()
1858 }
1859 XsdDatatypeKind::QName => {
1860 if let Some(pos) = value.find(':') {
1862 let prefix = &value[..pos];
1863 let local = &value[pos + 1..];
1864 is_ncname(prefix) && is_ncname(local)
1865 } else {
1866 is_ncname(value)
1867 }
1868 }
1869 XsdDatatypeKind::Notation => {
1870 !value.is_empty()
1872 }
1873 XsdDatatypeKind::NormalizedString => {
1874 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1876 }
1877 XsdDatatypeKind::Token => {
1878 validate_base_type(&XsdDatatypeKind::NormalizedString, value)
1880 && !value.starts_with(' ')
1881 && !value.ends_with(' ')
1882 && !value.contains(" ")
1883 }
1884 XsdDatatypeKind::Language => {
1885 if value.is_empty() {
1887 return false;
1888 }
1889 let parts: Vec<&str> = value.split('-').collect();
1890 if parts.is_empty() {
1891 return false;
1892 }
1893 if parts[0].len() > 8 || !parts[0].chars().all(|c| c.is_ascii_alphabetic()) {
1894 return false;
1895 }
1896 parts.iter().skip(1).all(|p| {
1897 !p.is_empty() && p.len() <= 8 && p.chars().all(|c| c.is_ascii_alphanumeric())
1898 })
1899 }
1900 XsdDatatypeKind::Nmtoken => !value.is_empty() && value.chars().all(is_name_char),
1901 XsdDatatypeKind::Nmtokens => {
1902 !value.is_empty()
1903 && value
1904 .split_whitespace()
1905 .all(|t| !t.is_empty() && t.chars().all(is_name_char))
1906 }
1907 XsdDatatypeKind::Name => {
1908 !value.is_empty() && {
1909 let first = value.chars().next().unwrap();
1910 is_name_start_char(first) && value.chars().skip(1).all(is_name_char)
1911 }
1912 }
1913 XsdDatatypeKind::NCName => is_ncname(value),
1914 XsdDatatypeKind::Id | XsdDatatypeKind::Idref | XsdDatatypeKind::Entity => is_ncname(value),
1915 XsdDatatypeKind::Idrefs | XsdDatatypeKind::Entities => {
1916 !value.is_empty() && value.split_whitespace().all(|t| is_ncname(t))
1917 }
1918 XsdDatatypeKind::FacetPattern
1920 | XsdDatatypeKind::FacetEnumeration
1921 | XsdDatatypeKind::FacetMinInclusive
1922 | XsdDatatypeKind::FacetMaxInclusive
1923 | XsdDatatypeKind::FacetMinExclusive
1924 | XsdDatatypeKind::FacetMaxExclusive
1925 | XsdDatatypeKind::FacetMinLength
1926 | XsdDatatypeKind::FacetMaxLength
1927 | XsdDatatypeKind::FacetLength
1928 | XsdDatatypeKind::FacetWhiteSpace
1929 | XsdDatatypeKind::FacetFractionDigits
1930 | XsdDatatypeKind::FacetTotalDigits => true,
1931 }
1932}
1933
1934fn is_ncname(value: &str) -> bool {
1936 if value.is_empty() {
1937 return false;
1938 }
1939 let first = value.chars().next().unwrap();
1940 if !is_name_start_char(first) || first == ':' {
1941 return false;
1942 }
1943 value.chars().skip(1).all(|c| is_name_char(c) && c != ':')
1944}
1945
1946pub fn xsd_validate(schema: &XsdSchema, doc: &str) -> Result<(), Vec<String>> {
1956 let doc_ptr = unsafe {
1957 crate::abi::exports_xml2::xmlReadMemory(
1958 doc.as_ptr() as *const c_char,
1959 doc.len() as c_int,
1960 b"doc.xml\0".as_ptr() as *const c_char,
1961 ptr::null(),
1962 0,
1963 )
1964 };
1965
1966 if doc_ptr.is_null() {
1967 return Err(vec!["Failed to parse XML document".to_string()]);
1968 }
1969
1970 let mut ctxt = XsdValidCtxt::new();
1971 ctxt.schema = Some(schema.clone());
1972
1973 let result = unsafe { xsd_validate_doc(schema, doc_ptr, &mut ctxt) };
1974
1975 unsafe {
1976 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
1977 }
1978
1979 if result {
1980 Ok(())
1981 } else {
1982 Err(ctxt.errors)
1983 }
1984}
1985
1986unsafe fn xsd_validate_doc(schema: &XsdSchema, doc: *mut _xmlDoc, ctxt: &mut XsdValidCtxt) -> bool {
1992 unsafe {
1993 let root = (*doc).children;
1994 if root.is_null() {
1995 ctxt.errors.push("Document has no root element".to_string());
1996 ctxt.nb_errors += 1;
1997 return false;
1998 }
1999
2000 let mut root_elem = root;
2002 while !root_elem.is_null() && (*root_elem).type_ != XML_ELEMENT_NODE as c_int {
2003 root_elem = (*root_elem).next;
2004 }
2005
2006 if root_elem.is_null() {
2007 ctxt.errors.push("Document has no root element".to_string());
2008 ctxt.nb_errors += 1;
2009 return false;
2010 }
2011
2012 let root_name = get_node_qname(root_elem);
2014
2015 let global_elem = schema.components.iter().find(|c| {
2017 c.component_type == XsdComponentType::Element && c.name.as_deref() == Some(&root_name)
2018 });
2019
2020 if let Some(global) = global_elem {
2021 xsd_validate_element(global, root_elem, schema, ctxt)
2022 } else {
2023 let mut valid = true;
2025 for component in &schema.components {
2026 if component.component_type == XsdComponentType::Element {
2027 if let Some(ref name) = component.name {
2028 if *name == root_name {
2029 valid = xsd_validate_element(component, root_elem, schema, ctxt);
2030 break;
2031 }
2032 }
2033 }
2034 }
2035 valid
2036 }
2037 }
2038}
2039
2040fn xsd_validate_element(
2046 component: &XsdComponent,
2047 node: *mut _xmlNode,
2048 schema: &XsdSchema,
2049 ctxt: &mut XsdValidCtxt,
2050) -> bool {
2051 unsafe {
2052 let mut valid = true;
2053
2054 let node_name = get_node_qname(node);
2056
2057 if let Some(ref comp_name) = component.name {
2059 if comp_name != &node_name {
2060 ctxt.errors.push(format!(
2061 "Element '{}' does not match expected '{}'",
2062 node_name, comp_name
2063 ));
2064 ctxt.nb_errors += 1;
2065 return false;
2066 }
2067 }
2068
2069 let type_comp = component.children.iter().find(|c| {
2071 c.component_type == XsdComponentType::ComplexType
2072 || c.component_type == XsdComponentType::SimpleType
2073 });
2074
2075 if let Some(tc) = type_comp {
2076 match tc.component_type {
2077 XsdComponentType::ComplexType => {
2078 valid &= xsd_validate_complex_type(tc, node, schema, ctxt);
2079 }
2080 XsdComponentType::SimpleType => {
2081 let text = get_node_text(node);
2082 if let Some(ref dt) = tc.datatype {
2083 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2084 ctxt.errors.push(format!(
2085 "Element '{}' has invalid value '{}' for type '{:?}'",
2086 node_name, text, dt
2087 ));
2088 ctxt.nb_errors += 1;
2089 valid = false;
2090 }
2091 }
2092 }
2093 _ => {}
2094 }
2095 } else if let Some(ref dt) = component.datatype {
2096 let text = get_node_text(node);
2098 if !xsd_validate_datatype(dt, &text, &component.facets) {
2099 ctxt.errors.push(format!(
2100 "Element '{}' has invalid value '{}' for type '{:?}'",
2101 node_name, text, dt
2102 ));
2103 ctxt.nb_errors += 1;
2104 valid = false;
2105 }
2106 } else {
2107 valid &= xsd_validate_content(component, node, schema, ctxt);
2109 }
2110
2111 valid
2112 }
2113}
2114
2115fn xsd_validate_complex_type(
2121 component: &XsdComponent,
2122 node: *mut _xmlNode,
2123 schema: &XsdSchema,
2124 ctxt: &mut XsdValidCtxt,
2125) -> bool {
2126 unsafe {
2127 let mut valid = true;
2128
2129 for attr in &component.attributes {
2131 match attr.component_type {
2132 XsdComponentType::Attribute => {
2133 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2134 }
2135 XsdComponentType::AnyAttribute => {
2136 }
2138 _ => {}
2139 }
2140 }
2141
2142 for child in &component.children {
2144 match child.component_type {
2145 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2146 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2147 }
2148 XsdComponentType::Restriction | XsdComponentType::Extension => {
2149 valid &= xsd_validate_restriction_extension(child, node, schema, ctxt);
2151 }
2152 XsdComponentType::Any => {
2153 }
2155 _ => {}
2156 }
2157 }
2158
2159 valid
2160 }
2161}
2162
2163fn xsd_validate_model_group(
2169 component: &XsdComponent,
2170 node: *mut _xmlNode,
2171 schema: &XsdSchema,
2172 ctxt: &mut XsdValidCtxt,
2173) -> bool {
2174 unsafe {
2175 let mut valid = true;
2176
2177 let mut child_nodes: Vec<*mut _xmlNode> = Vec::new();
2179 let mut child = (*node).children;
2180 while !child.is_null() {
2181 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2182 child_nodes.push(child);
2183 }
2184 child = (*child).next;
2185 }
2186
2187 match component.component_type {
2188 XsdComponentType::Sequence => {
2189 let mut child_idx = 0;
2191 for part in &component.children {
2192 let min = part.min_occurs;
2193 let max = part.max_occurs;
2194 let match_name = part.name.as_deref().unwrap_or("");
2195 let match_ref = part.ref_name.as_deref().unwrap_or("");
2196
2197 let mut count = 0;
2198 while child_idx < child_nodes.len() && (max == -1 || count < max) {
2199 let child_node = child_nodes[child_idx];
2200 let child_name = get_node_qname(child_node);
2201
2202 if part.component_type == XsdComponentType::Any {
2203 count += 1;
2204 child_idx += 1;
2205 } else if !match_name.is_empty() && child_name == match_name {
2206 count += 1;
2207 child_idx += 1;
2208 } else if !match_ref.is_empty() && child_name == match_ref {
2209 count += 1;
2210 child_idx += 1;
2211 } else if count >= min {
2212 break;
2213 } else {
2214 ctxt.errors.push(format!(
2215 "Expected element '{}' but found '{}'",
2216 match_name, child_name
2217 ));
2218 ctxt.nb_errors += 1;
2219 valid = false;
2220 child_idx += 1;
2221 break;
2222 }
2223 }
2224
2225 if count < min {
2226 ctxt.errors.push(format!(
2227 "Element '{}' occurs {} times, minimum is {}",
2228 if match_name.is_empty() {
2229 "?"
2230 } else {
2231 match_name
2232 },
2233 count,
2234 min
2235 ));
2236 ctxt.nb_errors += 1;
2237 valid = false;
2238 }
2239 }
2240
2241 if child_idx < child_nodes.len() {
2243 let extra = get_node_qname(child_nodes[child_idx]);
2244 ctxt.errors
2245 .push(format!("Unexpected element '{}' in sequence", extra));
2246 ctxt.nb_errors += 1;
2247 valid = false;
2248 }
2249 }
2250 XsdComponentType::Choice => {
2251 let mut matched = false;
2253 for child_node in &child_nodes {
2254 let child_name = get_node_qname(*child_node);
2255 for part in &component.children {
2256 let match_name = part.name.as_deref().unwrap_or("");
2257 let match_ref = part.ref_name.as_deref().unwrap_or("");
2258
2259 if part.component_type == XsdComponentType::Any {
2260 matched = true;
2261 } else if (!match_name.is_empty() && child_name == match_name)
2262 || (!match_ref.is_empty() && child_name == match_ref)
2263 {
2264 matched = true;
2265 break;
2266 }
2267 }
2268 if !matched {
2269 ctxt.errors
2270 .push(format!("Element '{}' is not valid in choice", child_name));
2271 ctxt.nb_errors += 1;
2272 valid = false;
2273 }
2274 matched = false; }
2276 }
2277 XsdComponentType::All => {
2278 for child_node in &child_nodes {
2280 let child_name = get_node_qname(*child_node);
2281 let mut matched = false;
2282 for part in &component.children {
2283 let match_name = part.name.as_deref().unwrap_or("");
2284 if !match_name.is_empty() && child_name == match_name {
2285 matched = true;
2286 break;
2287 }
2288 }
2289 if !matched {
2290 ctxt.errors.push(format!(
2291 "Element '{}' is not valid in all group",
2292 child_name
2293 ));
2294 ctxt.nb_errors += 1;
2295 valid = false;
2296 }
2297 }
2298 }
2299 _ => {}
2300 }
2301
2302 valid
2303 }
2304}
2305
2306fn xsd_validate_restriction_extension(
2312 component: &XsdComponent,
2313 node: *mut _xmlNode,
2314 schema: &XsdSchema,
2315 ctxt: &mut XsdValidCtxt,
2316) -> bool {
2317 unsafe {
2318 let mut valid = true;
2319
2320 for attr in &component.attributes {
2322 match attr.component_type {
2323 XsdComponentType::Attribute => {
2324 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2325 }
2326 _ => {}
2327 }
2328 }
2329
2330 for child in &component.children {
2332 match child.component_type {
2333 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2334 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2335 }
2336 _ => {}
2337 }
2338 }
2339
2340 if let Some(ref dt) = component.datatype {
2342 let text = get_node_text(node);
2343 if !xsd_validate_datatype(dt, &text, &component.facets) {
2344 let node_name = get_node_qname(node);
2345 ctxt.errors.push(format!(
2346 "Element '{}' has invalid value '{}' for type '{:?}'",
2347 node_name, text, dt
2348 ));
2349 ctxt.nb_errors += 1;
2350 valid = false;
2351 }
2352 }
2353
2354 valid
2355 }
2356}
2357
2358fn xsd_validate_attribute(
2364 component: &XsdComponent,
2365 node: *mut _xmlNode,
2366 _schema: &XsdSchema,
2367 ctxt: &mut XsdValidCtxt,
2368) -> bool {
2369 unsafe {
2370 let attr_name = component.name.as_deref().unwrap_or("");
2371 if attr_name.is_empty() {
2372 return true;
2373 }
2374
2375 let attr_value = get_attr(node, attr_name);
2377
2378 let is_required = component.min_occurs > 0;
2379
2380 match attr_value {
2381 Some(ref val) => {
2382 if let Some(ref dt) = component.datatype {
2384 if !xsd_validate_datatype(dt, val, &component.facets) {
2385 ctxt.errors.push(format!(
2386 "Attribute '{}' has invalid value '{}' for type '{:?}'",
2387 attr_name, val, dt
2388 ));
2389 ctxt.nb_errors += 1;
2390 return false;
2391 }
2392 }
2393 true
2394 }
2395 None => {
2396 if is_required {
2397 ctxt.errors
2398 .push(format!("Required attribute '{}' is missing", attr_name));
2399 ctxt.nb_errors += 1;
2400 false
2401 } else {
2402 true
2403 }
2404 }
2405 }
2406 }
2407}
2408
2409fn xsd_validate_content(
2415 component: &XsdComponent,
2416 node: *mut _xmlNode,
2417 schema: &XsdSchema,
2418 ctxt: &mut XsdValidCtxt,
2419) -> bool {
2420 unsafe {
2421 let mut valid = true;
2422
2423 for child_comp in &component.children {
2424 match child_comp.component_type {
2425 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2426 valid &= xsd_validate_model_group(child_comp, node, schema, ctxt);
2427 }
2428 XsdComponentType::Element => {
2429 valid &= xsd_validate_element_inline(child_comp, node, schema, ctxt);
2431 }
2432 _ => {}
2433 }
2434 }
2435
2436 valid
2437 }
2438}
2439
2440fn xsd_validate_element_inline(
2446 component: &XsdComponent,
2447 node: *mut _xmlNode,
2448 schema: &XsdSchema,
2449 ctxt: &mut XsdValidCtxt,
2450) -> bool {
2451 unsafe {
2452 let mut valid = true;
2453 let mut child = (*node).children;
2454
2455 while !child.is_null() {
2456 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2457 let child_name = get_node_qname(child);
2458
2459 let match_name = component.name.as_deref().unwrap_or("");
2460 let match_ref = component.ref_name.as_deref().unwrap_or("");
2461
2462 if (!match_name.is_empty() && child_name == match_name)
2463 || (!match_ref.is_empty() && child_name == match_ref)
2464 {
2465 let type_comp = component.children.iter().find(|c| {
2467 c.component_type == XsdComponentType::ComplexType
2468 || c.component_type == XsdComponentType::SimpleType
2469 });
2470
2471 if let Some(tc) = type_comp {
2472 match tc.component_type {
2473 XsdComponentType::ComplexType => {
2474 valid &= xsd_validate_complex_type(tc, child, schema, ctxt);
2475 }
2476 XsdComponentType::SimpleType => {
2477 let text = get_node_text(child);
2478 if let Some(ref dt) = tc.datatype {
2479 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2480 ctxt.errors.push(format!(
2481 "Element '{}' has invalid value '{}'",
2482 child_name, text
2483 ));
2484 ctxt.nb_errors += 1;
2485 valid = false;
2486 }
2487 }
2488 }
2489 _ => {}
2490 }
2491 }
2492 }
2493 }
2494 child = (*child).next;
2495 }
2496
2497 valid
2498 }
2499}
2500
2501unsafe fn get_node_qname(node: *mut _xmlNode) -> String {
2507 if node.is_null() {
2508 return String::new();
2509 }
2510 unsafe {
2511 let ns = (*node).ns;
2513 let prefix = if !ns.is_null() && !(*ns).prefix.is_null() {
2514 let mut len = 0;
2515 while *(*ns).prefix.add(len) != 0 {
2516 len += 1;
2517 }
2518 let slice = std::slice::from_raw_parts((*ns).prefix, len);
2519 if let Ok(s) = std::str::from_utf8(slice) {
2520 format!("{}:", s)
2521 } else {
2522 String::new()
2523 }
2524 } else {
2525 String::new()
2526 };
2527
2528 let name = (*node).name;
2529 if name.is_null() {
2530 return String::new();
2531 }
2532 let mut len = 0;
2533 while *name.add(len) != 0 {
2534 len += 1;
2535 }
2536 let slice = std::slice::from_raw_parts(name, len);
2537 if let Ok(s) = std::str::from_utf8(slice) {
2538 format!("{}{}", prefix, s)
2539 } else {
2540 String::new()
2541 }
2542 }
2543}
2544
2545#[no_mangle]
2564pub unsafe extern "C" fn xmlSchemaNewParserCtxt(url: *const c_char) -> *mut c_void {
2565 if url.is_null() {
2566 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2568 return ctxt;
2569 }
2570
2571 let url_str = unsafe {
2573 if url.is_null() {
2574 String::new()
2575 } else {
2576 let mut len = 0;
2577 while *url.add(len) != 0 {
2578 len += 1;
2579 }
2580 let slice = std::slice::from_raw_parts(url as *const u8, len);
2581 String::from_utf8_lossy(slice).to_string()
2582 }
2583 };
2584
2585 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2588 if !url_str.is_empty() {
2590 let _ = url_str;
2592 }
2593
2594 ctxt
2595}
2596
2597#[no_mangle]
2609pub unsafe extern "C" fn xmlSchemaNewMemParserCtxt(
2610 buffer: *const c_char,
2611 size: c_int,
2612) -> *mut c_void {
2613 if buffer.is_null() || size <= 0 {
2614 return ptr::null_mut();
2615 }
2616
2617 let buf_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, size as usize) };
2619 let xml_str = String::from_utf8_lossy(buf_slice).to_string();
2620
2621 match xsd_parse(&xml_str) {
2622 Ok(schema) => {
2623 let schema_box = Box::new(schema);
2625 Box::into_raw(schema_box) as *mut c_void
2626 }
2627 Err(_) => ptr::null_mut(),
2628 }
2629}
2630
2631#[no_mangle]
2643pub unsafe extern "C" fn xmlSchemaParse(ctxt: *mut c_void) -> *mut c_void {
2644 if ctxt.is_null() {
2645 return ptr::null_mut();
2646 }
2647
2648 ctxt
2652}
2653
2654#[no_mangle]
2666pub unsafe extern "C" fn xmlSchemaFree(schema: *mut c_void) {
2667 if schema.is_null() {
2668 return;
2669 }
2670 unsafe {
2672 let _ = Box::from_raw(schema as *mut XsdSchema);
2673 }
2674}
2675
2676#[no_mangle]
2691pub unsafe extern "C" fn xmlSchemaValidateDoc(ctxt: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2692 if ctxt.is_null() || doc.is_null() {
2693 return -1;
2694 }
2695
2696 unsafe {
2697 let valid_ctxt = &mut *(ctxt as *mut XsdValidCtxt);
2698 let schema = match &valid_ctxt.schema {
2699 Some(s) => s,
2700 None => return -1,
2701 };
2702
2703 let mut temp_ctxt = XsdValidCtxt::new();
2704 temp_ctxt.schema = Some(schema.clone());
2705
2706 let valid = xsd_validate_doc(schema, doc, &mut temp_ctxt);
2707
2708 if valid {
2709 0
2710 } else {
2711 valid_ctxt.errors = temp_ctxt.errors;
2712 valid_ctxt.nb_errors = temp_ctxt.nb_errors;
2713 temp_ctxt.nb_errors
2714 }
2715 }
2716}
2717
2718#[no_mangle]
2730pub unsafe extern "C" fn xmlSchemaFreeParserCtxt(ctxt: *mut c_void) {
2731 if ctxt.is_null() {
2732 return;
2733 }
2734 unsafe {
2736 let _ = Box::from_raw(ctxt as *mut XsdSchema);
2737 }
2738}
2739
2740#[no_mangle]
2752pub unsafe extern "C" fn xmlSchemaFreeValidCtxt(ctxt: *mut c_void) {
2753 if ctxt.is_null() {
2754 return;
2755 }
2756 unsafe {
2758 let _ = Box::from_raw(ctxt as *mut XsdValidCtxt);
2759 }
2760}
2761
2762#[no_mangle]
2774pub unsafe extern "C" fn xmlSchemaNewValidCtxt(schema: *mut c_void) -> *mut c_void {
2775 let mut ctxt = XsdValidCtxt::new();
2776
2777 if !schema.is_null() {
2778 unsafe {
2780 let schema_ref = &*(schema as *const XsdSchema);
2781 ctxt.schema = Some(schema_ref.clone());
2782 }
2783 }
2784
2785 let boxed = Box::new(ctxt);
2786 Box::into_raw(boxed) as *mut c_void
2787}
2788
2789#[cfg(test)]
2794mod tests {
2795 use super::*;
2796
2797 #[test]
2800 fn test_validate_string() {
2801 assert!(xsd_validate_datatype(
2802 &XsdDatatypeKind::String,
2803 "hello",
2804 &[]
2805 ));
2806 assert!(xsd_validate_datatype(&XsdDatatypeKind::String, "", &[]));
2807 }
2808
2809 #[test]
2810 fn test_validate_boolean() {
2811 assert!(xsd_validate_datatype(
2812 &XsdDatatypeKind::Boolean,
2813 "true",
2814 &[]
2815 ));
2816 assert!(xsd_validate_datatype(
2817 &XsdDatatypeKind::Boolean,
2818 "false",
2819 &[]
2820 ));
2821 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "1", &[]));
2822 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "0", &[]));
2823 assert!(!xsd_validate_datatype(
2824 &XsdDatatypeKind::Boolean,
2825 "yes",
2826 &[]
2827 ));
2828 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Boolean, "no", &[]));
2829 }
2830
2831 #[test]
2832 fn test_validate_integer() {
2833 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "42", &[]));
2834 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "-42", &[]));
2835 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "+42", &[]));
2836 assert!(!xsd_validate_datatype(
2837 &XsdDatatypeKind::Integer,
2838 "12.5",
2839 &[]
2840 ));
2841 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Integer, "", &[]));
2842 assert!(!xsd_validate_datatype(
2843 &XsdDatatypeKind::Integer,
2844 "abc",
2845 &[]
2846 ));
2847 }
2848
2849 #[test]
2850 fn test_validate_decimal() {
2851 assert!(xsd_validate_datatype(&XsdDatatypeKind::Decimal, "42", &[]));
2852 assert!(xsd_validate_datatype(
2853 &XsdDatatypeKind::Decimal,
2854 "12.5",
2855 &[]
2856 ));
2857 assert!(xsd_validate_datatype(
2858 &XsdDatatypeKind::Decimal,
2859 "-3.14",
2860 &[]
2861 ));
2862 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Decimal, "", &[]));
2863 }
2864
2865 #[test]
2866 fn test_validate_float() {
2867 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "3.14", &[]));
2868 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "INF", &[]));
2869 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "-INF", &[]));
2870 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "NaN", &[]));
2871 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Float, "", &[]));
2872 }
2873
2874 #[test]
2875 fn test_validate_positive_integer() {
2876 assert!(xsd_validate_datatype(
2877 &XsdDatatypeKind::PositiveInteger,
2878 "1",
2879 &[]
2880 ));
2881 assert!(xsd_validate_datatype(
2882 &XsdDatatypeKind::PositiveInteger,
2883 "100",
2884 &[]
2885 ));
2886 assert!(!xsd_validate_datatype(
2887 &XsdDatatypeKind::PositiveInteger,
2888 "0",
2889 &[]
2890 ));
2891 assert!(!xsd_validate_datatype(
2892 &XsdDatatypeKind::PositiveInteger,
2893 "-1",
2894 &[]
2895 ));
2896 }
2897
2898 #[test]
2899 fn test_validate_non_negative_integer() {
2900 assert!(xsd_validate_datatype(
2901 &XsdDatatypeKind::NonNegativeInteger,
2902 "0",
2903 &[]
2904 ));
2905 assert!(xsd_validate_datatype(
2906 &XsdDatatypeKind::NonNegativeInteger,
2907 "42",
2908 &[]
2909 ));
2910 assert!(!xsd_validate_datatype(
2911 &XsdDatatypeKind::NonNegativeInteger,
2912 "-1",
2913 &[]
2914 ));
2915 }
2916
2917 #[test]
2918 fn test_validate_int_range() {
2919 assert!(xsd_validate_datatype(
2920 &XsdDatatypeKind::Int,
2921 "2147483647",
2922 &[]
2923 ));
2924 assert!(xsd_validate_datatype(
2925 &XsdDatatypeKind::Int,
2926 "-2147483648",
2927 &[]
2928 ));
2929 assert!(!xsd_validate_datatype(
2930 &XsdDatatypeKind::Int,
2931 "2147483648",
2932 &[]
2933 ));
2934 }
2935
2936 #[test]
2937 fn test_validate_short_range() {
2938 assert!(xsd_validate_datatype(&XsdDatatypeKind::Short, "32767", &[]));
2939 assert!(xsd_validate_datatype(
2940 &XsdDatatypeKind::Short,
2941 "-32768",
2942 &[]
2943 ));
2944 assert!(!xsd_validate_datatype(
2945 &XsdDatatypeKind::Short,
2946 "32768",
2947 &[]
2948 ));
2949 }
2950
2951 #[test]
2952 fn test_validate_byte_range() {
2953 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "127", &[]));
2954 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "-128", &[]));
2955 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Byte, "128", &[]));
2956 }
2957
2958 #[test]
2959 fn test_validate_date_time() {
2960 assert!(xsd_validate_datatype(
2961 &XsdDatatypeKind::DateTime,
2962 "2023-01-15T10:30:00",
2963 &[]
2964 ));
2965 assert!(!xsd_validate_datatype(
2966 &XsdDatatypeKind::DateTime,
2967 "not-a-date",
2968 &[]
2969 ));
2970 }
2971
2972 #[test]
2973 fn test_validate_date() {
2974 assert!(xsd_validate_datatype(
2975 &XsdDatatypeKind::Date,
2976 "2023-01-15",
2977 &[]
2978 ));
2979 assert!(!xsd_validate_datatype(
2980 &XsdDatatypeKind::Date,
2981 "2023/01/15",
2982 &[]
2983 ));
2984 }
2985
2986 #[test]
2987 fn test_validate_time() {
2988 assert!(xsd_validate_datatype(
2989 &XsdDatatypeKind::Time,
2990 "10:30:00",
2991 &[]
2992 ));
2993 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Time, "10:30", &[]));
2994 }
2995
2996 #[test]
2997 fn test_validate_hex_binary() {
2998 assert!(xsd_validate_datatype(
2999 &XsdDatatypeKind::HexBinary,
3000 "0FA1",
3001 &[]
3002 ));
3003 assert!(xsd_validate_datatype(&XsdDatatypeKind::HexBinary, "", &[]));
3004 assert!(!xsd_validate_datatype(
3005 &XsdDatatypeKind::HexBinary,
3006 "0FG1",
3007 &[]
3008 ));
3009 assert!(!xsd_validate_datatype(
3010 &XsdDatatypeKind::HexBinary,
3011 "0FA",
3012 &[]
3013 ));
3014 }
3015
3016 #[test]
3017 fn test_validate_base64() {
3018 assert!(xsd_validate_datatype(
3019 &XsdDatatypeKind::Base64Binary,
3020 "SGVsbG8=",
3021 &[]
3022 ));
3023 assert!(xsd_validate_datatype(
3024 &XsdDatatypeKind::Base64Binary,
3025 "",
3026 &[]
3027 ));
3028 assert!(!xsd_validate_datatype(
3029 &XsdDatatypeKind::Base64Binary,
3030 "Hello World!",
3031 &[]
3032 ));
3033 }
3034
3035 #[test]
3036 fn test_validate_ncname() {
3037 assert!(xsd_validate_datatype(
3038 &XsdDatatypeKind::NCName,
3039 "myElement",
3040 &[]
3041 ));
3042 assert!(xsd_validate_datatype(&XsdDatatypeKind::NCName, "_foo", &[]));
3043 assert!(!xsd_validate_datatype(
3044 &XsdDatatypeKind::NCName,
3045 "123abc",
3046 &[]
3047 ));
3048 assert!(!xsd_validate_datatype(&XsdDatatypeKind::NCName, "", &[]));
3049 }
3050
3051 #[test]
3052 fn test_validate_qname() {
3053 assert!(xsd_validate_datatype(
3054 &XsdDatatypeKind::QName,
3055 "ns:local",
3056 &[]
3057 ));
3058 assert!(xsd_validate_datatype(&XsdDatatypeKind::QName, "local", &[]));
3059 assert!(!xsd_validate_datatype(&XsdDatatypeKind::QName, "", &[]));
3060 }
3061
3062 #[test]
3063 fn test_validate_token() {
3064 assert!(xsd_validate_datatype(&XsdDatatypeKind::Token, "hello", &[]));
3065 assert!(!xsd_validate_datatype(
3066 &XsdDatatypeKind::Token,
3067 " hello",
3068 &[]
3069 ));
3070 assert!(!xsd_validate_datatype(
3071 &XsdDatatypeKind::Token,
3072 "hello ",
3073 &[]
3074 ));
3075 assert!(!xsd_validate_datatype(
3076 &XsdDatatypeKind::Token,
3077 "hello world",
3078 &[]
3079 ));
3080 assert!(!xsd_validate_datatype(
3081 &XsdDatatypeKind::Token,
3082 "hello\tworld",
3083 &[]
3084 ));
3085 }
3086
3087 #[test]
3088 fn test_validate_language() {
3089 assert!(xsd_validate_datatype(&XsdDatatypeKind::Language, "en", &[]));
3090 assert!(xsd_validate_datatype(
3091 &XsdDatatypeKind::Language,
3092 "en-US",
3093 &[]
3094 ));
3095 assert!(xsd_validate_datatype(
3096 &XsdDatatypeKind::Language,
3097 "zh-CN",
3098 &[]
3099 ));
3100 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Language, "", &[]));
3101 assert!(!xsd_validate_datatype(
3102 &XsdDatatypeKind::Language,
3103 "123",
3104 &[]
3105 ));
3106 }
3107
3108 #[test]
3109 fn test_validate_name() {
3110 assert!(xsd_validate_datatype(
3111 &XsdDatatypeKind::Name,
3112 "myElement",
3113 &[]
3114 ));
3115 assert!(xsd_validate_datatype(
3116 &XsdDatatypeKind::Name,
3117 "ns:local",
3118 &[]
3119 ));
3120 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Name, "", &[]));
3121 }
3122
3123 #[test]
3124 fn test_validate_nmtoken() {
3125 assert!(xsd_validate_datatype(
3126 &XsdDatatypeKind::Nmtoken,
3127 "token123",
3128 &[]
3129 ));
3130 assert!(xsd_validate_datatype(
3131 &XsdDatatypeKind::Nmtoken,
3132 "123token",
3133 &[]
3134 ));
3135 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Nmtoken, "", &[]));
3136 }
3137
3138 #[test]
3139 fn test_validate_duration() {
3140 assert!(xsd_validate_datatype(
3141 &XsdDatatypeKind::Duration,
3142 "P1Y2M3DT4H5M6S",
3143 &[]
3144 ));
3145 assert!(xsd_validate_datatype(
3146 &XsdDatatypeKind::Duration,
3147 "P1Y",
3148 &[]
3149 ));
3150 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Duration, "", &[]));
3151 }
3152
3153 #[test]
3154 fn test_validate_g_year() {
3155 assert!(xsd_validate_datatype(&XsdDatatypeKind::GYear, "2023", &[]));
3156 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GYear, "", &[]));
3157 }
3158
3159 #[test]
3160 fn test_validate_g_month() {
3161 assert!(xsd_validate_datatype(&XsdDatatypeKind::GMonth, "--05", &[]));
3162 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GMonth, "", &[]));
3163 }
3164
3165 #[test]
3166 fn test_validate_g_day() {
3167 assert!(xsd_validate_datatype(&XsdDatatypeKind::GDay, "---15", &[]));
3168 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GDay, "", &[]));
3169 }
3170
3171 #[test]
3174 fn test_facet_min_length() {
3175 let facets = vec![(XsdDatatypeKind::FacetMinLength, "3".to_string())];
3176 assert!(xsd_validate_datatype(
3177 &XsdDatatypeKind::String,
3178 "hello",
3179 &facets
3180 ));
3181 assert!(xsd_validate_datatype(
3182 &XsdDatatypeKind::String,
3183 "abc",
3184 &facets
3185 ));
3186 assert!(!xsd_validate_datatype(
3187 &XsdDatatypeKind::String,
3188 "ab",
3189 &facets
3190 ));
3191 }
3192
3193 #[test]
3194 fn test_facet_max_length() {
3195 let facets = vec![(XsdDatatypeKind::FacetMaxLength, "3".to_string())];
3196 assert!(xsd_validate_datatype(
3197 &XsdDatatypeKind::String,
3198 "ab",
3199 &facets
3200 ));
3201 assert!(xsd_validate_datatype(
3202 &XsdDatatypeKind::String,
3203 "abc",
3204 &facets
3205 ));
3206 assert!(!xsd_validate_datatype(
3207 &XsdDatatypeKind::String,
3208 "abcd",
3209 &facets
3210 ));
3211 }
3212
3213 #[test]
3214 fn test_facet_length() {
3215 let facets = vec![(XsdDatatypeKind::FacetLength, "3".to_string())];
3216 assert!(xsd_validate_datatype(
3217 &XsdDatatypeKind::String,
3218 "abc",
3219 &facets
3220 ));
3221 assert!(!xsd_validate_datatype(
3222 &XsdDatatypeKind::String,
3223 "ab",
3224 &facets
3225 ));
3226 assert!(!xsd_validate_datatype(
3227 &XsdDatatypeKind::String,
3228 "abcd",
3229 &facets
3230 ));
3231 }
3232
3233 #[test]
3234 fn test_facet_min_inclusive() {
3235 let facets = vec![(XsdDatatypeKind::FacetMinInclusive, "5".to_string())];
3236 assert!(xsd_validate_datatype(
3237 &XsdDatatypeKind::Integer,
3238 "5",
3239 &facets
3240 ));
3241 assert!(xsd_validate_datatype(
3242 &XsdDatatypeKind::Integer,
3243 "10",
3244 &facets
3245 ));
3246 assert!(!xsd_validate_datatype(
3247 &XsdDatatypeKind::Integer,
3248 "3",
3249 &facets
3250 ));
3251 }
3252
3253 #[test]
3254 fn test_facet_max_inclusive() {
3255 let facets = vec![(XsdDatatypeKind::FacetMaxInclusive, "10".to_string())];
3256 assert!(xsd_validate_datatype(
3257 &XsdDatatypeKind::Integer,
3258 "10",
3259 &facets
3260 ));
3261 assert!(xsd_validate_datatype(
3262 &XsdDatatypeKind::Integer,
3263 "5",
3264 &facets
3265 ));
3266 assert!(!xsd_validate_datatype(
3267 &XsdDatatypeKind::Integer,
3268 "15",
3269 &facets
3270 ));
3271 }
3272
3273 #[test]
3274 fn test_facet_pattern_digits() {
3275 let facets = vec![(XsdDatatypeKind::FacetPattern, r"\d+".to_string())];
3276 assert!(xsd_validate_datatype(
3277 &XsdDatatypeKind::String,
3278 "123",
3279 &facets
3280 ));
3281 assert!(!xsd_validate_datatype(
3282 &XsdDatatypeKind::String,
3283 "abc",
3284 &facets
3285 ));
3286 }
3287
3288 #[test]
3289 fn test_facet_pattern_alpha() {
3290 let facets = vec![(XsdDatatypeKind::FacetPattern, r"[a-zA-Z]+".to_string())];
3291 assert!(xsd_validate_datatype(
3292 &XsdDatatypeKind::String,
3293 "hello",
3294 &facets
3295 ));
3296 assert!(!xsd_validate_datatype(
3297 &XsdDatatypeKind::String,
3298 "123",
3299 &facets
3300 ));
3301 }
3302
3303 #[test]
3306 fn test_parse_empty_schema() {
3307 let schema_xml = r#"<?xml version="1.0"?>
3308 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3309 </xs:schema>"#;
3310
3311 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3312 assert!(schema.components.is_empty());
3313 }
3314
3315 #[test]
3316 fn test_parse_schema_with_target_namespace() {
3317 let schema_xml = r#"<?xml version="1.0"?>
3318 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
3319 targetNamespace="http://example.com/ns">
3320 </xs:schema>"#;
3321
3322 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3323 assert_eq!(
3324 schema.target_namespace,
3325 Some("http://example.com/ns".to_string())
3326 );
3327 }
3328
3329 #[test]
3330 fn test_parse_simple_element() {
3331 let schema_xml = r#"<?xml version="1.0"?>
3332 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3333 <xs:element name="name" type="xs:string"/>
3334 </xs:schema>"#;
3335
3336 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3337 assert_eq!(schema.components.len(), 1);
3338 assert_eq!(
3339 schema.components[0].component_type,
3340 XsdComponentType::Element
3341 );
3342 assert_eq!(schema.components[0].name, Some("name".to_string()));
3343 assert_eq!(schema.components[0].datatype, Some(XsdDatatypeKind::String));
3344 }
3345
3346 #[test]
3347 fn test_parse_integer_element() {
3348 let schema_xml = r#"<?xml version="1.0"?>
3349 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3350 <xs:element name="age" type="xs:integer"/>
3351 </xs:schema>"#;
3352
3353 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3354 assert_eq!(schema.components.len(), 1);
3355 assert_eq!(schema.components[0].name, Some("age".to_string()));
3356 assert_eq!(
3357 schema.components[0].datatype,
3358 Some(XsdDatatypeKind::Integer)
3359 );
3360 }
3361
3362 #[test]
3363 fn test_parse_element_with_attributes() {
3364 let schema_xml = r#"<?xml version="1.0"?>
3365 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3366 <xs:element name="product">
3367 <xs:complexType>
3368 <xs:sequence>
3369 <xs:element name="name" type="xs:string"/>
3370 <xs:element name="price" type="xs:decimal"/>
3371 </xs:sequence>
3372 <xs:attribute name="id" type="xs:integer" use="required"/>
3373 </xs:complexType>
3374 </xs:element>
3375 </xs:schema>"#;
3376
3377 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3378 assert_eq!(schema.components.len(), 1);
3379 assert_eq!(schema.components[0].name, Some("product".to_string()));
3380
3381 let ct = &schema.components[0].children;
3383 let complex_type = ct
3384 .iter()
3385 .find(|c| c.component_type == XsdComponentType::ComplexType);
3386 assert!(complex_type.is_some());
3387 if let Some(ctc) = complex_type {
3388 assert_eq!(ctc.attributes.len(), 1);
3389 assert_eq!(ctc.attributes[0].name, Some("id".to_string()));
3390 assert_eq!(ctc.attributes[0].datatype, Some(XsdDatatypeKind::Integer));
3391 }
3392 }
3393
3394 #[test]
3395 fn test_parse_complex_type_with_sequence() {
3396 let schema_xml = r#"<?xml version="1.0"?>
3397 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3398 <xs:complexType name="AddressType">
3399 <xs:sequence>
3400 <xs:element name="street" type="xs:string"/>
3401 <xs:element name="city" type="xs:string"/>
3402 <xs:element name="zip" type="xs:string"/>
3403 </xs:sequence>
3404 </xs:complexType>
3405 </xs:schema>"#;
3406
3407 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3408 assert_eq!(schema.components.len(), 1);
3409 assert_eq!(
3410 schema.components[0].component_type,
3411 XsdComponentType::ComplexType
3412 );
3413 assert_eq!(schema.components[0].name, Some("AddressType".to_string()));
3414 }
3415
3416 #[test]
3417 fn test_parse_restriction() {
3418 let schema_xml = r#"<?xml version="1.0"?>
3419 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3420 <xs:simpleType name="AgeType">
3421 <xs:restriction base="xs:integer">
3422 <xs:minInclusive value="0"/>
3423 <xs:maxInclusive value="150"/>
3424 </xs:restriction>
3425 </xs:simpleType>
3426 </xs:schema>"#;
3427
3428 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3429 assert_eq!(schema.components.len(), 1);
3430 assert_eq!(
3431 schema.components[0].component_type,
3432 XsdComponentType::SimpleType
3433 );
3434
3435 let st = &schema.components[0];
3437 assert_eq!(st.datatype, Some(XsdDatatypeKind::Integer));
3438 assert!(!st.facets.is_empty());
3439 }
3440
3441 #[test]
3442 fn test_parse_enumeration() {
3443 let schema_xml = r#"<?xml version="1.0"?>
3444 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3445 <xs:simpleType name="ColorType">
3446 <xs:restriction base="xs:string">
3447 <xs:enumeration value="red"/>
3448 <xs:enumeration value="green"/>
3449 <xs:enumeration value="blue"/>
3450 </xs:restriction>
3451 </xs:simpleType>
3452 </xs:schema>"#;
3453
3454 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3455 assert_eq!(schema.components.len(), 1);
3456 assert_eq!(schema.components[0].name, Some("ColorType".to_string()));
3457 }
3458
3459 #[test]
3460 fn test_parse_min_max_occurs() {
3461 let schema_xml = r#"<?xml version="1.0"?>
3462 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3463 <xs:element name="items">
3464 <xs:complexType>
3465 <xs:sequence>
3466 <xs:element name="item" type="xs:string"
3467 minOccurs="0" maxOccurs="unbounded"/>
3468 </xs:sequence>
3469 </xs:complexType>
3470 </xs:element>
3471 </xs:schema>"#;
3472
3473 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3474 assert_eq!(schema.components.len(), 1);
3475
3476 let elem = &schema.components[0];
3478 let ct = elem
3479 .children
3480 .iter()
3481 .find(|c| c.component_type == XsdComponentType::ComplexType);
3482 assert!(ct.is_some());
3483 if let Some(ctc) = ct {
3484 let seq = ctc
3485 .children
3486 .iter()
3487 .find(|c| c.component_type == XsdComponentType::Sequence);
3488 assert!(seq.is_some());
3489 if let Some(seqc) = seq {
3490 assert!(!seqc.children.is_empty());
3491 let item = &seqc.children[0];
3492 assert_eq!(item.min_occurs, 0);
3493 assert_eq!(item.max_occurs, -1);
3494 }
3495 }
3496 }
3497
3498 #[test]
3499 fn test_parse_attribute_default() {
3500 let schema_xml = r#"<?xml version="1.0"?>
3501 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3502 <xs:element name="book">
3503 <xs:complexType>
3504 <xs:sequence>
3505 <xs:element name="title" type="xs:string"/>
3506 </xs:sequence>
3507 <xs:attribute name="lang" type="xs:string" default="en"/>
3508 <xs:attribute name="id" type="xs:integer" use="required"/>
3509 </xs:complexType>
3510 </xs:element>
3511 </xs:schema>"#;
3512
3513 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3514 let elem = &schema.components[0];
3515 let ct = elem
3516 .children
3517 .iter()
3518 .find(|c| c.component_type == XsdComponentType::ComplexType);
3519 assert!(ct.is_some());
3520 if let Some(ctc) = ct {
3521 let lang_attr = ctc
3522 .attributes
3523 .iter()
3524 .find(|a| a.name.as_deref() == Some("lang"));
3525 assert!(lang_attr.is_some());
3526 if let Some(la) = lang_attr {
3527 assert_eq!(la.min_occurs, 0); }
3529
3530 let id_attr = ctc
3531 .attributes
3532 .iter()
3533 .find(|a| a.name.as_deref() == Some("id"));
3534 assert!(id_attr.is_some());
3535 }
3536 }
3537
3538 #[test]
3539 fn test_parse_element_with_ref() {
3540 let schema_xml = r#"<?xml version="1.0"?>
3541 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3542 <xs:element name="root">
3543 <xs:complexType>
3544 <xs:sequence>
3545 <xs:element ref="child" minOccurs="0"/>
3546 </xs:sequence>
3547 </xs:complexType>
3548 </xs:element>
3549 <xs:element name="child" type="xs:string"/>
3550 </xs:schema>"#;
3551
3552 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3553 assert_eq!(schema.components.len(), 2);
3554 let root = &schema.components[0];
3556 let ct = root
3557 .children
3558 .iter()
3559 .find(|c| c.component_type == XsdComponentType::ComplexType);
3560 assert!(ct.is_some());
3561 if let Some(ctc) = ct {
3562 let seq = ctc
3563 .children
3564 .iter()
3565 .find(|c| c.component_type == XsdComponentType::Sequence);
3566 assert!(seq.is_some());
3567 if let Some(seqc) = seq {
3568 assert!(!seqc.children.is_empty());
3569 let ref_elem = &seqc.children[0];
3570 assert_eq!(ref_elem.ref_name, Some("child".to_string()));
3571 }
3572 }
3573 }
3574
3575 #[test]
3578 fn test_validate_simple_element() {
3579 let schema_xml = r#"<?xml version="1.0"?>
3580 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3581 <xs:element name="name" type="xs:string"/>
3582 </xs:schema>"#;
3583
3584 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3585
3586 let doc = r#"<?xml version="1.0"?>
3587 <name>John Doe</name>"#;
3588
3589 assert!(xsd_validate(&schema, doc).is_ok());
3590 }
3591
3592 #[test]
3593 fn test_validate_integer_element() {
3594 let schema_xml = r#"<?xml version="1.0"?>
3595 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3596 <xs:element name="age" type="xs:integer"/>
3597 </xs:schema>"#;
3598
3599 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3600
3601 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3602 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>not-a-number</age>"#).is_err());
3603 }
3604
3605 #[test]
3606 fn test_validate_complex_element() {
3607 let schema_xml = r#"<?xml version="1.0"?>
3608 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3609 <xs:element name="product">
3610 <xs:complexType>
3611 <xs:sequence>
3612 <xs:element name="name" type="xs:string"/>
3613 <xs:element name="price" type="xs:decimal"/>
3614 </xs:sequence>
3615 <xs:attribute name="id" type="xs:integer" use="required"/>
3616 </xs:complexType>
3617 </xs:element>
3618 </xs:schema>"#;
3619
3620 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3621
3622 let valid_doc = r#"<?xml version="1.0"?>
3623 <product id="123">
3624 <name>Widget</name>
3625 <price>9.99</price>
3626 </product>"#;
3627
3628 assert!(xsd_validate(&schema, valid_doc).is_ok());
3629 }
3630
3631 #[test]
3632 fn test_validate_missing_required_attribute() {
3633 let schema_xml = r#"<?xml version="1.0"?>
3634 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3635 <xs:element name="product">
3636 <xs:complexType>
3637 <xs:sequence>
3638 <xs:element name="name" type="xs:string"/>
3639 </xs:sequence>
3640 <xs:attribute name="id" type="xs:integer" use="required"/>
3641 </xs:complexType>
3642 </xs:element>
3643 </xs:schema>"#;
3644
3645 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3646
3647 let invalid_doc = r#"<?xml version="1.0"?>
3648 <product>
3649 <name>Widget</name>
3650 </product>"#;
3651
3652 assert!(xsd_validate(&schema, invalid_doc).is_err());
3653 }
3654
3655 #[test]
3656 fn test_validate_enumeration_facet() {
3657 let schema_xml = r#"<?xml version="1.0"?>
3658 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3659 <xs:element name="color">
3660 <xs:simpleType>
3661 <xs:restriction base="xs:string">
3662 <xs:enumeration value="red"/>
3663 <xs:enumeration value="green"/>
3664 <xs:enumeration value="blue"/>
3665 </xs:restriction>
3666 </xs:simpleType>
3667 </xs:element>
3668 </xs:schema>"#;
3669
3670 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3671
3672 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><color>red</color>"#).is_ok());
3675 }
3676
3677 #[test]
3678 fn test_validate_boolean_element() {
3679 let schema_xml = r#"<?xml version="1.0"?>
3680 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3681 <xs:element name="active" type="xs:boolean"/>
3682 </xs:schema>"#;
3683
3684 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3685
3686 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>true</active>"#).is_ok());
3687 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>false</active>"#).is_ok());
3688 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>1</active>"#).is_ok());
3689 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>yes</active>"#).is_err());
3690 }
3691
3692 #[test]
3693 fn test_validate_element_with_range_constraint() {
3694 let schema_xml = r#"<?xml version="1.0"?>
3695 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3696 <xs:element name="age">
3697 <xs:simpleType>
3698 <xs:restriction base="xs:integer">
3699 <xs:minInclusive value="0"/>
3700 <xs:maxInclusive value="150"/>
3701 </xs:restriction>
3702 </xs:simpleType>
3703 </xs:element>
3704 </xs:schema>"#;
3705
3706 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3707
3708 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3709 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>0</age>"#).is_ok());
3710 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>150</age>"#).is_ok());
3711 }
3713
3714 #[test]
3715 fn test_validate_optional_element() {
3716 let schema_xml = r#"<?xml version="1.0"?>
3717 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3718 <xs:element name="person">
3719 <xs:complexType>
3720 <xs:sequence>
3721 <xs:element name="name" type="xs:string"/>
3722 <xs:element name="nickname" type="xs:string" minOccurs="0"/>
3723 </xs:sequence>
3724 </xs:complexType>
3725 </xs:element>
3726 </xs:schema>"#;
3727
3728 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3729
3730 let doc_with_nick = r#"<?xml version="1.0"?>
3731 <person>
3732 <name>John</name>
3733 <nickname>Johnny</nickname>
3734 </person>"#;
3735
3736 let doc_without_nick = r#"<?xml version="1.0"?>
3737 <person>
3738 <name>John</name>
3739 </person>"#;
3740
3741 assert!(xsd_validate(&schema, doc_with_nick).is_ok());
3742 assert!(xsd_validate(&schema, doc_without_nick).is_ok());
3743 }
3744
3745 #[test]
3746 fn test_validate_unbounded_element() {
3747 let schema_xml = r#"<?xml version="1.0"?>
3748 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3749 <xs:element name="items">
3750 <xs:complexType>
3751 <xs:sequence>
3752 <xs:element name="item" type="xs:string"
3753 minOccurs="0" maxOccurs="unbounded"/>
3754 </xs:sequence>
3755 </xs:complexType>
3756 </xs:element>
3757 </xs:schema>"#;
3758
3759 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3760
3761 let doc = r#"<?xml version="1.0"?>
3762 <items>
3763 <item>one</item>
3764 <item>two</item>
3765 <item>three</item>
3766 </items>"#;
3767
3768 assert!(xsd_validate(&schema, doc).is_ok());
3769 }
3770
3771 #[test]
3772 fn test_validate_date_element() {
3773 let schema_xml = r#"<?xml version="1.0"?>
3774 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3775 <xs:element name="birthDate" type="xs:date"/>
3776 </xs:schema>"#;
3777
3778 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3779
3780 assert!(xsd_validate(
3781 &schema,
3782 r#"<?xml version="1.0"?><birthDate>1990-01-15</birthDate>"#
3783 )
3784 .is_ok());
3785 assert!(xsd_validate(
3786 &schema,
3787 r#"<?xml version="1.0"?><birthDate>not-a-date</birthDate>"#
3788 )
3789 .is_err());
3790 }
3791
3792 #[test]
3793 fn test_validate_choice() {
3794 let schema_xml = r#"<?xml version="1.0"?>
3795 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3796 <xs:element name="contact">
3797 <xs:complexType>
3798 <xs:choice>
3799 <xs:element name="email" type="xs:string"/>
3800 <xs:element name="phone" type="xs:string"/>
3801 </xs:choice>
3802 </xs:complexType>
3803 </xs:element>
3804 </xs:schema>"#;
3805
3806 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3807
3808 assert!(xsd_validate(
3809 &schema,
3810 r#"<?xml version="1.0"?><contact><email>a@b.com</email></contact>"#
3811 )
3812 .is_ok());
3813 assert!(xsd_validate(
3814 &schema,
3815 r#"<?xml version="1.0"?><contact><phone>555-1234</phone></contact>"#
3816 )
3817 .is_ok());
3818 }
3819
3820 #[test]
3821 fn test_validate_positive_integer_constraint() {
3822 let schema_xml = r#"<?xml version="1.0"?>
3823 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3824 <xs:element name="quantity" type="xs:positiveInteger"/>
3825 </xs:schema>"#;
3826
3827 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3828
3829 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>1</quantity>"#).is_ok());
3830 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>0</quantity>"#).is_err());
3831 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>-1</quantity>"#).is_err());
3832 }
3833
3834 #[test]
3837 fn test_xml_schema_new_mem_parser_ctxt() {
3838 let schema_xml = r#"<?xml version="1.0"?>
3839 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3840 <xs:element name="name" type="xs:string"/>
3841 </xs:schema>"#;
3842
3843 let ctxt = unsafe {
3844 xmlSchemaNewMemParserCtxt(
3845 schema_xml.as_ptr() as *const c_char,
3846 schema_xml.len() as c_int,
3847 )
3848 };
3849 assert!(!ctxt.is_null());
3850
3851 let schema = unsafe { xmlSchemaParse(ctxt) };
3852 assert!(!schema.is_null());
3853
3854 unsafe {
3855 xmlSchemaFree(schema);
3856 }
3857 }
3858
3859 #[test]
3860 fn test_xml_schema_validate_doc() {
3861 let schema_xml = r#"<?xml version="1.0"?>
3862 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3863 <xs:element name="name" type="xs:string"/>
3864 </xs:schema>"#;
3865
3866 let doc_xml = r#"<?xml version="1.0"?>
3867 <name>John Doe</name>"#;
3868
3869 let ctxt = unsafe {
3870 xmlSchemaNewMemParserCtxt(
3871 schema_xml.as_ptr() as *const c_char,
3872 schema_xml.len() as c_int,
3873 )
3874 };
3875 let schema = unsafe { xmlSchemaParse(ctxt) };
3876 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
3877
3878 let doc = unsafe {
3879 crate::abi::exports_xml2::xmlReadMemory(
3880 doc_xml.as_ptr() as *const c_char,
3881 doc_xml.len() as c_int,
3882 b"test.xml\0".as_ptr() as *const c_char,
3883 ptr::null(),
3884 0,
3885 )
3886 };
3887
3888 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
3889 assert_eq!(result, 0);
3890
3891 unsafe {
3892 xmlSchemaFreeValidCtxt(valid_ctxt);
3893 xmlSchemaFree(schema);
3894 crate::abi::exports_xml2::xmlFreeDoc(doc);
3895 }
3896 }
3897
3898 #[test]
3899 fn test_xml_schema_validate_invalid_doc() {
3900 let schema_xml = r#"<?xml version="1.0"?>
3901 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3902 <xs:element name="age" type="xs:integer"/>
3903 </xs:schema>"#;
3904
3905 let doc_xml = r#"<?xml version="1.0"?>
3906 <age>not-a-number</age>"#;
3907
3908 let ctxt = unsafe {
3909 xmlSchemaNewMemParserCtxt(
3910 schema_xml.as_ptr() as *const c_char,
3911 schema_xml.len() as c_int,
3912 )
3913 };
3914 let schema = unsafe { xmlSchemaParse(ctxt) };
3915 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
3916
3917 let doc = unsafe {
3918 crate::abi::exports_xml2::xmlReadMemory(
3919 doc_xml.as_ptr() as *const c_char,
3920 doc_xml.len() as c_int,
3921 b"test.xml\0".as_ptr() as *const c_char,
3922 ptr::null(),
3923 0,
3924 )
3925 };
3926
3927 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
3928 assert_ne!(result, 0); unsafe {
3931 xmlSchemaFreeValidCtxt(valid_ctxt);
3932 xmlSchemaFree(schema);
3933 crate::abi::exports_xml2::xmlFreeDoc(doc);
3934 }
3935 }
3936
3937 #[test]
3938 fn test_xml_schema_new_valid_ctxt_null() {
3939 let ctxt = unsafe { xmlSchemaNewValidCtxt(ptr::null_mut()) };
3940 assert!(!ctxt.is_null());
3941 unsafe { xmlSchemaFreeValidCtxt(ctxt) };
3942 }
3943
3944 #[test]
3945 fn test_xml_schema_free_null() {
3946 unsafe {
3947 xmlSchemaFree(ptr::null_mut());
3948 xmlSchemaFreeParserCtxt(ptr::null_mut());
3949 xmlSchemaFreeValidCtxt(ptr::null_mut());
3950 }
3951 }
3952
3953 #[test]
3954 fn test_xml_schema_new_parser_ctxt_null() {
3955 let ctxt = unsafe { xmlSchemaNewParserCtxt(ptr::null()) };
3956 assert!(!ctxt.is_null());
3957 unsafe {
3959 allocator::xmlFree(ctxt);
3960 }
3961 }
3962
3963 #[test]
3964 fn test_datatype_parse_kind() {
3965 assert_eq!(
3966 parse_datatype_kind("xs:string"),
3967 Some(XsdDatatypeKind::String)
3968 );
3969 assert_eq!(parse_datatype_kind("string"), Some(XsdDatatypeKind::String));
3970 assert_eq!(
3971 parse_datatype_kind("xs:integer"),
3972 Some(XsdDatatypeKind::Integer)
3973 );
3974 assert_eq!(
3975 parse_datatype_kind("xs:boolean"),
3976 Some(XsdDatatypeKind::Boolean)
3977 );
3978 assert_eq!(
3979 parse_datatype_kind("xs:decimal"),
3980 Some(XsdDatatypeKind::Decimal)
3981 );
3982 assert_eq!(
3983 parse_datatype_kind("xs:float"),
3984 Some(XsdDatatypeKind::Float)
3985 );
3986 assert_eq!(
3987 parse_datatype_kind("xs:double"),
3988 Some(XsdDatatypeKind::Double)
3989 );
3990 assert_eq!(parse_datatype_kind("xs:date"), Some(XsdDatatypeKind::Date));
3991 assert_eq!(
3992 parse_datatype_kind("xs:dateTime"),
3993 Some(XsdDatatypeKind::DateTime)
3994 );
3995 assert_eq!(parse_datatype_kind("xs:time"), Some(XsdDatatypeKind::Time));
3996 assert_eq!(
3997 parse_datatype_kind("xs:hexBinary"),
3998 Some(XsdDatatypeKind::HexBinary)
3999 );
4000 assert_eq!(
4001 parse_datatype_kind("xs:base64Binary"),
4002 Some(XsdDatatypeKind::Base64Binary)
4003 );
4004 assert_eq!(
4005 parse_datatype_kind("xs:anyURI"),
4006 Some(XsdDatatypeKind::AnyURI)
4007 );
4008 assert_eq!(
4009 parse_datatype_kind("xs:QName"),
4010 Some(XsdDatatypeKind::QName)
4011 );
4012 assert_eq!(
4013 parse_datatype_kind("xs:normalizedString"),
4014 Some(XsdDatatypeKind::NormalizedString)
4015 );
4016 assert_eq!(
4017 parse_datatype_kind("xs:token"),
4018 Some(XsdDatatypeKind::Token)
4019 );
4020 assert_eq!(
4021 parse_datatype_kind("xs:language"),
4022 Some(XsdDatatypeKind::Language)
4023 );
4024 assert_eq!(parse_datatype_kind("xs:Name"), Some(XsdDatatypeKind::Name));
4025 assert_eq!(
4026 parse_datatype_kind("xs:NCName"),
4027 Some(XsdDatatypeKind::NCName)
4028 );
4029 assert_eq!(parse_datatype_kind("xs:ID"), Some(XsdDatatypeKind::Id));
4030 assert_eq!(
4031 parse_datatype_kind("xs:IDREF"),
4032 Some(XsdDatatypeKind::Idref)
4033 );
4034 assert_eq!(
4035 parse_datatype_kind("xs:integer"),
4036 Some(XsdDatatypeKind::Integer)
4037 );
4038 assert_eq!(parse_datatype_kind("xs:long"), Some(XsdDatatypeKind::Long));
4039 assert_eq!(parse_datatype_kind("xs:int"), Some(XsdDatatypeKind::Int));
4040 assert_eq!(
4041 parse_datatype_kind("xs:short"),
4042 Some(XsdDatatypeKind::Short)
4043 );
4044 assert_eq!(parse_datatype_kind("xs:byte"), Some(XsdDatatypeKind::Byte));
4045 assert_eq!(
4046 parse_datatype_kind("xs:positiveInteger"),
4047 Some(XsdDatatypeKind::PositiveInteger)
4048 );
4049 assert_eq!(
4050 parse_datatype_kind("xs:negativeInteger"),
4051 Some(XsdDatatypeKind::NegativeInteger)
4052 );
4053 assert_eq!(parse_datatype_kind("unknown"), None);
4054 }
4055}