leptris 1.9.324.0-aarch64-linux → 1.9.331.0-aarch64-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/Rakefile +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/ffi.rb +5 -0
- data/lib/leptris/xml/xsd.rb +18 -0
- data/lib/libleptris.so +0 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +145 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/cli/commands/validate.c +5 -7
- data/vendor-src/libleptris/src/include/leptris.h +8 -0
- data/vendor-src/libleptris/src/leptris/dom/node_public.c +1 -1
- data/vendor-src/libleptris/src/leptris/dom/text.c +4 -2
- data/vendor-src/libleptris/src/leptris/dom/text.h +7 -2
- data/vendor-src/libleptris/src/leptris/flat/direct_parse.c +32 -4
- data/vendor-src/libleptris/src/leptris/html/html_parse.c +2 -1
- data/vendor-src/libleptris/src/leptris/leptris.c +7 -2
- data/vendor-src/libleptris/src/leptris/xsd/compile.c +793 -78
- data/vendor-src/libleptris/src/leptris/xsd/content_model.c +20 -2
- data/vendor-src/libleptris/src/leptris/xsd/validate.c +57 -19
- data/vendor-src/libleptris/src/leptris/xsd/xsd_internal.h +62 -3
- data/vendor-src/libleptris/src/leptris/xslt/xslt_exec.c +1 -1
- data/vendor-src/libleptris/test/CMakeLists.txt +5 -0
- data/vendor-src/libleptris/test/parser/test_parser.cpp +116 -0
- data/vendor-src/libleptris/test/xsd/test_xsd_compile.cpp +399 -4
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +1 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* grow the model (datatypes, facets, content models, identity
|
|
5
5
|
* constraints) — this slice's contract is the API shape, the
|
|
6
6
|
* xs:schema identity check, and the declaration enumeration. */
|
|
7
|
+
#include <ctype.h>
|
|
7
8
|
#include <stdio.h>
|
|
8
9
|
#include <stdlib.h>
|
|
9
10
|
#include <string.h>
|
|
@@ -34,9 +35,14 @@ struct leptris_xsd_schema {
|
|
|
34
35
|
XsdSimple* simple_types;
|
|
35
36
|
XsdElementDecl* elements;
|
|
36
37
|
XsdCm* complex_types; /* name-carrying model roots */
|
|
38
|
+
XsdGroupDef* groups; /* top-level xs:group definitions */
|
|
39
|
+
XsdAttrGroupDef* attr_groups;
|
|
40
|
+
XsdAttrDecl* top_attrs; /* top-level xs:attribute declarations */
|
|
37
41
|
XsdTypeAttrs* type_attrs;
|
|
38
42
|
XsdElementIcs* element_ics;
|
|
39
43
|
char* target_ns;
|
|
44
|
+
char* base_dir; /* schemaLocation resolution (file compile) */
|
|
45
|
+
int include_depth; /* include/import recursion guard */
|
|
40
46
|
void* validator; /* slice-4 parked error list */
|
|
41
47
|
char* error;
|
|
42
48
|
};
|
|
@@ -56,6 +62,24 @@ static XsdCm* xsd_cm_new(XsdCmKind kind);
|
|
|
56
62
|
static void xsd_cm_occurrence(XsdCm* cm, LeptrisElement e);
|
|
57
63
|
static XsdCm* xsd_cm_parse(struct leptris_xsd_schema* s,
|
|
58
64
|
LeptrisElement group, XsdCm** tail_out);
|
|
65
|
+
static XsdAttrDecl* xsd_capture_attr_rows(struct leptris_xsd_schema* s,
|
|
66
|
+
LeptrisElement container,
|
|
67
|
+
int depth);
|
|
68
|
+
extern XsdCm* xsd_find_complex(struct leptris_xsd_schema* s,
|
|
69
|
+
const char* type_name);
|
|
70
|
+
extern const XsdTypeAttrs* xsd_find_type_attrs(
|
|
71
|
+
struct leptris_xsd_schema* s, const char* type_name);
|
|
72
|
+
static XsdCm* xsd_cm_copy_list(const XsdCm* head);
|
|
73
|
+
static void xsd_capture_root(struct leptris_xsd_schema* s,
|
|
74
|
+
LeptrisElement root);
|
|
75
|
+
static char* xsd_read_file(const char* path, size_t* out_len);
|
|
76
|
+
static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src);
|
|
77
|
+
static void xsd_register_complex(struct leptris_xsd_schema* s,
|
|
78
|
+
XsdCm* root, XsdAttrDecl* attrs,
|
|
79
|
+
const char* name);
|
|
80
|
+
static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
81
|
+
LeptrisElement ct,
|
|
82
|
+
const char* name);
|
|
59
83
|
static XsdSimple* xsd_capture_simple(LeptrisElement st);
|
|
60
84
|
|
|
61
85
|
|
|
@@ -76,6 +100,7 @@ static void xsd_cm_free(XsdCm* cm) {
|
|
|
76
100
|
free(cm->type);
|
|
77
101
|
free(cm->ns);
|
|
78
102
|
free(cm->any_ns);
|
|
103
|
+
free(cm->text_type);
|
|
79
104
|
free(cm);
|
|
80
105
|
cm = next;
|
|
81
106
|
}
|
|
@@ -107,13 +132,7 @@ static int xsd_capture_inline(struct leptris_xsd_schema* s,
|
|
|
107
132
|
leptris_element_expanded_name(e, &local, &prefix, &uri);
|
|
108
133
|
if (!local || !uri || strcmp(uri, XSD_NS) != 0) continue;
|
|
109
134
|
if (strcmp(local, "complexType") == 0) {
|
|
110
|
-
|
|
111
|
-
if (!root) return 0;
|
|
112
|
-
root->name = xsd_strdup(synth);
|
|
113
|
-
root->first_child = xsd_cm_parse(s, e, NULL);
|
|
114
|
-
root->next = s->complex_types;
|
|
115
|
-
s->complex_types = root;
|
|
116
|
-
return 1;
|
|
135
|
+
return xsd_capture_complex_model(s, e, synth) ? 1 : 0;
|
|
117
136
|
}
|
|
118
137
|
if (strcmp(local, "simpleType") == 0) {
|
|
119
138
|
XsdSimple* captured = xsd_capture_simple(e);
|
|
@@ -168,6 +187,13 @@ static XsdCm* xsd_cm_parse(struct leptris_xsd_schema* s,
|
|
|
168
187
|
cm->type = xsd_strdup(synth);
|
|
169
188
|
}
|
|
170
189
|
}
|
|
190
|
+
} else if (strcmp(local, "group") == 0) {
|
|
191
|
+
/* <xs:group ref="g"/> — expanded at NFA build so
|
|
192
|
+
* forward references need no capture order */
|
|
193
|
+
cm = xsd_cm_new(XSD_CM_GROUP_REF);
|
|
194
|
+
if (cm)
|
|
195
|
+
cm->name = xsd_strdup(
|
|
196
|
+
leptris_element_attribute(e, "ref"));
|
|
171
197
|
} else if (strcmp(local, "any") == 0) {
|
|
172
198
|
cm = xsd_cm_new(XSD_CM_ANY);
|
|
173
199
|
if (cm) {
|
|
@@ -225,7 +251,81 @@ static XsdSimple* xsd_capture_simple(LeptrisElement st) {
|
|
|
225
251
|
leptris_element_expanded_name(e, &local, &prefix, &uri);
|
|
226
252
|
if (uri && strcmp(uri, XSD_NS) != 0) continue;
|
|
227
253
|
if (!local) continue;
|
|
228
|
-
if (strcmp(local, "
|
|
254
|
+
if (strcmp(local, "list") == 0) {
|
|
255
|
+
simple->deriv = XSD_SIMPLE_LIST;
|
|
256
|
+
const char* it = leptris_element_attribute(e, "itemType");
|
|
257
|
+
if (it && *it) {
|
|
258
|
+
simple->item_type = xsd_strdup(it);
|
|
259
|
+
} else {
|
|
260
|
+
/* inline anonymous item type rides this capture */
|
|
261
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
262
|
+
leptris_element_as_node(e));
|
|
263
|
+
q && !simple->item_def;
|
|
264
|
+
q = leptris_node_next_sibling(q)) {
|
|
265
|
+
if (leptris_node_get_type(q) !=
|
|
266
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
267
|
+
continue;
|
|
268
|
+
LeptrisElement qe = (LeptrisElement)q;
|
|
269
|
+
const char* ql = NULL;
|
|
270
|
+
leptris_element_expanded_name(qe, &ql, NULL, NULL);
|
|
271
|
+
if (ql && strcmp(ql, "simpleType") == 0)
|
|
272
|
+
simple->item_def = xsd_capture_simple(qe);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} else if (strcmp(local, "union") == 0) {
|
|
276
|
+
simple->deriv = XSD_SIMPLE_UNION;
|
|
277
|
+
const char* mt =
|
|
278
|
+
leptris_element_attribute(e, "memberTypes");
|
|
279
|
+
if (mt && *mt) {
|
|
280
|
+
size_t n = 0;
|
|
281
|
+
for (const char* p = mt; *p;) {
|
|
282
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
283
|
+
if (!*p) break;
|
|
284
|
+
while (*p && !isspace((unsigned char)*p)) p++;
|
|
285
|
+
n++;
|
|
286
|
+
}
|
|
287
|
+
if (n) {
|
|
288
|
+
simple->members = (char**)calloc(n, sizeof(char*));
|
|
289
|
+
if (simple->members) {
|
|
290
|
+
size_t i = 0;
|
|
291
|
+
const char* p = mt;
|
|
292
|
+
while (*p && i < n) {
|
|
293
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
294
|
+
if (!*p) break;
|
|
295
|
+
const char* start = p;
|
|
296
|
+
while (*p && !isspace((unsigned char)*p)) p++;
|
|
297
|
+
size_t len = (size_t)(p - start);
|
|
298
|
+
char* tok = (char*)malloc(len + 1);
|
|
299
|
+
if (!tok) break;
|
|
300
|
+
memcpy(tok, start, len);
|
|
301
|
+
tok[len] = 0;
|
|
302
|
+
simple->members[i++] = tok;
|
|
303
|
+
}
|
|
304
|
+
simple->member_count = i;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/* inline anonymous members ride this capture */
|
|
309
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
310
|
+
leptris_element_as_node(e));
|
|
311
|
+
q; q = leptris_node_next_sibling(q)) {
|
|
312
|
+
if (leptris_node_get_type(q) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
313
|
+
continue;
|
|
314
|
+
LeptrisElement qe = (LeptrisElement)q;
|
|
315
|
+
const char* ql = NULL;
|
|
316
|
+
leptris_element_expanded_name(qe, &ql, NULL, NULL);
|
|
317
|
+
if (!ql || strcmp(ql, "simpleType") != 0) continue;
|
|
318
|
+
XsdSimple* def = xsd_capture_simple(qe);
|
|
319
|
+
if (!def) continue;
|
|
320
|
+
XsdSimple** grown = (XsdSimple**)realloc(
|
|
321
|
+
simple->member_defs,
|
|
322
|
+
(simple->member_def_count + 1) *
|
|
323
|
+
sizeof(XsdSimple*));
|
|
324
|
+
if (!grown) break;
|
|
325
|
+
simple->member_defs = grown;
|
|
326
|
+
simple->member_defs[simple->member_def_count++] = def;
|
|
327
|
+
}
|
|
328
|
+
} else if (strcmp(local, "restriction") == 0) {
|
|
229
329
|
simple->base =
|
|
230
330
|
xsd_strdup(leptris_element_attribute(e, "base"));
|
|
231
331
|
for (LeptrisNodeRef f = leptris_node_first_child(
|
|
@@ -287,6 +387,71 @@ static const XsdSimple* xsd_find_simple(struct leptris_xsd_schema* s,
|
|
|
287
387
|
return NULL;
|
|
288
388
|
}
|
|
289
389
|
|
|
390
|
+
extern int xsd_builtin_valid(const char* type, const char* v);
|
|
391
|
+
extern int rng_regex_matches(const char* pat, const char* text);
|
|
392
|
+
static int xsd_valid_chain(struct leptris_xsd_schema* s,
|
|
393
|
+
const XsdSimple* t, const char* v, int depth);
|
|
394
|
+
|
|
395
|
+
/* One list item or union member: a builtin reference, a local
|
|
396
|
+
* schema type (chain-walked), or an inline capture. Unresolved
|
|
397
|
+
* names accept (the compile-time leniency the corpus gate pins). */
|
|
398
|
+
static int xsd_item_valid(struct leptris_xsd_schema* s,
|
|
399
|
+
const char* name, const XsdSimple* def,
|
|
400
|
+
const char* v, int depth) {
|
|
401
|
+
if (name && strncmp(name, "xs:", 3) == 0)
|
|
402
|
+
return xsd_builtin_valid(name, v);
|
|
403
|
+
if (def) return xsd_valid_chain(s, def, v, depth + 1);
|
|
404
|
+
if (name) {
|
|
405
|
+
const XsdSimple* next = xsd_find_simple(s, name);
|
|
406
|
+
if (next) return xsd_valid_chain(s, next, v, depth + 1);
|
|
407
|
+
}
|
|
408
|
+
return 1;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
static int xsd_deriv_valid(struct leptris_xsd_schema* s,
|
|
412
|
+
const XsdSimple* t, const char* v,
|
|
413
|
+
int depth) {
|
|
414
|
+
if (t->deriv == XSD_SIMPLE_LIST) {
|
|
415
|
+
char* dup = xsd_strdup(v);
|
|
416
|
+
if (!dup) return 0;
|
|
417
|
+
size_t n = 0;
|
|
418
|
+
int ok = 1;
|
|
419
|
+
for (char* p = dup; *p;) {
|
|
420
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
421
|
+
if (!*p) break;
|
|
422
|
+
char* end = p;
|
|
423
|
+
while (*end && !isspace((unsigned char)*end)) end++;
|
|
424
|
+
char was = *end;
|
|
425
|
+
*end = 0;
|
|
426
|
+
if (ok && !xsd_item_valid(s, t->item_type, t->item_def, p,
|
|
427
|
+
depth))
|
|
428
|
+
ok = 0;
|
|
429
|
+
*end = was;
|
|
430
|
+
p = end;
|
|
431
|
+
n++;
|
|
432
|
+
}
|
|
433
|
+
free(dup);
|
|
434
|
+
/* length family counts ITEMS for lists (XSD semantics) */
|
|
435
|
+
if (ok && t->length >= 0 && (long)n != t->length) ok = 0;
|
|
436
|
+
if (ok && t->min_length >= 0 && (long)n < t->min_length) ok = 0;
|
|
437
|
+
if (ok && t->max_length >= 0 && (long)n > t->max_length) ok = 0;
|
|
438
|
+
/* pattern applies to the whole lexical */
|
|
439
|
+
if (ok && t->pattern && !rng_regex_matches(t->pattern, v))
|
|
440
|
+
ok = 0;
|
|
441
|
+
return ok;
|
|
442
|
+
}
|
|
443
|
+
if (t->deriv == XSD_SIMPLE_UNION) {
|
|
444
|
+
for (size_t i = 0; i < t->member_count; i++)
|
|
445
|
+
if (xsd_item_valid(s, t->members[i], NULL, v, depth))
|
|
446
|
+
return 1;
|
|
447
|
+
for (size_t i = 0; i < t->member_def_count; i++)
|
|
448
|
+
if (xsd_item_valid(s, NULL, t->member_defs[i], v, depth))
|
|
449
|
+
return 1;
|
|
450
|
+
return 0;
|
|
451
|
+
}
|
|
452
|
+
return xsd_simple_valid(t, v);
|
|
453
|
+
}
|
|
454
|
+
|
|
290
455
|
static int xsd_valid_chain(struct leptris_xsd_schema* s,
|
|
291
456
|
const XsdSimple* t, const char* v, int depth) {
|
|
292
457
|
if (!t || depth > 32) return 0;
|
|
@@ -294,6 +459,8 @@ static int xsd_valid_chain(struct leptris_xsd_schema* s,
|
|
|
294
459
|
const XsdSimple* next = xsd_find_simple(s, t->base);
|
|
295
460
|
if (next && !xsd_valid_chain(s, next, v, depth + 1)) return 0;
|
|
296
461
|
}
|
|
462
|
+
if (t->deriv != XSD_SIMPLE_RESTRICT)
|
|
463
|
+
return xsd_deriv_valid(s, t, v, depth);
|
|
297
464
|
return xsd_simple_valid(t, v);
|
|
298
465
|
}
|
|
299
466
|
|
|
@@ -321,9 +488,82 @@ static int xsd_is_declaration(const char* local, const char* uri) {
|
|
|
321
488
|
return 0;
|
|
322
489
|
}
|
|
323
490
|
|
|
491
|
+
static char* xsd_read_file(const char* path, size_t* out_len) {
|
|
492
|
+
*out_len = 0;
|
|
493
|
+
FILE* f = fopen(path, "rb");
|
|
494
|
+
if (!f) return NULL;
|
|
495
|
+
if (fseek(f, 0, SEEK_END) != 0) {
|
|
496
|
+
fclose(f);
|
|
497
|
+
return NULL;
|
|
498
|
+
}
|
|
499
|
+
long size = ftell(f);
|
|
500
|
+
if (size < 0 || fseek(f, 0, SEEK_SET) != 0) {
|
|
501
|
+
fclose(f);
|
|
502
|
+
return NULL;
|
|
503
|
+
}
|
|
504
|
+
char* buf = (char*)malloc((size_t)size + 1);
|
|
505
|
+
if (!buf) {
|
|
506
|
+
fclose(f);
|
|
507
|
+
return NULL;
|
|
508
|
+
}
|
|
509
|
+
size_t got = fread(buf, 1, (size_t)size, f);
|
|
510
|
+
fclose(f);
|
|
511
|
+
buf[got] = 0;
|
|
512
|
+
*out_len = got;
|
|
513
|
+
return buf;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
|
|
517
|
+
size_t len,
|
|
518
|
+
const char* base_dir,
|
|
519
|
+
LeptrisStatus* status);
|
|
520
|
+
|
|
324
521
|
LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
325
522
|
size_t len,
|
|
326
523
|
LeptrisStatus* status) {
|
|
524
|
+
return xsd_compile_impl(xsd_text, len, NULL, status);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile_file(
|
|
528
|
+
const char* path, LeptrisStatus* status) {
|
|
529
|
+
if (status) *status = LEPTRIS_OK;
|
|
530
|
+
if (!path || !*path) {
|
|
531
|
+
if (status) *status = LEPTRIS_ERROR_PARSE;
|
|
532
|
+
return NULL;
|
|
533
|
+
}
|
|
534
|
+
size_t len = 0;
|
|
535
|
+
char* text = xsd_read_file(path, &len);
|
|
536
|
+
if (!text) {
|
|
537
|
+
if (status) *status = LEPTRIS_ERROR_PARSE;
|
|
538
|
+
return NULL;
|
|
539
|
+
}
|
|
540
|
+
/* relative schemaLocations resolve against the schema's own
|
|
541
|
+
* directory (both separators: Windows paths carry '\') */
|
|
542
|
+
const char* slash = strrchr(path, '/');
|
|
543
|
+
const char* bslash = strrchr(path, '\\');
|
|
544
|
+
if (bslash && (!slash || bslash > slash)) slash = bslash;
|
|
545
|
+
char* base_dir = NULL;
|
|
546
|
+
if (slash) {
|
|
547
|
+
size_t n = (size_t)(slash - path);
|
|
548
|
+
if (n == 0) n = 1; /* "/f.xsd" roots at "/" */
|
|
549
|
+
base_dir = (char*)malloc(n + 1);
|
|
550
|
+
if (base_dir) {
|
|
551
|
+
memcpy(base_dir, path, n);
|
|
552
|
+
base_dir[n] = 0;
|
|
553
|
+
}
|
|
554
|
+
} else {
|
|
555
|
+
base_dir = xsd_strdup(".");
|
|
556
|
+
}
|
|
557
|
+
LeptrisXsdSchema s = xsd_compile_impl(text, len, base_dir, status);
|
|
558
|
+
free(base_dir);
|
|
559
|
+
free(text);
|
|
560
|
+
return s;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
|
|
564
|
+
size_t len,
|
|
565
|
+
const char* base_dir,
|
|
566
|
+
LeptrisStatus* status) {
|
|
327
567
|
if (status) *status = LEPTRIS_OK;
|
|
328
568
|
if (!xsd_text || len == 0) {
|
|
329
569
|
if (status) *status = LEPTRIS_ERROR_PARSE;
|
|
@@ -336,6 +576,7 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
|
336
576
|
if (status) *status = LEPTRIS_ERROR_MEMORY;
|
|
337
577
|
return NULL;
|
|
338
578
|
}
|
|
579
|
+
s->base_dir = xsd_strdup(base_dir);
|
|
339
580
|
|
|
340
581
|
/* target namespace (xs:any ##other/##targetNamespace filters) */
|
|
341
582
|
s->target_ns = NULL;
|
|
@@ -367,15 +608,79 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
|
367
608
|
goto fail;
|
|
368
609
|
}
|
|
369
610
|
|
|
611
|
+
xsd_capture_root(s, root);
|
|
612
|
+
|
|
613
|
+
leptris_document_free(doc);
|
|
614
|
+
return s;
|
|
615
|
+
|
|
616
|
+
fail:
|
|
617
|
+
if (doc) leptris_document_free(doc);
|
|
618
|
+
if (status) *status = LEPTRIS_ERROR_PARSE;
|
|
619
|
+
/* Failure returns an error-carrying handle (the documented
|
|
620
|
+
* contract): leptris_xsd_error says why, free it the same way. */
|
|
621
|
+
return (LeptrisXsdSchema)s;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* Every top-level declaration under an xs:schema root. xs:include
|
|
625
|
+
* / xs:import / xs:redefine resolve their schemaLocation against
|
|
626
|
+
* the owning schema's base_dir (string-compiled schemas have none
|
|
627
|
+
* and skip them); the referenced root's declarations merge into
|
|
628
|
+
* the same tables. */
|
|
629
|
+
static void xsd_capture_root(struct leptris_xsd_schema* s,
|
|
630
|
+
LeptrisElement root) {
|
|
370
631
|
for (LeptrisNodeRef n =
|
|
371
632
|
leptris_node_first_child(leptris_element_as_node(root));
|
|
372
633
|
n; n = leptris_node_next_sibling(n)) {
|
|
373
634
|
if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
374
635
|
continue;
|
|
636
|
+
const char* local = NULL;
|
|
637
|
+
const char* prefix = NULL;
|
|
638
|
+
const char* uri = NULL;
|
|
375
639
|
leptris_element_expanded_name((LeptrisElement)n, &local, &prefix,
|
|
376
640
|
&uri);
|
|
377
641
|
if (!xsd_is_declaration(local, uri)) continue;
|
|
378
642
|
s->declaration_count++;
|
|
643
|
+
|
|
644
|
+
if (strcmp(local, "include") == 0 ||
|
|
645
|
+
strcmp(local, "import") == 0 ||
|
|
646
|
+
strcmp(local, "redefine") == 0) {
|
|
647
|
+
const char* loc = leptris_element_attribute(
|
|
648
|
+
(LeptrisElement)n, "schemaLocation");
|
|
649
|
+
if (loc && s->base_dir && s->include_depth < 16) {
|
|
650
|
+
char path[4096];
|
|
651
|
+
snprintf(path, sizeof(path), "%s/%s", s->base_dir,
|
|
652
|
+
loc);
|
|
653
|
+
size_t flen = 0;
|
|
654
|
+
char* text = xsd_read_file(path, &flen);
|
|
655
|
+
if (text) {
|
|
656
|
+
LeptrisDocument sub =
|
|
657
|
+
leptris_parse_string(text, flen, NULL);
|
|
658
|
+
if (sub) {
|
|
659
|
+
LeptrisElement subroot =
|
|
660
|
+
leptris_document_root(sub);
|
|
661
|
+
const char* tns =
|
|
662
|
+
subroot
|
|
663
|
+
? leptris_element_attribute(
|
|
664
|
+
subroot, "targetNamespace")
|
|
665
|
+
: NULL;
|
|
666
|
+
/* same-namespace merges and no-namespace
|
|
667
|
+
* chameleon includes; foreign-namespace
|
|
668
|
+
* imports stay lax at this tier */
|
|
669
|
+
if (subroot &&
|
|
670
|
+
(!tns || !s->target_ns ||
|
|
671
|
+
strcmp(tns, s->target_ns) == 0)) {
|
|
672
|
+
s->include_depth++;
|
|
673
|
+
xsd_capture_root(s, subroot);
|
|
674
|
+
s->include_depth--;
|
|
675
|
+
}
|
|
676
|
+
leptris_document_free(sub);
|
|
677
|
+
}
|
|
678
|
+
free(text);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
|
|
379
684
|
if (strcmp(local, "element") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
380
685
|
const char* nm = leptris_element_attribute((LeptrisElement)n,
|
|
381
686
|
"name");
|
|
@@ -387,6 +692,16 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
|
387
692
|
if (d) {
|
|
388
693
|
d->name = xsd_strdup(nm);
|
|
389
694
|
d->type = xsd_strdup(ty);
|
|
695
|
+
d->fixed = xsd_strdup(
|
|
696
|
+
leptris_element_attribute((LeptrisElement)n,
|
|
697
|
+
"fixed"));
|
|
698
|
+
const char* sg = leptris_element_attribute(
|
|
699
|
+
(LeptrisElement)n, "substitutionGroup");
|
|
700
|
+
if (sg) {
|
|
701
|
+
const char* colon = strchr(sg, ':');
|
|
702
|
+
d->sub_head = xsd_strdup(
|
|
703
|
+
colon ? colon + 1 : sg);
|
|
704
|
+
}
|
|
390
705
|
d->next = s->elements;
|
|
391
706
|
s->elements = d;
|
|
392
707
|
}
|
|
@@ -411,57 +726,54 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
|
411
726
|
}
|
|
412
727
|
} else if (strcmp(local, "complexType") == 0 && uri &&
|
|
413
728
|
!strcmp(uri, XSD_NS)) {
|
|
729
|
+
const char* nm =
|
|
730
|
+
leptris_element_attribute((LeptrisElement)n, "name");
|
|
731
|
+
if (nm)
|
|
732
|
+
xsd_capture_complex_model(s, (LeptrisElement)n, nm);
|
|
733
|
+
} else if (strcmp(local, "attribute") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
414
734
|
const char* nm =
|
|
415
735
|
leptris_element_attribute((LeptrisElement)n, "name");
|
|
416
736
|
if (nm) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
root->name = xsd_strdup(nm);
|
|
421
|
-
root->first_child =
|
|
422
|
-
xsd_cm_parse(s, (LeptrisElement)n, NULL);
|
|
423
|
-
root->next = s->complex_types;
|
|
424
|
-
s->complex_types = root;
|
|
425
|
-
}
|
|
426
|
-
/* slice 4: attribute declarations of the type */
|
|
427
|
-
XsdAttrDecl* head = NULL;
|
|
428
|
-
XsdAttrDecl* tail = NULL;
|
|
429
|
-
for (LeptrisNodeRef ac = leptris_node_first_child(
|
|
430
|
-
leptris_element_as_node((LeptrisElement)n));
|
|
431
|
-
ac; ac = leptris_node_next_sibling(ac)) {
|
|
432
|
-
if (leptris_node_get_type(ac) !=
|
|
433
|
-
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
434
|
-
continue;
|
|
435
|
-
LeptrisElement ae = (LeptrisElement)ac;
|
|
436
|
-
const char* al = NULL, *ap = NULL, *au = NULL;
|
|
437
|
-
leptris_element_expanded_name(ae, &al, &ap, &au);
|
|
438
|
-
if (!al || (au && strcmp(au, XSD_NS) != 0)) continue;
|
|
439
|
-
if (strcmp(al, "attribute") != 0) continue;
|
|
440
|
-
const char* an = leptris_element_attribute(ae, "name");
|
|
441
|
-
if (!an) continue; /* ref forms: slice 5 */
|
|
442
|
-
XsdAttrDecl* d = (XsdAttrDecl*)calloc(1, sizeof(*d));
|
|
443
|
-
if (!d) continue;
|
|
444
|
-
d->name = xsd_strdup(an);
|
|
737
|
+
XsdAttrDecl* d = (XsdAttrDecl*)calloc(1, sizeof(*d));
|
|
738
|
+
if (d) {
|
|
739
|
+
d->name = xsd_strdup(nm);
|
|
445
740
|
d->type = xsd_strdup(
|
|
446
|
-
leptris_element_attribute(
|
|
447
|
-
|
|
448
|
-
|
|
741
|
+
leptris_element_attribute((LeptrisElement)n,
|
|
742
|
+
"type"));
|
|
743
|
+
d->fixed = xsd_strdup(
|
|
744
|
+
leptris_element_attribute((LeptrisElement)n,
|
|
745
|
+
"fixed"));
|
|
746
|
+
const char* use = leptris_element_attribute(
|
|
747
|
+
(LeptrisElement)n, "use");
|
|
449
748
|
d->required = (use && strcmp(use, "required") == 0);
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
else
|
|
453
|
-
head = d;
|
|
454
|
-
tail = d;
|
|
749
|
+
d->next = s->top_attrs;
|
|
750
|
+
s->top_attrs = d;
|
|
455
751
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
752
|
+
}
|
|
753
|
+
} else if (strcmp(local, "attributeGroup") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
754
|
+
const char* nm =
|
|
755
|
+
leptris_element_attribute((LeptrisElement)n, "name");
|
|
756
|
+
if (nm) {
|
|
757
|
+
XsdAttrGroupDef* g =
|
|
758
|
+
(XsdAttrGroupDef*)calloc(1, sizeof(*g));
|
|
759
|
+
if (g) {
|
|
760
|
+
g->name = xsd_strdup(nm);
|
|
761
|
+
g->attrs = xsd_capture_attr_rows(
|
|
762
|
+
s, (LeptrisElement)n, 0);
|
|
763
|
+
g->next = s->attr_groups;
|
|
764
|
+
s->attr_groups = g;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
} else if (strcmp(local, "group") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
768
|
+
const char* nm =
|
|
769
|
+
leptris_element_attribute((LeptrisElement)n, "name");
|
|
770
|
+
if (nm) {
|
|
771
|
+
XsdGroupDef* g = (XsdGroupDef*)calloc(1, sizeof(*g));
|
|
772
|
+
if (g) {
|
|
773
|
+
g->name = xsd_strdup(nm);
|
|
774
|
+
g->model = xsd_cm_parse(s, (LeptrisElement)n, NULL);
|
|
775
|
+
g->next = s->groups;
|
|
776
|
+
s->groups = g;
|
|
465
777
|
}
|
|
466
778
|
}
|
|
467
779
|
} else if (strcmp(local, "simpleType") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
@@ -472,16 +784,33 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile(const char* xsd_text,
|
|
|
472
784
|
}
|
|
473
785
|
}
|
|
474
786
|
}
|
|
787
|
+
}
|
|
475
788
|
|
|
476
|
-
|
|
477
|
-
return
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
789
|
+
static void xsd_free_simple_one(XsdSimple* t) {
|
|
790
|
+
if (!t) return;
|
|
791
|
+
free(t->name);
|
|
792
|
+
free(t->base);
|
|
793
|
+
free(t->pattern);
|
|
794
|
+
XsdFacetValue* fv = t->enum_values;
|
|
795
|
+
while (fv) {
|
|
796
|
+
XsdFacetValue* fn = fv->next;
|
|
797
|
+
free(fv->text);
|
|
798
|
+
free(fv);
|
|
799
|
+
fv = fn;
|
|
800
|
+
}
|
|
801
|
+
free(t->min_inclusive);
|
|
802
|
+
free(t->min_exclusive);
|
|
803
|
+
free(t->max_inclusive);
|
|
804
|
+
free(t->max_exclusive);
|
|
805
|
+
free(t->whitespace);
|
|
806
|
+
free(t->item_type);
|
|
807
|
+
xsd_free_simple_one(t->item_def);
|
|
808
|
+
for (size_t i = 0; i < t->member_count; i++) free(t->members[i]);
|
|
809
|
+
free(t->members);
|
|
810
|
+
for (size_t i = 0; i < t->member_def_count; i++)
|
|
811
|
+
xsd_free_simple_one(t->member_defs[i]);
|
|
812
|
+
free(t->member_defs);
|
|
813
|
+
free(t);
|
|
485
814
|
}
|
|
486
815
|
|
|
487
816
|
LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
@@ -514,6 +843,7 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
|
514
843
|
XsdAttrDecl* an = a->next;
|
|
515
844
|
free(a->name);
|
|
516
845
|
free(a->type);
|
|
846
|
+
free(a->fixed);
|
|
517
847
|
free(a);
|
|
518
848
|
a = an;
|
|
519
849
|
}
|
|
@@ -526,31 +856,52 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
|
526
856
|
XsdElementDecl* dn = d->next;
|
|
527
857
|
free(d->name);
|
|
528
858
|
free(d->type);
|
|
859
|
+
free(d->fixed);
|
|
860
|
+
free(d->sub_head);
|
|
529
861
|
free(d);
|
|
530
862
|
d = dn;
|
|
531
863
|
}
|
|
864
|
+
XsdAttrGroupDef* ag = s->attr_groups;
|
|
865
|
+
while (ag) {
|
|
866
|
+
XsdAttrGroupDef* agn = ag->next;
|
|
867
|
+
free(ag->name);
|
|
868
|
+
XsdAttrDecl* a = ag->attrs;
|
|
869
|
+
while (a) {
|
|
870
|
+
XsdAttrDecl* an2 = a->next;
|
|
871
|
+
free(a->name);
|
|
872
|
+
free(a->type);
|
|
873
|
+
free(a->fixed);
|
|
874
|
+
free(a);
|
|
875
|
+
a = an2;
|
|
876
|
+
}
|
|
877
|
+
free(ag);
|
|
878
|
+
ag = agn;
|
|
879
|
+
}
|
|
880
|
+
XsdAttrDecl* ta_row = s->top_attrs;
|
|
881
|
+
while (ta_row) {
|
|
882
|
+
XsdAttrDecl* ta_next = ta_row->next;
|
|
883
|
+
free(ta_row->name);
|
|
884
|
+
free(ta_row->type);
|
|
885
|
+
free(ta_row->fixed);
|
|
886
|
+
free(ta_row);
|
|
887
|
+
ta_row = ta_next;
|
|
888
|
+
}
|
|
889
|
+
XsdGroupDef* g = s->groups;
|
|
890
|
+
while (g) {
|
|
891
|
+
XsdGroupDef* gn = g->next;
|
|
892
|
+
free(g->name);
|
|
893
|
+
xsd_cm_free(g->model);
|
|
894
|
+
free(g);
|
|
895
|
+
g = gn;
|
|
896
|
+
}
|
|
532
897
|
free(s->target_ns);
|
|
898
|
+
free(s->base_dir);
|
|
533
899
|
if (s->validator)
|
|
534
900
|
xsd_validator_free((struct xsd_validator*)s->validator);
|
|
535
901
|
XsdSimple* t = s->simple_types;
|
|
536
902
|
while (t) {
|
|
537
903
|
XsdSimple* next = t->next;
|
|
538
|
-
|
|
539
|
-
free(t->base);
|
|
540
|
-
free(t->pattern);
|
|
541
|
-
XsdFacetValue* fv = t->enum_values;
|
|
542
|
-
while (fv) {
|
|
543
|
-
XsdFacetValue* fn = fv->next;
|
|
544
|
-
free(fv->text);
|
|
545
|
-
free(fv);
|
|
546
|
-
fv = fn;
|
|
547
|
-
}
|
|
548
|
-
free(t->min_inclusive);
|
|
549
|
-
free(t->min_exclusive);
|
|
550
|
-
free(t->max_inclusive);
|
|
551
|
-
free(t->max_exclusive);
|
|
552
|
-
free(t->whitespace);
|
|
553
|
-
free(t);
|
|
904
|
+
xsd_free_simple_one(t);
|
|
554
905
|
t = next;
|
|
555
906
|
}
|
|
556
907
|
free(s->error);
|
|
@@ -559,12 +910,376 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
|
559
910
|
|
|
560
911
|
/* ---- slice 2: lexical validation --------------------------------- */
|
|
561
912
|
|
|
913
|
+
static XsdCm* xsd_cm_copy_list(const XsdCm* head) {
|
|
914
|
+
XsdCm* out = NULL;
|
|
915
|
+
XsdCm* out_tail = NULL;
|
|
916
|
+
for (const XsdCm* src = head; src; src = src->next) {
|
|
917
|
+
XsdCm* d = (XsdCm*)calloc(1, sizeof(*d));
|
|
918
|
+
if (!d) break;
|
|
919
|
+
d->kind = src->kind;
|
|
920
|
+
d->name = xsd_strdup(src->name);
|
|
921
|
+
d->type = xsd_strdup(src->type);
|
|
922
|
+
d->ns = xsd_strdup(src->ns);
|
|
923
|
+
d->any_ns = xsd_strdup(src->any_ns);
|
|
924
|
+
d->process_skip = src->process_skip;
|
|
925
|
+
d->min = src->min;
|
|
926
|
+
d->max = src->max;
|
|
927
|
+
d->first_child = xsd_cm_copy_list(src->first_child);
|
|
928
|
+
if (out_tail)
|
|
929
|
+
out_tail->next = d;
|
|
930
|
+
else
|
|
931
|
+
out = d;
|
|
932
|
+
out_tail = d;
|
|
933
|
+
}
|
|
934
|
+
return out;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
static void xsd_register_complex(struct leptris_xsd_schema* s,
|
|
938
|
+
XsdCm* root, XsdAttrDecl* attrs,
|
|
939
|
+
const char* name) {
|
|
940
|
+
if (!root) return;
|
|
941
|
+
root->name = xsd_strdup(name);
|
|
942
|
+
root->next = s->complex_types;
|
|
943
|
+
s->complex_types = root;
|
|
944
|
+
if (attrs) {
|
|
945
|
+
XsdTypeAttrs* ta = (XsdTypeAttrs*)calloc(1, sizeof(*ta));
|
|
946
|
+
if (ta) {
|
|
947
|
+
ta->type_name = xsd_strdup(name);
|
|
948
|
+
ta->attrs = attrs;
|
|
949
|
+
ta->next = s->type_attrs;
|
|
950
|
+
s->type_attrs = ta;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/* One complexType capture, shared by top-level declarations and
|
|
956
|
+
* inline anonymous types: content model + derivation
|
|
957
|
+
* (complexContent/simpleContent extension|restriction) + the
|
|
958
|
+
* attribute rows the derivation carries. */
|
|
959
|
+
static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
960
|
+
LeptrisElement ct,
|
|
961
|
+
const char* name) {
|
|
962
|
+
XsdCm* root = xsd_cm_new(XSD_CM_SEQ); /* wrapper keeps the name */
|
|
963
|
+
if (!root) return NULL;
|
|
964
|
+
XsdAttrDecl* attrs = NULL;
|
|
965
|
+
|
|
966
|
+
for (LeptrisNodeRef n =
|
|
967
|
+
leptris_node_first_child(leptris_element_as_node(ct));
|
|
968
|
+
n; n = leptris_node_next_sibling(n)) {
|
|
969
|
+
if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
970
|
+
continue;
|
|
971
|
+
LeptrisElement e = (LeptrisElement)n;
|
|
972
|
+
const char* local = NULL, *prefix = NULL, *uri = NULL;
|
|
973
|
+
leptris_element_expanded_name(e, &local, &prefix, &uri);
|
|
974
|
+
if (!local || !uri || strcmp(uri, XSD_NS) != 0) continue;
|
|
975
|
+
|
|
976
|
+
if (strcmp(local, "complexContent") == 0) {
|
|
977
|
+
/* extension|restriction child carries base + model */
|
|
978
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
979
|
+
leptris_element_as_node(e));
|
|
980
|
+
q; q = leptris_node_next_sibling(q)) {
|
|
981
|
+
if (leptris_node_get_type(q) !=
|
|
982
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
983
|
+
continue;
|
|
984
|
+
LeptrisElement dq = (LeptrisElement)q;
|
|
985
|
+
const char* dl = NULL;
|
|
986
|
+
leptris_element_expanded_name(dq, &dl, NULL, NULL);
|
|
987
|
+
if (!dl || (strcmp(dl, "extension") != 0 &&
|
|
988
|
+
strcmp(dl, "restriction") != 0))
|
|
989
|
+
continue;
|
|
990
|
+
const char* base =
|
|
991
|
+
leptris_element_attribute(dq, "base");
|
|
992
|
+
XsdCm* base_root =
|
|
993
|
+
(base && strncmp(base, "xs:", 3) != 0)
|
|
994
|
+
? xsd_find_complex(s, base)
|
|
995
|
+
: NULL;
|
|
996
|
+
if (strcmp(dl, "extension") == 0) {
|
|
997
|
+
/* base content first, derived content after */
|
|
998
|
+
root->first_child = xsd_cm_copy_list(
|
|
999
|
+
base_root ? base_root->first_child : NULL);
|
|
1000
|
+
XsdCm* own_tail = root->first_child;
|
|
1001
|
+
while (own_tail && own_tail->next)
|
|
1002
|
+
own_tail = own_tail->next;
|
|
1003
|
+
XsdCm* own = xsd_cm_parse(s, dq, NULL);
|
|
1004
|
+
if (own_tail)
|
|
1005
|
+
own_tail->next = own;
|
|
1006
|
+
else if (!root->first_child)
|
|
1007
|
+
root->first_child = own;
|
|
1008
|
+
if (base_root) {
|
|
1009
|
+
const XsdTypeAttrs* bt = xsd_find_type_attrs(
|
|
1010
|
+
s, base);
|
|
1011
|
+
attrs = xsd_copy_attr_rows(bt ? bt->attrs
|
|
1012
|
+
: NULL);
|
|
1013
|
+
}
|
|
1014
|
+
XsdAttrDecl* own_attrs =
|
|
1015
|
+
xsd_capture_attr_rows(s, dq, 0);
|
|
1016
|
+
if (own_attrs) {
|
|
1017
|
+
XsdAttrDecl* at = attrs;
|
|
1018
|
+
while (at && at->next) at = at->next;
|
|
1019
|
+
if (at)
|
|
1020
|
+
at->next = own_attrs;
|
|
1021
|
+
else
|
|
1022
|
+
attrs = own_attrs;
|
|
1023
|
+
}
|
|
1024
|
+
} else {
|
|
1025
|
+
/* restriction: the derived model REPLACES */
|
|
1026
|
+
root->first_child = xsd_cm_parse(s, dq, NULL);
|
|
1027
|
+
attrs = xsd_capture_attr_rows(s, dq, 0);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
} else if (strcmp(local, "simpleContent") == 0) {
|
|
1031
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
1032
|
+
leptris_element_as_node(e));
|
|
1033
|
+
q; q = leptris_node_next_sibling(q)) {
|
|
1034
|
+
if (leptris_node_get_type(q) !=
|
|
1035
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1036
|
+
continue;
|
|
1037
|
+
LeptrisElement dq = (LeptrisElement)q;
|
|
1038
|
+
const char* dl = NULL;
|
|
1039
|
+
leptris_element_expanded_name(dq, &dl, NULL, NULL);
|
|
1040
|
+
if (!dl || (strcmp(dl, "extension") != 0 &&
|
|
1041
|
+
strcmp(dl, "restriction") != 0))
|
|
1042
|
+
continue;
|
|
1043
|
+
const char* base =
|
|
1044
|
+
leptris_element_attribute(dq, "base");
|
|
1045
|
+
if (base) {
|
|
1046
|
+
if (strncmp(base, "xs:", 3) == 0) {
|
|
1047
|
+
root->text_type = xsd_strdup(base);
|
|
1048
|
+
} else {
|
|
1049
|
+
/* restriction facets under a local base
|
|
1050
|
+
* ride a synthesized "complex:NAME" slot */
|
|
1051
|
+
int has_facets = 0;
|
|
1052
|
+
for (LeptrisNodeRef f =
|
|
1053
|
+
leptris_node_first_child(
|
|
1054
|
+
leptris_element_as_node(dq));
|
|
1055
|
+
f; f = leptris_node_next_sibling(f)) {
|
|
1056
|
+
if (leptris_node_get_type(f) !=
|
|
1057
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1058
|
+
continue;
|
|
1059
|
+
const char* fl = NULL;
|
|
1060
|
+
leptris_element_expanded_name(
|
|
1061
|
+
(LeptrisElement)f, &fl, NULL, NULL);
|
|
1062
|
+
if (fl && strcmp(fl, "facet") != 0 &&
|
|
1063
|
+
strcmp(fl, "simpleType") != 0)
|
|
1064
|
+
has_facets = 1;
|
|
1065
|
+
}
|
|
1066
|
+
XsdSimple* captured =
|
|
1067
|
+
has_facets
|
|
1068
|
+
? xsd_capture_simple(dq)
|
|
1069
|
+
: NULL;
|
|
1070
|
+
if (captured) {
|
|
1071
|
+
char synth[512];
|
|
1072
|
+
snprintf(synth, sizeof(synth),
|
|
1073
|
+
"complex:%s", name);
|
|
1074
|
+
free(captured->name);
|
|
1075
|
+
captured->name = xsd_strdup(synth);
|
|
1076
|
+
captured->next = s->simple_types;
|
|
1077
|
+
s->simple_types = captured;
|
|
1078
|
+
root->text_type = xsd_strdup(synth);
|
|
1079
|
+
} else {
|
|
1080
|
+
root->text_type = xsd_strdup(base);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
attrs = xsd_capture_attr_rows(s, dq, 0);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (!root->first_child && !root->text_type) {
|
|
1089
|
+
/* no derivation: the direct-content spelling. A derivation
|
|
1090
|
+
* that captured attributes but produced no element model
|
|
1091
|
+
* (e.g. an attributes-only restriction) already set them —
|
|
1092
|
+
* re-capturing would orphan those rows. */
|
|
1093
|
+
root->first_child = xsd_cm_parse(s, ct, NULL);
|
|
1094
|
+
if (!attrs) attrs = xsd_capture_attr_rows(s, ct, 0);
|
|
1095
|
+
}
|
|
1096
|
+
/* the NFA and model walkers consume ONE root particle —
|
|
1097
|
+
* a multi-particle model (derivation splices) normalizes
|
|
1098
|
+
* under a sequence */
|
|
1099
|
+
if (root->first_child && root->first_child->next) {
|
|
1100
|
+
XsdCm* seq = xsd_cm_new(XSD_CM_SEQ);
|
|
1101
|
+
if (seq) {
|
|
1102
|
+
seq->first_child = root->first_child;
|
|
1103
|
+
root->first_child = seq;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
xsd_register_complex(s, root, attrs, name);
|
|
1107
|
+
return root;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
static const XsdElementDecl* xsd_find_element_decl(
|
|
1111
|
+
struct leptris_xsd_schema* s, const char* name) {
|
|
1112
|
+
for (XsdElementDecl* d = s->elements; d; d = d->next)
|
|
1113
|
+
if (strcmp(d->name, name) == 0) return d;
|
|
1114
|
+
return NULL;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
int xsd_is_substitute(struct leptris_xsd_schema* s,
|
|
1118
|
+
const char* name, const char* head) {
|
|
1119
|
+
const XsdElementDecl* d = xsd_find_element_decl(s, name);
|
|
1120
|
+
for (int hops = 0; d && d->sub_head && hops < 16; hops++) {
|
|
1121
|
+
if (strcmp(d->sub_head, head) == 0) return 1;
|
|
1122
|
+
d = xsd_find_element_decl(s, d->sub_head);
|
|
1123
|
+
}
|
|
1124
|
+
return 0;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
XsdGroupDef* xsd_find_group(struct leptris_xsd_schema* s,
|
|
1128
|
+
const char* name) {
|
|
1129
|
+
if (!s || !name) return NULL;
|
|
1130
|
+
for (XsdGroupDef* g = s->groups; g; g = g->next)
|
|
1131
|
+
if (strcmp(g->name, name) == 0) return g;
|
|
1132
|
+
return NULL;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
static const XsdAttrDecl* xsd_find_top_attr(
|
|
1136
|
+
struct leptris_xsd_schema* s, const char* name) {
|
|
1137
|
+
if (!s || !name) return NULL;
|
|
1138
|
+
for (XsdAttrDecl* a = s->top_attrs; a; a = a->next)
|
|
1139
|
+
if (strcmp(a->name, name) == 0) return a;
|
|
1140
|
+
return NULL;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/* Deep-copy a captured row chain (attributeGroup refs splice
|
|
1144
|
+
* copies — every referencing type owns its rows). */
|
|
1145
|
+
static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src) {
|
|
1146
|
+
XsdAttrDecl* head = NULL;
|
|
1147
|
+
XsdAttrDecl* tail = NULL;
|
|
1148
|
+
for (; src; src = src->next) {
|
|
1149
|
+
XsdAttrDecl* d = (XsdAttrDecl*)calloc(1, sizeof(*d));
|
|
1150
|
+
if (!d) break;
|
|
1151
|
+
d->name = xsd_strdup(src->name);
|
|
1152
|
+
d->type = xsd_strdup(src->type);
|
|
1153
|
+
d->fixed = xsd_strdup(src->fixed);
|
|
1154
|
+
d->required = src->required;
|
|
1155
|
+
if (tail)
|
|
1156
|
+
tail->next = d;
|
|
1157
|
+
else
|
|
1158
|
+
head = d;
|
|
1159
|
+
tail = d;
|
|
1160
|
+
}
|
|
1161
|
+
return head;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/* Capture the attribute rows of a complexType or attributeGroup:
|
|
1165
|
+
* named rows, inline anonymous simpleTypes (synthesized slots),
|
|
1166
|
+
* refs to top-level attributes, and attributeGroup refs. */
|
|
1167
|
+
/* Named row with an inline anonymous simpleType rides a
|
|
1168
|
+
* synthesized "attribute:NAME" slot, the element-slot pattern. */
|
|
1169
|
+
static const char* xsd_inline_attr_type(
|
|
1170
|
+
struct leptris_xsd_schema* s, LeptrisElement ae,
|
|
1171
|
+
const char* attr_name) {
|
|
1172
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
1173
|
+
leptris_element_as_node(ae));
|
|
1174
|
+
q; q = leptris_node_next_sibling(q)) {
|
|
1175
|
+
if (leptris_node_get_type(q) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1176
|
+
continue;
|
|
1177
|
+
LeptrisElement qe = (LeptrisElement)q;
|
|
1178
|
+
const char* ql = NULL;
|
|
1179
|
+
leptris_element_expanded_name(qe, &ql, NULL, NULL);
|
|
1180
|
+
if (!ql || strcmp(ql, "simpleType") != 0) continue;
|
|
1181
|
+
char synth[512];
|
|
1182
|
+
snprintf(synth, sizeof(synth), "attribute:%s", attr_name);
|
|
1183
|
+
XsdSimple* captured = xsd_capture_simple(qe);
|
|
1184
|
+
if (!captured) return NULL;
|
|
1185
|
+
free(captured->name);
|
|
1186
|
+
captured->name = xsd_strdup(synth);
|
|
1187
|
+
captured->next = s->simple_types;
|
|
1188
|
+
s->simple_types = captured;
|
|
1189
|
+
return captured->name;
|
|
1190
|
+
}
|
|
1191
|
+
return NULL;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
static XsdAttrDecl* xsd_capture_attr_rows(struct leptris_xsd_schema* s,
|
|
1195
|
+
LeptrisElement container,
|
|
1196
|
+
int depth) {
|
|
1197
|
+
XsdAttrDecl* head = NULL;
|
|
1198
|
+
XsdAttrDecl* tail = NULL;
|
|
1199
|
+
if (depth > 8) return NULL;
|
|
1200
|
+
for (LeptrisNodeRef ac = leptris_node_first_child(
|
|
1201
|
+
leptris_element_as_node(container));
|
|
1202
|
+
ac; ac = leptris_node_next_sibling(ac)) {
|
|
1203
|
+
if (leptris_node_get_type(ac) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1204
|
+
continue;
|
|
1205
|
+
LeptrisElement ae = (LeptrisElement)ac;
|
|
1206
|
+
const char* al = NULL, *ap = NULL, *au = NULL;
|
|
1207
|
+
leptris_element_expanded_name(ae, &al, &ap, &au);
|
|
1208
|
+
if (!al || (au && strcmp(au, XSD_NS) != 0)) continue;
|
|
1209
|
+
|
|
1210
|
+
if (strcmp(al, "attribute") == 0) {
|
|
1211
|
+
const char* an = leptris_element_attribute(ae, "name");
|
|
1212
|
+
const char* use = leptris_element_attribute(ae, "use");
|
|
1213
|
+
XsdAttrDecl* d = (XsdAttrDecl*)calloc(1, sizeof(*d));
|
|
1214
|
+
if (!d) continue;
|
|
1215
|
+
if (an) {
|
|
1216
|
+
d->name = xsd_strdup(an);
|
|
1217
|
+
d->type = xsd_strdup(
|
|
1218
|
+
leptris_element_attribute(ae, "type"));
|
|
1219
|
+
if (!d->type)
|
|
1220
|
+
d->type = xsd_strdup(
|
|
1221
|
+
xsd_inline_attr_type(s, ae, an));
|
|
1222
|
+
d->fixed = xsd_strdup(
|
|
1223
|
+
leptris_element_attribute(ae, "fixed"));
|
|
1224
|
+
d->required = (use && strcmp(use, "required") == 0);
|
|
1225
|
+
} else {
|
|
1226
|
+
/* ref to a top-level attribute declaration */
|
|
1227
|
+
const char* ref =
|
|
1228
|
+
leptris_element_attribute(ae, "ref");
|
|
1229
|
+
const XsdAttrDecl* src =
|
|
1230
|
+
ref ? xsd_find_top_attr(s, ref) : NULL;
|
|
1231
|
+
if (!src) {
|
|
1232
|
+
free(d);
|
|
1233
|
+
continue;
|
|
1234
|
+
}
|
|
1235
|
+
d->name = xsd_strdup(src->name);
|
|
1236
|
+
d->type = xsd_strdup(src->type);
|
|
1237
|
+
d->fixed = xsd_strdup(src->fixed);
|
|
1238
|
+
d->required = use
|
|
1239
|
+
? (strcmp(use, "required") == 0)
|
|
1240
|
+
: src->required;
|
|
1241
|
+
}
|
|
1242
|
+
if (tail)
|
|
1243
|
+
tail->next = d;
|
|
1244
|
+
else
|
|
1245
|
+
head = d;
|
|
1246
|
+
tail = d;
|
|
1247
|
+
} else if (strcmp(al, "attributeGroup") == 0) {
|
|
1248
|
+
const char* ref =
|
|
1249
|
+
leptris_element_attribute(ae, "ref");
|
|
1250
|
+
if (!ref) continue;
|
|
1251
|
+
XsdAttrGroupDef* g = s->attr_groups;
|
|
1252
|
+
for (; g; g = g->next)
|
|
1253
|
+
if (strcmp(g->name, ref) == 0) break;
|
|
1254
|
+
if (!g || !g->attrs) continue;
|
|
1255
|
+
XsdAttrDecl* copied = xsd_copy_attr_rows(g->attrs);
|
|
1256
|
+
if (!copied) continue;
|
|
1257
|
+
if (!head)
|
|
1258
|
+
head = copied;
|
|
1259
|
+
else
|
|
1260
|
+
tail->next = copied;
|
|
1261
|
+
tail = copied;
|
|
1262
|
+
while (tail->next) tail = tail->next;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return head;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
562
1268
|
LEPTRIS_API int leptris_xsd_builtin_valid(const char* builtin,
|
|
563
1269
|
const char* lexical) {
|
|
564
1270
|
extern int xsd_builtin_valid(const char* type, const char* v);
|
|
565
1271
|
return xsd_builtin_valid(builtin, lexical);
|
|
566
1272
|
}
|
|
567
1273
|
|
|
1274
|
+
/* The instance validator routes every user simpleType through the
|
|
1275
|
+
* chain walker so list/union derivations dispatch with the schema
|
|
1276
|
+
* in hand (the bare xsd_simple_valid cannot resolve item/member
|
|
1277
|
+
* names). */
|
|
1278
|
+
int xsd_simple_valid_chain(struct leptris_xsd_schema* s,
|
|
1279
|
+
const XsdSimple* t, const char* v) {
|
|
1280
|
+
return xsd_valid_chain(s, t, v, 0);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
568
1283
|
LEPTRIS_API int leptris_xsd_simple_valid(LeptrisXsdSchema schema,
|
|
569
1284
|
const char* type_name,
|
|
570
1285
|
const char* lexical) {
|