leptris 1.9.331.0 → 1.9.334.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/Rakefile +19 -1
  4. data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
  5. data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
  6. data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
  7. data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
  8. data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
  9. data/lib/leptris/vendor/arm64-darwin/libutf8proc.3.dylib +0 -0
  10. data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
  11. data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
  12. data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
  13. data/lib/leptris/vendor/x86_64-darwin/libutf8proc.3.dylib +0 -0
  14. data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
  15. data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
  16. data/lib/leptris/version.rb +1 -1
  17. data/lib/leptris/xml/cdata.rb +4 -0
  18. data/lib/leptris/xml/comment.rb +4 -0
  19. data/lib/leptris/xml/descriptor.rb +55 -0
  20. data/lib/leptris/xml/entity_reference.rb +4 -0
  21. data/lib/leptris/xml/ffi.rb +25 -0
  22. data/lib/leptris/xml/node.rb +1 -0
  23. data/lib/leptris/xml/processing_instruction.rb +4 -0
  24. data/lib/leptris/xml/text.rb +4 -0
  25. data/vendor-src/README.md +1 -1
  26. data/vendor-src/libleptris/CHANGELOG.md +65 -0
  27. data/vendor-src/libleptris/CMakeLists.txt +1 -1
  28. data/vendor-src/libleptris/src/include/leptris/descriptor.h +30 -0
  29. data/vendor-src/libleptris/src/include/leptris.h +5 -0
  30. data/vendor-src/libleptris/src/leptris/descriptor/plan.c +144 -0
  31. data/vendor-src/libleptris/src/leptris/dom/element_modify.c +7 -0
  32. data/vendor-src/libleptris/src/leptris/xsd/compile.c +241 -4
  33. data/vendor-src/libleptris/src/leptris/xsd/content_model.c +50 -0
  34. data/vendor-src/libleptris/src/leptris/xsd/validate.c +190 -8
  35. data/vendor-src/libleptris/src/leptris/xsd/xsd_internal.h +34 -0
  36. data/vendor-src/libleptris/test/abi/test_descriptor.cpp +95 -0
  37. data/vendor-src/libleptris/test/xsd/test_xsd_compile.cpp +380 -0
  38. data/vendor-src/libleptris/vcpkg.json +1 -1
  39. metadata +2 -2
@@ -36,11 +36,14 @@ struct leptris_xsd_schema {
36
36
  XsdElementDecl* elements;
37
37
  XsdCm* complex_types; /* name-carrying model roots */
38
38
  XsdGroupDef* groups; /* top-level xs:group definitions */
39
+ XsdCm* default_open; /* xs:defaultOpenContent wildcard */
40
+ int default_oc_empty; /* appliesToEmpty="true" */
39
41
  XsdAttrGroupDef* attr_groups;
40
42
  XsdAttrDecl* top_attrs; /* top-level xs:attribute declarations */
41
43
  XsdTypeAttrs* type_attrs;
42
44
  XsdElementIcs* element_ics;
43
45
  char* target_ns;
46
+ int version_11; /* xs:schema @version = "1.1" */
44
47
  char* base_dir; /* schemaLocation resolution (file compile) */
45
48
  int include_depth; /* include/import recursion guard */
46
49
  void* validator; /* slice-4 parked error list */
@@ -76,10 +79,18 @@ static char* xsd_read_file(const char* path, size_t* out_len);
76
79
  static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src);
77
80
  static void xsd_register_complex(struct leptris_xsd_schema* s,
78
81
  XsdCm* root, XsdAttrDecl* attrs,
79
- const char* name);
82
+ const char* name,
83
+ char* any_attr_ns);
80
84
  static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
81
85
  LeptrisElement ct,
82
86
  const char* name);
87
+ static XsdAssert* xsd_capture_assert(struct leptris_xsd_schema* s,
88
+ LeptrisElement e);
89
+ static XsdCm* xsd_capture_any(LeptrisElement any_child);
90
+ static char* xsd_capture_any_attr_ns(LeptrisElement container);
91
+ static void xsd_capture_alternatives(struct leptris_xsd_schema* s,
92
+ LeptrisElement decl_elem,
93
+ XsdElementDecl* d);
83
94
  static XsdSimple* xsd_capture_simple(LeptrisElement st);
84
95
 
85
96
 
