leptris 1.9.320.0-arm-linux → 1.9.321.0-arm-linux

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.
@@ -0,0 +1,232 @@
1
+ /* xsd/content_model.c — #1075 slice 3: content-model evaluation.
2
+ *
3
+ * The compiled model tree lowers into a Thompson NFA (epsilon +
4
+ * symbol transitions, occurrence bounds via counting copies and a
5
+ * loop for unbounded) and the child sequence is consumed by
6
+ * simulating the live state set — linear in children x states, no
7
+ * backtracking blowup on nested choices.
8
+ *
9
+ * Namespace filters (xs:any/@namespace): "##any" (default),
10
+ * "##other" (not the target namespace, not unqualified),
11
+ * "##targetNamespace", "##local", or a space-separated URI list.
12
+ */
13
+ #include <stdlib.h>
14
+ #include <string.h>
15
+
16
+ #include "xsd_internal.h"
17
+
18
+ typedef struct {
19
+ int from;
20
+ int symbol; /* -1 = epsilon; else a particle transition */
21
+ XsdCm* particle; /* symbol owner (element ref or wildcard) */
22
+ int to;
23
+ } CmTrans;
24
+
25
+ typedef struct {
26
+ CmTrans* trans;
27
+ size_t count, cap;
28
+ int state_count; /* explicit: state ids are NOT transition ids */
29
+ int start, accept;
30
+ } CmNfa;
31
+
32
+ static int nfa_state(CmNfa* n) { return n->state_count++; }
33
+
34
+ static void nfa_trans(CmNfa* n, int from, int symbol, XsdCm* particle,
35
+ int to) {
36
+ if (n->count == n->cap) {
37
+ size_t cap = n->cap ? n->cap * 2 : 16;
38
+ CmTrans* grown = (CmTrans*)realloc(n->trans, cap * sizeof(*grown));
39
+ if (!grown) return; /* OOM: walk treats the NFA as non-matching */
40
+ n->trans = grown;
41
+ n->cap = cap;
42
+ }
43
+ n->trans[n->count].from = from;
44
+ n->trans[n->count].symbol = symbol;
45
+ n->trans[n->count].particle = particle;
46
+ n->trans[n->count].to = to;
47
+ n->count++;
48
+ }
49
+
50
+ static void cm_build(CmNfa* n, XsdCm* node, int from, int to);
51
+ static void cm_build_occurrence(CmNfa* n, XsdCm* node,
52
+ int from, int to);
53
+
54
+ /* chain the group children: first reads `from`, last writes `to`.
55
+ * xs:all is evaluated in sequence order for now (its order-free
56
+ * semantics arrive with slice 4's all-semantics pass). */
57
+ static void cm_build_children(CmNfa* n, XsdCm* node, int from, int to) {
58
+ XsdCm* c = node->first_child;
59
+ if (!c) {
60
+ nfa_trans(n, from, -1, NULL, to);
61
+ return;
62
+ }
63
+ int cursor = from;
64
+ while (c->next) {
65
+ int mid = nfa_state(n);
66
+ cm_build_occurrence(n, c, cursor, mid);
67
+ cursor = mid;
68
+ c = c->next;
69
+ }
70
+ cm_build_occurrence(n, c, cursor, to);
71
+ }
72
+
73
+ static void cm_build(CmNfa* n, XsdCm* node, int from, int to) {
74
+ switch (node->kind) {
75
+ case XSD_CM_ELEMENT:
76
+ case XSD_CM_ANY:
77
+ nfa_trans(n, from, 0, node, to);
78
+ return;
79
+ case XSD_CM_SEQ:
80
+ case XSD_CM_ALL:
81
+ cm_build_children(n, node, from, to);
82
+ return;
83
+ case XSD_CM_CHOICE: {
84
+ XsdCm* c = node->first_child;
85
+ if (!c) {
86
+ nfa_trans(n, from, -1, NULL, to);
87
+ return;
88
+ }
89
+ for (; c; c = c->next) cm_build_occurrence(n, c, from, to);
90
+ return;
91
+ }
92
+ }
93
+ }
94
+
95
+ /* occurrence bounds: min copies, then (max-min) optionals, or an
96
+ * epsilon self-loop region for unbounded. */
97
+ static void cm_build_occurrence(CmNfa* n, XsdCm* node, int from, int to) {
98
+ for (int i = 0; i < node->min; i++) {
99
+ int mid = nfa_state(n);
100
+ cm_build(n, node, from, mid);
101
+ from = mid;
102
+ }
103
+ if (node->max < 0) {
104
+ int loop = nfa_state(n);
105
+ nfa_trans(n, from, -1, NULL, loop);
106
+ cm_build(n, node, loop, loop);
107
+ nfa_trans(n, loop, -1, NULL, to);
108
+ return;
109
+ }
110
+ for (int i = node->min; i < node->max; i++) {
111
+ nfa_trans(n, from, -1, NULL, to);
112
+ int mid = nfa_state(n);
113
+ cm_build(n, node, from, mid);
114
+ from = mid;
115
+ }
116
+ nfa_trans(n, from, -1, NULL, to);
117
+ }
118
+
119
+ /* ---- namespace filter (xs:any/@namespace) ------------------------ */
120
+
121
+ static int any_ns_matches(XsdCm* any, const char* uri,
122
+ const char* target_ns) {
123
+ const char* f = any->any_ns ? any->any_ns : "##any";
124
+ if (strcmp(f, "##any") == 0) return 1;
125
+ if (strcmp(f, "##local") == 0) return uri == NULL;
126
+ if (strcmp(f, "##targetNamespace") == 0)
127
+ return target_ns && uri && strcmp(uri, target_ns) == 0;
128
+ if (strcmp(f, "##other") == 0)
129
+ return uri != NULL &&
130
+ !(target_ns && strcmp(uri, target_ns) == 0);
131
+ /* space-separated URI list (+##local) */
132
+ const char* p = f;
133
+ while (*p) {
134
+ while (*p == ' ') p++;
135
+ const char* start = p;
136
+ while (*p && *p != ' ') p++;
137
+ size_t len = (size_t)(p - start);
138
+ if (len == 0) break;
139
+ if (strncmp(start, "##local", len) == 0 && len == 7) {
140
+ if (uri == NULL) return 1;
141
+ continue;
142
+ }
143
+ if (uri && strlen(uri) == len && strncmp(start, uri, len) == 0)
144
+ return 1;
145
+ }
146
+ return 0;
147
+ }
148
+
149
+ /* ---- simulation --------------------------------------------------- */
150
+
151
+ typedef struct {
152
+ int* states;
153
+ size_t count, cap;
154
+ } StateSet;
155
+
156
+ static void ss_add(StateSet* ss, int st) {
157
+ for (size_t i = 0; i < ss->count; i++)
158
+ if (ss->states[i] == st) return;
159
+ if (ss->count == ss->cap) {
160
+ size_t cap = ss->cap ? ss->cap * 2 : 16;
161
+ int* grown = (int*)realloc(ss->states, cap * sizeof(int));
162
+ if (!grown) return;
163
+ ss->states = grown;
164
+ ss->cap = cap;
165
+ }
166
+ ss->states[ss->count++] = st;
167
+ }
168
+
169
+ static void ss_close(StateSet* ss, CmNfa* n) {
170
+ /* fixpoint over epsilon edges */
171
+ size_t i = 0;
172
+ while (i < ss->count) {
173
+ int st = ss->states[i];
174
+ for (size_t t = 0; t < n->count; t++)
175
+ if (n->trans[t].from == st && n->trans[t].symbol == -1)
176
+ ss_add(ss, n->trans[t].to);
177
+ i++;
178
+ }
179
+ }
180
+
181
+ int xsd_content_valid(struct leptris_xsd_schema* s, XsdCm* model,
182
+ const char* target_ns, const char* const* names,
183
+ const char* const* ns_uris, size_t count) {
184
+ (void)s;
185
+ if (!model) return -1;
186
+ CmNfa n;
187
+ memset(&n, 0, sizeof(n));
188
+ n.start = nfa_state(&n);
189
+ n.accept = nfa_state(&n);
190
+ cm_build_occurrence(&n, model, n.start, n.accept);
191
+
192
+ StateSet live;
193
+ memset(&live, 0, sizeof(live));
194
+ ss_add(&live, n.start);
195
+ ss_close(&live, &n);
196
+
197
+ for (size_t c = 0; c < count; c++) {
198
+ StateSet next;
199
+ memset(&next, 0, sizeof(next));
200
+ const char* uri = ns_uris ? ns_uris[c] : NULL;
201
+ for (size_t i = 0; i < live.count; i++) {
202
+ for (size_t t = 0; t < n.count; t++) {
203
+ CmTrans* tr = &n.trans[t];
204
+ if (tr->from != live.states[i] || tr->symbol == -1)
205
+ continue;
206
+ XsdCm* p = tr->particle;
207
+ if (p->kind == XSD_CM_ELEMENT) {
208
+ if (strcmp(p->name, names[c]) == 0 &&
209
+ (!p->ns || (uri && strcmp(uri, p->ns) == 0)))
210
+ ss_add(&next, tr->to);
211
+ } else if (p->kind == XSD_CM_ANY) {
212
+ if (any_ns_matches(p, uri, target_ns))
213
+ ss_add(&next, tr->to);
214
+ }
215
+ }
216
+ }
217
+ free(live.states);
218
+ live = next;
219
+ ss_close(&live, &n);
220
+ if (live.count == 0) {
221
+ free(n.trans);
222
+ return 0;
223
+ }
224
+ }
225
+
226
+ int accept = 0;
227
+ for (size_t i = 0; i < live.count; i++)
228
+ if (live.states[i] == n.accept) accept = 1;
229
+ free(live.states);
230
+ free(n.trans);
231
+ return accept;
232
+ }
@@ -0,0 +1,287 @@
1
+ /* xsd/validate.c — #1075 slice 4: instance-document validation.
2
+ *
3
+ * Walks an instance tree against the compiled schema: element
4
+ * declarations resolve by local name (global declarations), their
5
+ * types drive attribute checking (declared rows, required use),
6
+ * text-content lexical checks (builtins + user simpleTypes), and
7
+ * child-sequence content-model checks (slice 3's NFA). Failures
8
+ * accumulate in the schema-owned error list — the RNG accessor
9
+ * pattern: validate returns 1/0, errors enumerate every miss.
10
+ */
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+
15
+ #include "../../include/leptris.h"
16
+ #include "xsd_internal.h"
17
+
18
+ extern int xsd_content_valid(struct leptris_xsd_schema* s, XsdCm* model,
19
+ const char* target_ns,
20
+ const char* const* names,
21
+ const char* const* ns_uris, size_t count);
22
+ extern int xsd_builtin_valid(const char* type, const char* v);
23
+ extern int xsd_simple_valid(const XsdSimple* simple, const char* v);
24
+
25
+ struct xsd_error {
26
+ char* text;
27
+ struct xsd_error* next;
28
+ };
29
+
30
+ struct leptris_xsd_schema; /* opaque here; compile.c owns the struct */
31
+
32
+ /* The validator reaches the compiled model through accessors the
33
+ * compiler exports (compile.c defines the struct). */
34
+ extern const XsdElementDecl* xsd_find_element(
35
+ struct leptris_xsd_schema* s, const char* name);
36
+ extern XsdCm* xsd_find_complex(struct leptris_xsd_schema* s,
37
+ const char* type_name);
38
+ extern const XsdSimple* xsd_find_simple_pub(
39
+ struct leptris_xsd_schema* s, const char* name);
40
+ extern const char* xsd_target_ns(struct leptris_xsd_schema* s);
41
+ extern const XsdTypeAttrs* xsd_find_type_attrs(
42
+ struct leptris_xsd_schema* s, const char* type_name);
43
+
44
+ /* ---- error list ---------------------------------------------------- */
45
+
46
+ static void verr(struct leptris_xsd_schema* s, const char* fmt,
47
+ const char* a, const char* b);
48
+ struct xsd_validator {
49
+ struct leptris_xsd_schema* s;
50
+ struct xsd_error* errors;
51
+ struct xsd_error* tail;
52
+ size_t count;
53
+ };
54
+
55
+ static void verr_push(struct xsd_validator* v, const char* msg) {
56
+ struct xsd_error* e = (struct xsd_error*)malloc(sizeof(*e));
57
+ if (!e) return;
58
+ size_t n = strlen(msg) + 1;
59
+ e->text = (char*)malloc(n);
60
+ if (!e->text) {
61
+ free(e);
62
+ return;
63
+ }
64
+ memcpy(e->text, msg, n);
65
+ e->next = NULL;
66
+ if (v->tail)
67
+ v->tail->next = e;
68
+ else
69
+ v->errors = e;
70
+ v->tail = e;
71
+ v->count++;
72
+ }
73
+
74
+ static void verrf(struct xsd_validator* v, const char* what,
75
+ const char* name, const char* detail) {
76
+ /* "element 'x': detail" — bounded composition */
77
+ char buf[256];
78
+ int w = snprintf(buf, sizeof(buf), "%s '%s': %s", what,
79
+ name ? name : "?", detail ? detail : "invalid");
80
+ (void)w;
81
+ verr_push(v, buf);
82
+ }
83
+
84
+ /* ---- lexical helpers ---------------------------------------------- */
85
+
86
+ static int text_valid(struct xsd_validator* v,
87
+ struct leptris_xsd_schema* s, const char* type,
88
+ const char* lexical, const char* what,
89
+ const char* name) {
90
+ if (!type) return 1;
91
+ int r;
92
+ if (strncmp(type, "xs:", 3) == 0)
93
+ r = xsd_builtin_valid(type, lexical);
94
+ else {
95
+ const XsdSimple* st = xsd_find_simple_pub(s, type);
96
+ if (!st) return 1; /* unresolved: accept */
97
+ r = xsd_simple_valid(st, lexical);
98
+ }
99
+ if (r == 0) {
100
+ verrf(v, what, name, "lexical value does not match its type");
101
+ return 0;
102
+ }
103
+ return 1;
104
+ }
105
+
106
+ /* One element: attributes, text, children. */
107
+ static void validate_element(struct xsd_validator* v,
108
+ struct leptris_xsd_schema* s,
109
+ LeptrisElement elem, int depth);
110
+
111
+ static void validate_children(struct xsd_validator* v,
112
+ struct leptris_xsd_schema* s,
113
+ LeptrisElement elem, XsdCm* ct) {
114
+ XsdCm* model = ct->first_child;
115
+ if (!model) return;
116
+ /* collect child names + uris */
117
+ size_t n = 0;
118
+ for (LeptrisNodeRef c =
119
+ leptris_node_first_child(leptris_element_as_node(elem));
120
+ c; c = leptris_node_next_sibling(c))
121
+ if (leptris_node_get_type(c) == LEPTRIS_NODE_TYPE_ELEMENT) n++;
122
+ if (!n) return;
123
+ const char** names = (const char**)malloc(n * sizeof(char*));
124
+ const char** uris = (const char**)calloc(n, sizeof(char*));
125
+ if (!names || !uris) {
126
+ free(names);
127
+ free(uris);
128
+ return;
129
+ }
130
+ size_t i = 0;
131
+ for (LeptrisNodeRef c =
132
+ leptris_node_first_child(leptris_element_as_node(elem));
133
+ c; c = leptris_node_next_sibling(c)) {
134
+ if (leptris_node_get_type(c) != LEPTRIS_NODE_TYPE_ELEMENT)
135
+ continue;
136
+ LeptrisElement ce = (LeptrisElement)c;
137
+ const char* local = NULL, *prefix = NULL, *uri = NULL;
138
+ leptris_element_expanded_name(ce, &local, &prefix, &uri);
139
+ names[i] = local ? local : "";
140
+ uris[i] = uri;
141
+ i++;
142
+ }
143
+ int ok = xsd_content_valid(s, model, xsd_target_ns(s), names, uris,
144
+ n);
145
+ free(names);
146
+ free(uris);
147
+ if (!ok) {
148
+ const char* local = NULL;
149
+ leptris_element_expanded_name(elem, &local, NULL, NULL);
150
+ verrf(v, "element", local, "children do not match the content model");
151
+ }
152
+ /* recurse; local particles carry types (first-name-match DFS —
153
+ * position-exact particle typing arrives with the NFA trace). */
154
+ for (LeptrisNodeRef c =
155
+ leptris_node_first_child(leptris_element_as_node(elem));
156
+ c; c = leptris_node_next_sibling(c)) {
157
+ LeptrisElement ce = (LeptrisElement)c;
158
+ const char* cl = NULL, *cp = NULL, *cu = NULL;
159
+ leptris_element_expanded_name(ce, &cl, &cp, &cu);
160
+ if (cl && !xsd_find_element(s, cl) && model) {
161
+ const char* ptype = NULL;
162
+ XsdCm* stack[64];
163
+ int sp = 0;
164
+ stack[sp++] = model;
165
+ while (sp > 0 && ptype == NULL) {
166
+ XsdCm* p = stack[--sp];
167
+ for (; p; p = p->next) {
168
+ if (p->kind == XSD_CM_ELEMENT && p->name &&
169
+ strcmp(p->name, cl) == 0 && p->type) {
170
+ ptype = p->type;
171
+ break;
172
+ }
173
+ if (sp < 64 && p->first_child)
174
+ stack[sp++] = p->first_child;
175
+ }
176
+ }
177
+ if (ptype) {
178
+ const char* text = leptris_element_text(ce);
179
+ if (text && *text)
180
+ text_valid(v, s, ptype, text, "element", cl);
181
+ }
182
+ }
183
+ if (leptris_node_get_type(c) != LEPTRIS_NODE_TYPE_ELEMENT)
184
+ continue;
185
+ validate_element(v, s, ce, 0);
186
+ }
187
+ }
188
+
189
+ static void validate_attributes(struct xsd_validator* v,
190
+ struct leptris_xsd_schema* s,
191
+ LeptrisElement elem,
192
+ const XsdTypeAttrs* ta) {
193
+ if (!ta) return;
194
+ /* declared rows: present? value typed? */
195
+ for (XsdAttrDecl* a = ta->attrs; a; a = a->next) {
196
+ const char* val = leptris_element_attribute(elem, a->name);
197
+ if (!val) {
198
+ /* lenient: the qualified spelling (#1586 semantics) */
199
+ for (LeptrisAttribute at =
200
+ leptris_element_first_attribute(elem);
201
+ at; at = leptris_attribute_next(at)) {
202
+ const char* qn = leptris_attribute_get_name(at);
203
+ const char* colon = qn ? strchr(qn, ':') : NULL;
204
+ if (qn && colon && strcmp(colon + 1, a->name) == 0) {
205
+ val = leptris_attribute_get_value(elem, at);
206
+ break;
207
+ }
208
+ if (qn && !colon && strcmp(qn, a->name) == 0) {
209
+ val = leptris_attribute_get_value(elem, at);
210
+ break;
211
+ }
212
+ }
213
+ }
214
+ if (!val) {
215
+ if (a->required)
216
+ verrf(v, "attribute", a->name, "required but absent");
217
+ continue;
218
+ }
219
+ text_valid(v, s, a->type, val, "attribute", a->name);
220
+ }
221
+ }
222
+
223
+ static void validate_element(struct xsd_validator* v,
224
+ struct leptris_xsd_schema* s,
225
+ LeptrisElement elem, int depth) {
226
+ if (depth > 64) return;
227
+ const char* local = NULL, *prefix = NULL, *uri = NULL;
228
+ leptris_element_expanded_name(elem, &local, &prefix, &uri);
229
+ if (!local) return;
230
+ const XsdElementDecl* d = xsd_find_element(s, local);
231
+ if (!d) return; /* undeclared: lax at this depth (strict later) */
232
+
233
+ if (!d->type) return; /* anyType */
234
+
235
+ XsdCm* ct = xsd_find_complex(s, d->type);
236
+ if (ct) {
237
+ validate_attributes(v, s, elem, xsd_find_type_attrs(s, d->type));
238
+ validate_children(v, s, elem, ct);
239
+ return;
240
+ }
241
+
242
+ /* simple-typed element: text must be lexically valid */
243
+ if (strncmp(d->type, "xs:", 3) == 0 ||
244
+ xsd_find_simple_pub(s, d->type)) {
245
+ const char* text = leptris_element_text(elem);
246
+ if (text && *text)
247
+ text_valid(v, s, d->type, text, "element", local);
248
+ }
249
+ }
250
+
251
+ struct xsd_validator* xsd_validator_new(struct leptris_xsd_schema* s) {
252
+ struct xsd_validator* v =
253
+ (struct xsd_validator*)calloc(1, sizeof(*v));
254
+ if (v) v->s = s;
255
+ return v;
256
+ }
257
+
258
+ void xsd_validator_free(struct xsd_validator* v) {
259
+ if (!v) return;
260
+ struct xsd_error* e = v->errors;
261
+ while (e) {
262
+ struct xsd_error* n = e->next;
263
+ free(e->text);
264
+ free(e);
265
+ e = n;
266
+ }
267
+ free(v);
268
+ }
269
+
270
+ int xsd_validator_run(struct xsd_validator* v, LeptrisDocument doc) {
271
+ if (!v || !doc) return -1;
272
+ LeptrisElement root = leptris_document_root(doc);
273
+ if (!root) return -1;
274
+ validate_element(v, v->s, root, 0);
275
+ return v->count == 0 ? 1 : 0;
276
+ }
277
+
278
+ size_t xsd_validator_error_count(struct xsd_validator* v) {
279
+ return v ? v->count : 0;
280
+ }
281
+
282
+ const char* xsd_validator_error_at(struct xsd_validator* v, size_t i) {
283
+ if (!v) return NULL;
284
+ struct xsd_error* e = v->errors;
285
+ for (size_t k = 0; e && k < i; k++) e = e->next;
286
+ return e ? e->text : NULL;
287
+ }
@@ -37,7 +37,55 @@ typedef struct xsd_simple {
37
37
  struct xsd_simple* next;
38
38
  } XsdSimple;