@@ -95,6 +106,15 @@ static XsdCm* xsd_cm_new(XsdCmKind kind) {
95
106
  static void xsd_cm_free(XsdCm* cm) {
96
107
  while (cm) {
97
108
  XsdCm* next = cm->next;
109
+ XsdAssert* a = cm->asserts;
110
+ while (a) {
111
+ XsdAssert* an = a->next;
112
+ if (a->compiled) leptris_xquery_free(a->compiled);
113
+ free(a->test);
114
+ free(a);
115
+ a = an;
116
+ }
117
+ if (cm->oc_owned && cm->open_any) xsd_cm_free(cm->open_any);
98
118
  xsd_cm_free(cm->first_child);
99
119
  free(cm->name);
100
120
  free(cm->type);
@@ -370,6 +390,9 @@ static XsdSimple* xsd_capture_simple(LeptrisElement st) {
370
390
  simple->fraction_digits = val ? strtol(val, NULL, 10) : -1;
371
391
  else if (strcmp(fl, "whiteSpace") == 0)
372
392
  simple->whitespace = xsd_strdup(val);
393
+ else if (strcmp(fl, "assertion") == 0)
394
+ simple->assertion = xsd_strdup(
395
+ leptris_element_attribute(fe, "test"));
373
396
  }
374
397
  }
375
398
  }
@@ -481,6 +504,7 @@ static int xsd_is_declaration(const char* local, const char* uri) {
481
504
  static const char* names[] = {
482
505
  "element", "attribute", "simpleType", "complexType",
483
506
  "group", "attributeGroup", "notation", "include",
507
+ "defaultOpenContent",
484
508
  "import", "redefine", NULL
485
509
  };
486
510
  for (int i = 0; names[i]; i++)
@@ -594,6 +618,10 @@ static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
594
618
  }
595
619
  s->target_ns = xsd_strdup(
596
620
  leptris_element_attribute(root, "targetNamespace"));
621
+ {
622
+ const char* ver = leptris_element_attribute(root, "version");
623
+ s->version_11 = (ver && strcmp(ver, "1.1") == 0);
624
+ }
597
625
 
598
626
  const char* local = NULL;
599
627
  const char* prefix = NULL;
@@ -692,6 +720,7 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
692
720
  if (d) {
693
721
  d->name = xsd_strdup(nm);
694
722
  d->type = xsd_strdup(ty);
723
+ xsd_capture_alternatives(s, (LeptrisElement)n, d);
695
724
  d->fixed = xsd_strdup(
696
725
  leptris_element_attribute((LeptrisElement)n,
697
726
  "fixed"));
@@ -730,6 +759,29 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
730
759
  leptris_element_attribute((LeptrisElement)n, "name");
731
760
  if (nm)
732
761
  xsd_capture_complex_model(s, (LeptrisElement)n, nm);
762
+ } else if (strcmp(local, "defaultOpenContent") == 0 && uri &&
763
+ !strcmp(uri, XSD_NS)) {
764
+ if (s->version_11) {
765
+ const char* ape = leptris_element_attribute(
766
+ (LeptrisElement)n, "appliesToEmpty");
767
+ for (LeptrisNodeRef q = leptris_node_first_child(
768
+ leptris_element_as_node((LeptrisElement)n));
769
+ q && !s->default_open;
770
+ q = leptris_node_next_sibling(q)) {
771
+ if (leptris_node_get_type(q) !=
772
+ LEPTRIS_NODE_TYPE_ELEMENT)
773
+ continue;
774
+ LeptrisElement qe = (LeptrisElement)q;
775
+ const char* ql = NULL;
776
+ leptris_element_expanded_name(qe, &ql, NULL, NULL);
777
+ if (ql && strcmp(ql, "any") == 0)
778
+ s->default_open = xsd_capture_any(qe);
779
+ }
780
+ if (s->default_open)
781
+ s->default_oc_empty =
782
+ (ape && strcmp(ape, "true") == 0);
783
+ }
784
+ continue;
733
785
  } else if (strcmp(local, "attribute") == 0 && uri && !strcmp(uri, XSD_NS)) {
734
786
  const char* nm =
735
787
  leptris_element_attribute((LeptrisElement)n, "name");
@@ -803,6 +855,8 @@ static void xsd_free_simple_one(XsdSimple* t) {
803
855
  free(t->max_inclusive);
804
856
  free(t->max_exclusive);
805
857
  free(t->whitespace);
858
+ if (t->assertion_q) leptris_xquery_free(t->assertion_q);
859
+ free(t->assertion);
806
860
  free(t->item_type);
807
861
  xsd_free_simple_one(t->item_def);
808
862
  for (size_t i = 0; i < t->member_count; i++) free(t->members[i]);
@@ -848,12 +902,22 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
848
902
  a = an;
849
903
  }
850
904
  free(ta->type_name);
905
+ free(ta->any_attr_ns);
851
906
  free(ta);
852
907
  ta = tn;
853
908
  }
854
909
  XsdElementDecl* d = s->elements;
855
910
  while (d) {
856
911
  XsdElementDecl* dn = d->next;
912
+ XsdAlternative* a = d->alternatives;
913
+ while (a) {
914
+ XsdAlternative* an = a->next;
915
+ if (a->compiled) leptris_xquery_free(a->compiled);
916
+ free(a->test);
917
+ free(a->type);
918
+ free(a);
919
+ a = an;
920
+ }
857
921
  free(d->name);
858
922
  free(d->type);
859
923
  free(d->fixed);
@@ -894,6 +958,7 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
894
958
  free(g);
895
959
  g = gn;
896
960
  }
961
+ if (s->default_open) xsd_cm_free(s->default_open);
897
962
  free(s->target_ns);
898
963
  free(s->base_dir);
899
964
  if (s->validator)
@@ -936,19 +1001,107 @@ static XsdCm* xsd_cm_copy_list(const XsdCm* head) {
936
1001
 
937
1002
  static void xsd_register_complex(struct leptris_xsd_schema* s,
938
1003
  XsdCm* root, XsdAttrDecl* attrs,
939
- const char* name) {
1004
+ const char* name,
1005
+ char* any_attr_ns) {
940
1006
  if (!root) return;
941
1007
  root->name = xsd_strdup(name);
942
1008
  root->next = s->complex_types;
943
1009
  s->complex_types = root;
944
- if (attrs) {
1010
+ if (attrs || any_attr_ns) {
945
1011
  XsdTypeAttrs* ta = (XsdTypeAttrs*)calloc(1, sizeof(*ta));
946
1012
  if (ta) {
947
1013
  ta->type_name = xsd_strdup(name);
948
1014
  ta->attrs = attrs;
1015
+ ta->any_attr_ns = any_attr_ns;
949
1016
  ta->next = s->type_attrs;
950
1017
  s->type_attrs = ta;
951
1018
  }
1019
+ } else if (any_attr_ns) {
1020
+ free(any_attr_ns);
1021
+ }
1022
+ }
1023
+
1024
+ /* XSD 1.1: xs:alternative children of an element declaration. */
1025
+ static void xsd_capture_alternatives(struct leptris_xsd_schema* s,
1026
+ LeptrisElement decl_elem,
1027
+ XsdElementDecl* d) {
1028
+ if (!s->version_11) return;
1029
+ XsdAlternative* tail = NULL;
1030
+ for (LeptrisNodeRef n =
1031
+ leptris_node_first_child(leptris_element_as_node(decl_elem));
1032
+ n; n = leptris_node_next_sibling(n)) {
1033
+ if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
1034
+ continue;
1035
+ LeptrisElement e = (LeptrisElement)n;
1036
+ const char* local = NULL;
1037
+ leptris_element_expanded_name(e, &local, NULL, NULL);
1038
+ if (!local || strcmp(local, "alternative") != 0) continue;
1039
+ const char* test = leptris_element_attribute(e, "test");
1040
+ const char* type = leptris_element_attribute(e, "type");
1041
+ if (!test || !type) continue;
1042
+ XsdAlternative* a = (XsdAlternative*)calloc(1, sizeof(*a));
1043
+ if (!a) continue;
1044
+ a->test = xsd_strdup(test);
1045
+ a->type = xsd_strdup(type);
1046
+ a->compiled = leptris_xquery_parse(test, strlen(test));
1047
+ if (tail)
1048
+ tail->next = a;
1049
+ else
1050
+ d->alternatives = a;
1051
+ tail = a;
1052
+ }
1053
+ }
1054
+
1055
+ static XsdCm* xsd_capture_any(LeptrisElement any_child) {
1056
+ XsdCm* w = xsd_cm_new(XSD_CM_ANY);
1057
+ if (!w) return NULL;
1058
+ w->any_ns = xsd_strdup(
1059
+ leptris_element_attribute(any_child, "namespace"));
1060
+ const char* pc = leptris_element_attribute(any_child,
1061
+ "processContents");
1062
+ w->process_skip =
1063
+ (pc && (strcmp(pc, "skip") == 0 || strcmp(pc, "lax") == 0))
1064
+ ? 1
1065
+ : 0;
1066
+ w->min = 0;
1067
+ w->max = -1;
1068
+ return w;
1069
+ }
1070
+
1071
+ static XsdAssert* xsd_capture_assert(struct leptris_xsd_schema* s,
1072
+ LeptrisElement e) {
1073
+ const char* test = leptris_element_attribute(e, "test");
1074
+ if (!test || !*test) return NULL;
1075
+ XsdAssert* a = (XsdAssert*)calloc(1, sizeof(*a));
1076
+ if (!a) return NULL;
1077
+ a->test = xsd_strdup(test);
1078
+ if (s->version_11) {
1079
+ a->compiled = leptris_xquery_parse(test, strlen(test));
1080
+ /* NULL = syntax error: evaluation reports the assertion
1081
+ * as failed (XSD 1.1: an error is a failure) */
1082
+ }
1083
+ return a;
1084
+ }
1085
+
1086
+ /* Append every xs:assert child under `container` to the type. */
1087
+ static void xsd_capture_assert_children(
1088
+ struct leptris_xsd_schema* s, LeptrisElement container,
1089
+ XsdCm* root) {
1090
+ XsdAssert* tail = root->asserts;
1091
+ while (tail && tail->next) tail = tail->next;
1092
+ for (LeptrisNodeRef n =
1093
+ leptris_node_first_child(leptris_element_as_node(container));
1094
+ n; n = leptris_node_next_sibling(n)) {
1095
+ if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
1096
+ continue;
1097
+ LeptrisElement e = (LeptrisElement)n;
1098
+ const char* local = NULL;
1099
+ leptris_element_expanded_name(e, &local, NULL, NULL);
1100
+ if (!local || strcmp(local, "assert") != 0) continue;
1101
+ XsdAssert* a = xsd_capture_assert(s, e);
1102
+ if (!a) continue;
1103
+ if (!root->asserts) root->asserts = a;
1104
+ tail = a;
952
1105
  }
953
1106
  }
954
1107
 
@@ -962,6 +1115,7 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
962
1115
  XsdCm* root = xsd_cm_new(XSD_CM_SEQ); /* wrapper keeps the name */
963
1116
  if (!root) return NULL;
964
1117
  XsdAttrDecl* attrs = NULL;
1118
+ char* any_attr_ns = NULL;
965
1119
 
966
1120
  for (LeptrisNodeRef n =
967
1121
  leptris_node_first_child(leptris_element_as_node(ct));
@@ -1026,6 +1180,11 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
1026
1180
  root->first_child = xsd_cm_parse(s, dq, NULL);
1027
1181
  attrs = xsd_capture_attr_rows(s, dq, 0);
1028
1182
  }
1183
+ /* XSD 1.1: asserts nested under the derivation */
1184
+ if (s->version_11)
1185
+ xsd_capture_assert_children(s, dq, root);
1186
+ if (!any_attr_ns)
1187
+ any_attr_ns = xsd_capture_any_attr_ns(dq);
1029
1188
  }
1030
1189
  } else if (strcmp(local, "simpleContent") == 0) {
1031
1190
  for (LeptrisNodeRef q = leptris_node_first_child(
@@ -1092,7 +1251,52 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
1092
1251
  * re-capturing would orphan those rows. */
1093
1252
  root->first_child = xsd_cm_parse(s, ct, NULL);
1094
1253
  if (!attrs) attrs = xsd_capture_attr_rows(s, ct, 0);
1254
+ if (!any_attr_ns) any_attr_ns = xsd_capture_any_attr_ns(ct);
1095
1255
  }
1256
+ /* XSD 1.1: openContent on the type, else the schema default */
1257
+ if (s->version_11) {
1258
+ for (LeptrisNodeRef n =
1259
+ leptris_node_first_child(leptris_element_as_node(ct));
1260
+ n; n = leptris_node_next_sibling(n)) {
1261
+ if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
1262
+ continue;
1263
+ LeptrisElement e = (LeptrisElement)n;
1264
+ const char* ocl = NULL;
1265
+ leptris_element_expanded_name(e, &ocl, NULL, NULL);
1266
+ if (!ocl || strcmp(ocl, "openContent") != 0) continue;
1267
+ const char* mode = leptris_element_attribute(e, "mode");
1268
+ for (LeptrisNodeRef q = leptris_node_first_child(
1269
+ leptris_element_as_node(e));
1270
+ q && !root->open_any;
1271
+ q = leptris_node_next_sibling(q)) {
1272
+ if (leptris_node_get_type(q) !=
1273
+ LEPTRIS_NODE_TYPE_ELEMENT)
1274
+ continue;
1275
+ LeptrisElement qe = (LeptrisElement)q;
1276
+ const char* ql = NULL;
1277
+ leptris_element_expanded_name(qe, &ql, NULL, NULL);
1278
+ if (ql && strcmp(ql, "any") == 0) {
1279
+ root->open_any = xsd_capture_any(qe);
1280
+ if (root->open_any) root->oc_owned = 1;
1281
+ }
1282
+ }
1283
+ if (mode && strcmp(mode, "suffix") == 0)
1284
+ root->oc_mode = 1;
1285
+ else if (mode && strcmp(mode, "interleave") == 0)
1286
+ root->oc_mode = 2;
1287
+ else
1288
+ root->oc_mode = 0;
1289
+ }
1290
+ }
1291
+ if (!root->oc_mode && s->default_open && root->first_child)
1292
+ root->oc_mode = 2;
1293
+ if (!root->oc_mode && s->default_open && !root->first_child &&
1294
+ s->default_oc_empty)
1295
+ root->oc_mode = 2;
1296
+ if (root->oc_mode == 2 && !root->open_any && s->default_open)
1297
+ root->open_any = s->default_open;
1298
+ /* XSD 1.1: direct xs:assert children of the complexType */
1299
+ if (s->version_11) xsd_capture_assert_children(s, ct, root);
1096
1300
  /* the NFA and model walkers consume ONE root particle —
1097
1301
  * a multi-particle model (derivation splices) normalizes
1098
1302
  * under a sequence */
@@ -1103,7 +1307,19 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
1103
1307
  root->first_child = seq;
1104
1308
  }
1105
1309
  }
1106
- xsd_register_complex(s, root, attrs, name);
1310
+ /* open-content semantics ride the model root (the NFA builds
1311
+ * from ct->first_child, never the name wrapper) */
1312
+ if (root->first_child) {
1313
+ root->first_child->open_any = root->open_any;
1314
+ root->first_child->oc_mode = root->oc_mode;
1315
+ root->first_child->oc_owned = root->oc_owned;
1316
+ root->open_any = NULL;
1317
+ root->oc_owned = 0;
1318
+ } else if (root->open_any && root->oc_owned) {
1319
+ xsd_cm_free(root->open_any);
1320
+ root->open_any = NULL;
1321
+ }
1322
+ xsd_register_complex(s, root, attrs, name, any_attr_ns);
1107
1323
  return root;
1108
1324
  }