39
39
 
40
+ /* Content-model node: a particle (element ref / wildcard) or a
41
+ * group (sequence | choice | all). Owned by the schema; freed
42
+ * with the schema. */
43
+ typedef enum {
44
+ XSD_CM_ELEMENT = 0,
45
+ XSD_CM_ANY,
46
+ XSD_CM_SEQ,
47
+ XSD_CM_CHOICE,
48
+ XSD_CM_ALL
49
+ } XsdCmKind;
50
+
51
+ typedef struct xsd_cm {
52
+ XsdCmKind kind;
53
+ char* name; /* CM_ELEMENT: child element local name */
54
+ char* type; /* CM_ELEMENT: the particle's type ref, if any */
55
+ char* ns; /* CM_ELEMENT: expected namespace (NULL = unqualified) */
56
+ char* any_ns; /* CM_ANY: the namespace attribute grammar */
57
+ int process_skip; /* CM_ANY: processContents="skip" or "lax" */
58
+ int min, max; /* occurrence bounds; max < 0 = unbounded */
59
+ struct xsd_cm* first_child; /* group children list */
60
+ struct xsd_cm* next; /* sibling link within the parent group */
61
+ } XsdCm;
62
+
63
+ /* A top-level xs:element declaration (slice 3: name + type ref). */
64
+ typedef struct xsd_element_decl {
65
+ char* name;
66
+ char* type; /* "xs:string"-style builtin or a local type name */
67
+ struct xsd_element_decl* next;
68
+ } XsdElementDecl;
69
+
70
+ typedef struct xsd_attr_decl {
71
+ char* name; /* attribute local name */
72
+ char* type; /* builtin ref or local simpleType name (NULL=anySimple) */
73
+ int required;
74
+ struct xsd_attr_decl* next;
75
+ } XsdAttrDecl;
76
+
77
+ /* complexType name -> its attribute declarations (hash-free: a
78
+ * parallel list keyed the same way as complex model roots). */
79
+ typedef struct xsd_type_attrs {
80
+ char* type_name;
81
+ XsdAttrDecl* attrs;
82
+ struct xsd_type_attrs* next;
83
+ } XsdTypeAttrs;
84
+
40
85
  #ifdef __cplusplus
41
86
  }
42
87
  #endif
88
+
89
+ /* ---- slice 4: attribute declarations + instance validation ------- */
90
+
43
91
  #endif /* LEPTRIS_XSD_INTERNAL_H */