1109
1325
 
@@ -1124,6 +1340,10 @@ int xsd_is_substitute(struct leptris_xsd_schema* s,
1124
1340
  return 0;
1125
1341
  }
1126
1342
 
1343
+ int xsd_schema_version_11(struct leptris_xsd_schema* s) {
1344
+ return s ? s->version_11 : 0;
1345
+ }
1346
+
1127
1347
  XsdGroupDef* xsd_find_group(struct leptris_xsd_schema* s,
1128
1348
  const char* name) {
1129
1349
  if (!s || !name) return NULL;
@@ -1265,6 +1485,23 @@ static XsdAttrDecl* xsd_capture_attr_rows(struct leptris_xsd_schema* s,
1265
1485
  return head;
1266
1486
  }
1267
1487
 
1488
+ /* One container's xs:anyAttribute grammar (NULL when absent). */
1489
+ static char* xsd_capture_any_attr_ns(LeptrisElement container) {
1490
+ for (LeptrisNodeRef ac = leptris_node_first_child(
1491
+ leptris_element_as_node(container));
1492
+ ac; ac = leptris_node_next_sibling(ac)) {
1493
+ if (leptris_node_get_type(ac) != LEPTRIS_NODE_TYPE_ELEMENT)
1494
+ continue;
1495
+ LeptrisElement ae = (LeptrisElement)ac;
1496
+ const char* al = NULL;
1497
+ leptris_element_expanded_name(ae, &al, NULL, NULL);
1498
+ if (al && strcmp(al, "anyAttribute") == 0)
1499
+ return xsd_strdup(
1500
+ leptris_element_attribute(ae, "namespace"));
1501
+ }
1502
+ return NULL;
1503
+ }
1504
+
1268
1505
  LEPTRIS_API int leptris_xsd_builtin_valid(const char* builtin,
1269
1506
  const char* lexical) {
1270
1507
  extern int xsd_builtin_valid(const char* type, const char* v);
@@ -56,20 +56,35 @@ static void cm_build_occurrence(CmNfa* n, XsdCm* node,
56
56
  /* chain the group children: first reads `from`, last writes `to`.
57
57
  * xs:all is evaluated in sequence order for now (its order-free
58
58
  * semantics arrive with slice 4's all-semantics pass). */
59
+ /* XSD 1.1 open content: a wildcard self-loop at a junction lets
60
+ * any-namespace elements (per the wildcard's grammar) consume a
61
+ * child without advancing the model. */
62
+ static void oc_loop(CmNfa* n, XsdCm* node, int state) {
63
+ if (!node->open_any || !node->oc_mode) return;
64
+ nfa_trans(n, state, 0, node->open_any, state);
65
+ }
66
+
59
67
  static void cm_build_children(CmNfa* n, XsdCm* node, int from, int to) {
60
68
  XsdCm* c = node->first_child;
61
69
  if (!c) {
62
70
  nfa_trans(n, from, -1, NULL, to);
63
71
  return;
64
72
  }
73
+ int interleave =
74
+ (node->open_any && node->oc_mode == 2) ? 1 : 0;
65
75
  int cursor = from;
76
+ if (interleave) oc_loop(n, node, cursor);
66
77
  while (c->next) {
67
78
  int mid = nfa_state(n);
68
79
  cm_build_occurrence(n, c, cursor, mid);
69
80
  cursor = mid;
81
+ if (interleave) oc_loop(n, node, cursor);
70
82
  c = c->next;
71
83
  }
72
84
  cm_build_occurrence(n, c, cursor, to);
85
+ /* suffix (and interleave) wildcards may follow the sequence */
86
+ if (node->open_any && node->oc_mode)
87
+ oc_loop(n, node, to);
73
88
  }
74
89
 
75
90
  static void cm_build(CmNfa* n, XsdCm* node, int from, int to) {
@@ -193,10 +208,45 @@ static void ss_close(StateSet* ss, CmNfa* n) {
193
208
  }
194
209
  }
195
210
 
211
+ /* XSD xs:all at the model root: order-free, each particle at
212
+ * most maxOccurs times, minOccurs floors — a counting check over
213
+ * the particle list (XSD 1.0 restricts xs:all to the model root,
214
+ * each child a particle, maxOccurs <= 1). */
215
+ static int all_root_valid(XsdCm* all, const char* target_ns,
216
+ const char* const* names,
217
+ const char* const* ns_uris, size_t count) {
218
+ for (XsdCm* p = all->first_child; p; p = p->next) {
219
+ size_t hits = 0;
220
+ for (size_t i = 0; i < count; i++) {
221
+ const char* uri = ns_uris ? ns_uris[i] : NULL;
222
+ if (p->name && strcmp(p->name, names[i]) == 0 &&
223
+ (!p->ns || (uri && strcmp(uri, p->ns) == 0)))
224
+ hits++;
225
+ }
226
+ if ((long)hits < p->min) return 0;
227
+ if (p->max >= 0 && (long)hits > p->max) return 0;
228
+ }
229
+ /* every instance child must belong to a particle */
230
+ for (size_t i = 0; i < count; i++) {
231
+ int matched = 0;
232
+ const char* uri = ns_uris ? ns_uris[i] : NULL;
233
+ for (XsdCm* p = all->first_child; p && !matched; p = p->next) {
234
+ if (p->name && strcmp(p->name, names[i]) == 0 &&
235
+ (!p->ns || (uri && strcmp(uri, p->ns) == 0)))
236
+ matched = 1;
237
+ }
238
+ if (!matched) return 0;
239
+ }
240
+ (void)target_ns;
241
+ return 1;
242
+ }
243
+
196
244
  int xsd_content_valid(struct leptris_xsd_schema* s, XsdCm* model,
197
245
  const char* target_ns, const char* const* names,
198
246
  const char* const* ns_uris, size_t count) {
199
247
  if (!model) return -1;
248
+ if (model->kind == XSD_CM_ALL && model->first_child)
249
+ return all_root_valid(model, target_ns, names, ns_uris, count);
200
250
  CmNfa n;
201
251
  memset(&n, 0, sizeof(n));
202
252
  n.s = s;