teptris 0.3.22.0 → 0.3.23.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.
- checksums.yaml +4 -4
- data/ext/teptris_ext/engine/README.md +1 -1
- data/ext/teptris_ext/engine/src/include/teptris/schema.h +7 -0
- data/ext/teptris_ext/engine/src/include/teptris/version.h +2 -2
- data/ext/teptris_ext/engine/src/teptris/schema/metaschemas.c +243 -0
- data/ext/teptris_ext/engine/src/teptris/schema/metaschemas.h +15 -0
- data/ext/teptris_ext/engine/src/teptris/schema/refs.c +243 -0
- data/ext/teptris_ext/engine/src/teptris/schema/refs.h +24 -0
- data/ext/teptris_ext/engine/src/teptris/schema/schema.c +779 -40
- data/ext/teptris_ext/engine/src/teptris/schema/schema_internal.h +76 -6
- data/ext/teptris_ext/engine/src/teptris/schema/validate.c +87 -11
- data/lib/teptris/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a15759fbe1769570b78923b39bb95576a8d42fed349e61fde761085dcf0c7b85
|
|
4
|
+
data.tar.gz: 2622149afc41e720402bfbbba2f1f85499ec887e44ab6fa2f7604f27cb6db50c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b32e4a4e8165a739221d26b2904593be57b9c6b12d55f4a29d5ff10ede9becfb2c7dca61e8b70e6374acb859b972812b1d21bf17ff46c0216c3c048fc33187e
|
|
7
|
+
data.tar.gz: 83a570f3731f22e40570200251d4daae427e3a39c74ef96cb8259b0a5a9247ef810bab18638b59ae0f2711fb2bfdc38d0cad37afdf0ca3cdcaa240d76b08a500
|
|
@@ -74,6 +74,13 @@ typedef struct teptris_schema teptris_schema;
|
|
|
74
74
|
* {"error": "...", "path": "..."} locating the problem; free it with
|
|
75
75
|
* teptris_diag_free. Either out or diag_buf may be NULL if the caller
|
|
76
76
|
* does not want it. */
|
|
77
|
+
/* compile with a base directory: relative $refs and $ids in the
|
|
78
|
+
* schema resolve against files under it (local files only - the
|
|
79
|
+
* library never touches the network). compile() is compile_ex(NULL). */
|
|
80
|
+
TEPTRIS_API teptris_status teptris_schema_compile_ex(
|
|
81
|
+
const char *json, size_t len, const char *base_dir, size_t base_len,
|
|
82
|
+
struct teptris_schema **out, char **diag_buf, size_t *diag_len);
|
|
83
|
+
|
|
77
84
|
TEPTRIS_API teptris_status teptris_schema_compile(const char *json, size_t len,
|
|
78
85
|
teptris_schema **out,
|
|
79
86
|
char **diag_buf,
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/* The official JSON Schema metaschemas, vendored as built-in
|
|
2
|
+
* resources: a parser library never touches the network, but the
|
|
3
|
+
* metaschemas are part of the dialect itself. Provenance: the
|
|
4
|
+
* published drafts (draft-07, 2019-09, 2020-12) as shipped by the
|
|
5
|
+
* jsonschema crate v0.60.2 vendored copy; regenerated by
|
|
6
|
+
* scripts/gen_metaschemas.py - edit the script, not this file. */
|
|
7
|
+
#include "metaschemas.h"
|
|
8
|
+
|
|
9
|
+
const struct teptris_builtin_resource teptris_builtin_resources[] = {
|
|
10
|
+
{"http://json-schema.org/draft-07/schema",
|
|
11
|
+
"{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"$id\":\"http://json-schema.org/draft-07/schema#\",\"title\":"
|
|
12
|
+
"\"Core schema meta-schema\",\"definitions\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#"
|
|
13
|
+
"\"}},\"nonNegativeInteger\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"allOf\":[{\"$ref\":\""
|
|
14
|
+
"#/definitions/nonNegativeInteger\"},{\"default\":0}]},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"nul"
|
|
15
|
+
"l\",\"number\",\"object\",\"string\"]},\"stringArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems"
|
|
16
|
+
"\":true,\"default\":[]}},\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"type\":\"string\",\"format\":\"uri"
|
|
17
|
+
"-reference\"},\"$schema\":{\"type\":\"string\",\"format\":\"uri\"},\"$ref\":{\"type\":\"string\",\"format\":\"uri-refere"
|
|
18
|
+
"nce\"},\"$comment\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"defaul"
|
|
19
|
+
"t\":true,\"readOnly\":{\"type\":\"boolean\",\"default\":false},\"writeOnly\":{\"type\":\"boolean\",\"default\":false},\""
|
|
20
|
+
"examples\":{\"type\":\"array\",\"items\":true},\"multipleOf\":{\"type\":\"number\",\"exclusiveMinimum\":0},\"maximum\":{"
|
|
21
|
+
"\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimum\":{\"type\":\"number\"},\"exclusiveMinimum\":{"
|
|
22
|
+
"\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minLength\":{\"$ref\":\"#/definitio"
|
|
23
|
+
"ns/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"additionalItems\":{\"$ref\":\""
|
|
24
|
+
"#\"},\"items\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/schemaArray\"}],\"default\":true},\"maxItems\":{\""
|
|
25
|
+
"$ref\":\"#/definitions/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"uniq"
|
|
26
|
+
"ueItems\":{\"type\":\"boolean\",\"default\":false},\"contains\":{\"$ref\":\"#\"},\"maxProperties\":{\"$ref\":\"#/definit"
|
|
27
|
+
"ions/nonNegativeInteger\"},\"minProperties\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"required\":{\"$re"
|
|
28
|
+
"f\":\"#/definitions/stringArray\"},\"additionalProperties\":{\"$ref\":\"#\"},\"definitions\":{\"type\":\"object\",\"addi"
|
|
29
|
+
"tionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref"
|
|
30
|
+
"\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"propert"
|
|
31
|
+
"yNames\":{\"format\":\"regex\"},\"default\":{}},\"dependencies\":{\"type\":\"object\",\"additionalProperties\":{\"anyOf"
|
|
32
|
+
"\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/stringArray\"}]}},\"propertyNames\":{\"$ref\":\"#\"},\"const\":true,\"enu"
|
|
33
|
+
"m\":{\"type\":\"array\",\"items\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/definitions/simpleTypes\"},{\"type\":\"array"
|
|
34
|
+
"\",\"items\":{\"$ref\":\"#/definitions/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]},\"format\":{\"type\":\"stri"
|
|
35
|
+
"ng\"},\"contentMediaType\":{\"type\":\"string\"},\"contentEncoding\":{\"type\":\"string\"},\"if\":{\"$ref\":\"#\"},\"the"
|
|
36
|
+
"n\":{\"$ref\":\"#\"},\"else\":{\"$ref\":\"#\"},\"allOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"anyOf\":{\"$ref\":\""
|
|
37
|
+
"#/definitions/schemaArray\"},\"oneOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"not\":{\"$ref\":\"#\"}},\"default\":tr"
|
|
38
|
+
"ue}"
|
|
39
|
+
},
|
|
40
|
+
{"https://json-schema.org/draft-07/schema",
|
|
41
|
+
"{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"$id\":\"http://json-schema.org/draft-07/schema#\",\"title\":"
|
|
42
|
+
"\"Core schema meta-schema\",\"definitions\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#"
|
|
43
|
+
"\"}},\"nonNegativeInteger\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"allOf\":[{\"$ref\":\""
|
|
44
|
+
"#/definitions/nonNegativeInteger\"},{\"default\":0}]},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"nul"
|
|
45
|
+
"l\",\"number\",\"object\",\"string\"]},\"stringArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems"
|
|
46
|
+
"\":true,\"default\":[]}},\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"type\":\"string\",\"format\":\"uri"
|
|
47
|
+
"-reference\"},\"$schema\":{\"type\":\"string\",\"format\":\"uri\"},\"$ref\":{\"type\":\"string\",\"format\":\"uri-refere"
|
|
48
|
+
"nce\"},\"$comment\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"defaul"
|
|
49
|
+
"t\":true,\"readOnly\":{\"type\":\"boolean\",\"default\":false},\"writeOnly\":{\"type\":\"boolean\",\"default\":false},\""
|
|
50
|
+
"examples\":{\"type\":\"array\",\"items\":true},\"multipleOf\":{\"type\":\"number\",\"exclusiveMinimum\":0},\"maximum\":{"
|
|
51
|
+
"\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimum\":{\"type\":\"number\"},\"exclusiveMinimum\":{"
|
|
52
|
+
"\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minLength\":{\"$ref\":\"#/definitio"
|
|
53
|
+
"ns/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"additionalItems\":{\"$ref\":\""
|
|
54
|
+
"#\"},\"items\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/schemaArray\"}],\"default\":true},\"maxItems\":{\""
|
|
55
|
+
"$ref\":\"#/definitions/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"uniq"
|
|
56
|
+
"ueItems\":{\"type\":\"boolean\",\"default\":false},\"contains\":{\"$ref\":\"#\"},\"maxProperties\":{\"$ref\":\"#/definit"
|
|
57
|
+
"ions/nonNegativeInteger\"},\"minProperties\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"required\":{\"$re"
|
|
58
|
+
"f\":\"#/definitions/stringArray\"},\"additionalProperties\":{\"$ref\":\"#\"},\"definitions\":{\"type\":\"object\",\"addi"
|
|
59
|
+
"tionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref"
|
|
60
|
+
"\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"propert"
|
|
61
|
+
"yNames\":{\"format\":\"regex\"},\"default\":{}},\"dependencies\":{\"type\":\"object\",\"additionalProperties\":{\"anyOf"
|
|
62
|
+
"\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/stringArray\"}]}},\"propertyNames\":{\"$ref\":\"#\"},\"const\":true,\"enu"
|
|
63
|
+
"m\":{\"type\":\"array\",\"items\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/definitions/simpleTypes\"},{\"type\":\"array"
|
|
64
|
+
"\",\"items\":{\"$ref\":\"#/definitions/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]},\"format\":{\"type\":\"stri"
|
|
65
|
+
"ng\"},\"contentMediaType\":{\"type\":\"string\"},\"contentEncoding\":{\"type\":\"string\"},\"if\":{\"$ref\":\"#\"},\"the"
|
|
66
|
+
"n\":{\"$ref\":\"#\"},\"else\":{\"$ref\":\"#\"},\"allOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"anyOf\":{\"$ref\":\""
|
|
67
|
+
"#/definitions/schemaArray\"},\"oneOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"not\":{\"$ref\":\"#\"}},\"default\":tr"
|
|
68
|
+
"ue}"
|
|
69
|
+
},
|
|
70
|
+
{"https://json-schema.org/draft/2019-09/schema",
|
|
71
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/schema\","
|
|
72
|
+
"\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/core\":true,\"https://json-schema.org/draft/2019-09/vocab"
|
|
73
|
+
"/applicator\":true,\"https://json-schema.org/draft/2019-09/vocab/validation\":true,\"https://json-schema.org/draft/2019-"
|
|
74
|
+
"09/vocab/meta-data\":true,\"https://json-schema.org/draft/2019-09/vocab/format\":false,\"https://json-schema.org/draft/2"
|
|
75
|
+
"019-09/vocab/content\":true},\"$recursiveAnchor\":true,\"title\":\"Core and Validation specifications meta-schema\",\"al"
|
|
76
|
+
"lOf\":[{\"$ref\":\"meta/core\"},{\"$ref\":\"meta/applicator\"},{\"$ref\":\"meta/validation\"},{\"$ref\":\"meta/meta-data"
|
|
77
|
+
"\"},{\"$ref\":\"meta/format\"},{\"$ref\":\"meta/content\"}],\"type\":[\"object\",\"boolean\"],\"properties\":{\"definiti"
|
|
78
|
+
"ons\":{\"$comment\":\"While no longer an official keyword as it is replaced by $defs, this keyword is retained in the me"
|
|
79
|
+
"ta-schema to prevent incompatible extensions as it remains in common use.\",\"type\":\"object\",\"additionalProperties\""
|
|
80
|
+
":{\"$recursiveRef\":\"#\"},\"default\":{}},\"dependencies\":{\"$comment\":\"\\\"dependencies\\\" is no longer a keyword,"
|
|
81
|
+
" but schema authors should avoid redefining it to facilitate a smooth transition to \\\"dependentSchemas\\\" and \\\"dep"
|
|
82
|
+
"endentRequired\\\"\",\"type\":\"object\",\"additionalProperties\":{\"anyOf\":[{\"$recursiveRef\":\"#\"},{\"$ref\":\"meta"
|
|
83
|
+
"/validation#/$defs/stringArray\"}]}}}}"
|
|
84
|
+
},
|
|
85
|
+
{"https://json-schema.org/draft/2019-09/meta/core",
|
|
86
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/core"
|
|
87
|
+
"\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/core\":true},\"$recursiveAnchor\":true,\"title\":\"Cor"
|
|
88
|
+
"e vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"type\":\"string\",\"format\":\"u"
|
|
89
|
+
"ri-reference\",\"$comment\":\"Non-empty fragments not allowed.\",\"pattern\":\"^[^#]*#?$\"},\"$schema\":{\"type\":\"stri"
|
|
90
|
+
"ng\",\"format\":\"uri\"},\"$anchor\":{\"type\":\"string\",\"pattern\":\"^[A-Za-z][-A-Za-z0-9.:_]*$\"},\"$ref\":{\"type\""
|
|
91
|
+
":\"string\",\"format\":\"uri-reference\"},\"$recursiveRef\":{\"type\":\"string\",\"format\":\"uri-reference\"},\"$recurs"
|
|
92
|
+
"iveAnchor\":{\"type\":\"boolean\",\"default\":false},\"$vocabulary\":{\"type\":\"object\",\"propertyNames\":{\"type\":\""
|
|
93
|
+
"string\",\"format\":\"uri\"},\"additionalProperties\":{\"type\":\"boolean\"}},\"$comment\":{\"type\":\"string\"},\"$defs"
|
|
94
|
+
"\":{\"type\":\"object\",\"additionalProperties\":{\"$recursiveRef\":\"#\"},\"default\":{}}}}"
|
|
95
|
+
},
|
|
96
|
+
{"https://json-schema.org/draft/2019-09/meta/applicator",
|
|
97
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/appli"
|
|
98
|
+
"cator\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/applicator\":true},\"$recursiveAnchor\":true,\"ti"
|
|
99
|
+
"tle\":\"Applicator vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"additionalItems\":{\"$re"
|
|
100
|
+
"cursiveRef\":\"#\"},\"unevaluatedItems\":{\"$recursiveRef\":\"#\"},\"items\":{\"anyOf\":[{\"$recursiveRef\":\"#\"},{\"$r"
|
|
101
|
+
"ef\":\"#/$defs/schemaArray\"}]},\"contains\":{\"$recursiveRef\":\"#\"},\"additionalProperties\":{\"$recursiveRef\":\"#\""
|
|
102
|
+
"},\"unevaluatedProperties\":{\"$recursiveRef\":\"#\"},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$r"
|
|
103
|
+
"ecursiveRef\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$recursiveRe"
|
|
104
|
+
"f\":\"#\"},\"propertyNames\":{\"format\":\"regex\"},\"default\":{}},\"dependentSchemas\":{\"type\":\"object\",\"addition"
|
|
105
|
+
"alProperties\":{\"$recursiveRef\":\"#\"}},\"propertyNames\":{\"$recursiveRef\":\"#\"},\"if\":{\"$recursiveRef\":\"#\"},"
|
|
106
|
+
"\"then\":{\"$recursiveRef\":\"#\"},\"else\":{\"$recursiveRef\":\"#\"},\"allOf\":{\"$ref\":\"#/$defs/schemaArray\"},\"any"
|
|
107
|
+
"Of\":{\"$ref\":\"#/$defs/schemaArray\"},\"oneOf\":{\"$ref\":\"#/$defs/schemaArray\"},\"not\":{\"$recursiveRef\":\"#\"}},"
|
|
108
|
+
"\"$defs\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$recursiveRef\":\"#\"}}}}"
|
|
109
|
+
},
|
|
110
|
+
{"https://json-schema.org/draft/2019-09/meta/validation",
|
|
111
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/valid"
|
|
112
|
+
"ation\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/validation\":true},\"$recursiveAnchor\":true,\"ti"
|
|
113
|
+
"tle\":\"Validation vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"multipleOf\":{\"type\":"
|
|
114
|
+
"\"number\",\"exclusiveMinimum\":0},\"maximum\":{\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimu"
|
|
115
|
+
"m\":{\"type\":\"number\"},\"exclusiveMinimum\":{\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/$defs/nonNegativeIntege"
|
|
116
|
+
"r\"},\"minLength\":{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex"
|
|
117
|
+
"\"},\"maxItems\":{\"$ref\":\"#/$defs/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\""
|
|
118
|
+
"},\"uniqueItems\":{\"type\":\"boolean\",\"default\":false},\"maxContains\":{\"$ref\":\"#/$defs/nonNegativeInteger\"},\"m"
|
|
119
|
+
"inContains\":{\"$ref\":\"#/$defs/nonNegativeInteger\",\"default\":1},\"maxProperties\":{\"$ref\":\"#/$defs/nonNegativeIn"
|
|
120
|
+
"teger\"},\"minProperties\":{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\"},\"required\":{\"$ref\":\"#/$defs/stringArra"
|
|
121
|
+
"y\"},\"dependentRequired\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#/$defs/stringArray\"}},\"const\":t"
|
|
122
|
+
"rue,\"enum\":{\"type\":\"array\",\"items\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/$defs/simpleTypes\"},{\"type\":\"arr"
|
|
123
|
+
"ay\",\"items\":{\"$ref\":\"#/$defs/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]}},\"$defs\":{\"nonNegativeIntege"
|
|
124
|
+
"r\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"$ref\":\"#/$defs/nonNegativeInteger\",\"defau"
|
|
125
|
+
"lt\":0},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]},\"strin"
|
|
126
|
+
"gArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true,\"default\":[]}}}"
|
|
127
|
+
},
|
|
128
|
+
{"https://json-schema.org/draft/2019-09/meta/meta-data",
|
|
129
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/meta-"
|
|
130
|
+
"data\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/meta-data\":true},\"$recursiveAnchor\":true,\"titl"
|
|
131
|
+
"e\":\"Meta-data vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"title\":{\"type\":\"string"
|
|
132
|
+
"\"},\"description\":{\"type\":\"string\"},\"default\":true,\"deprecated\":{\"type\":\"boolean\",\"default\":false},\"rea"
|
|
133
|
+
"dOnly\":{\"type\":\"boolean\",\"default\":false},\"writeOnly\":{\"type\":\"boolean\",\"default\":false},\"examples\":{\""
|
|
134
|
+
"type\":\"array\",\"items\":true}}}"
|
|
135
|
+
},
|
|
136
|
+
{"https://json-schema.org/draft/2019-09/meta/content",
|
|
137
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/conte"
|
|
138
|
+
"nt\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/content\":true},\"$recursiveAnchor\":true,\"title\":"
|
|
139
|
+
"\"Content vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"contentMediaType\":{\"type\":\"st"
|
|
140
|
+
"ring\"},\"contentEncoding\":{\"type\":\"string\"},\"contentSchema\":{\"$recursiveRef\":\"#\"}}}"
|
|
141
|
+
},
|
|
142
|
+
{"https://json-schema.org/draft/2019-09/meta/format",
|
|
143
|
+
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"https://json-schema.org/draft/2019-09/meta/forma"
|
|
144
|
+
"t\",\"$vocabulary\":{\"https://json-schema.org/draft/2019-09/vocab/format\":true},\"$recursiveAnchor\":true,\"title\":\""
|
|
145
|
+
"Format vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"format\":{\"type\":\"string\"}}}"
|
|
146
|
+
},
|
|
147
|
+
{"https://json-schema.org/draft/2020-12/schema",
|
|
148
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/schema\","
|
|
149
|
+
"\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/core\":true,\"https://json-schema.org/draft/2020-12/vocab"
|
|
150
|
+
"/applicator\":true,\"https://json-schema.org/draft/2020-12/vocab/unevaluated\":true,\"https://json-schema.org/draft/2020"
|
|
151
|
+
"-12/vocab/validation\":true,\"https://json-schema.org/draft/2020-12/vocab/meta-data\":true,\"https://json-schema.org/dra"
|
|
152
|
+
"ft/2020-12/vocab/format-annotation\":true,\"https://json-schema.org/draft/2020-12/vocab/content\":true},\"$dynamicAnchor"
|
|
153
|
+
"\":\"meta\",\"title\":\"Core and Validation specifications meta-schema\",\"allOf\":[{\"$ref\":\"meta/core\"},{\"$ref\":"
|
|
154
|
+
"\"meta/applicator\"},{\"$ref\":\"meta/unevaluated\"},{\"$ref\":\"meta/validation\"},{\"$ref\":\"meta/meta-data\"},{\"$re"
|
|
155
|
+
"f\":\"meta/format-annotation\"},{\"$ref\":\"meta/content\"}],\"type\":[\"object\",\"boolean\"],\"$comment\":\"This meta-"
|
|
156
|
+
"schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they r"
|
|
157
|
+
"emain in common use.\",\"properties\":{\"definitions\":{\"$comment\":\"\\\"definitions\\\" has been replaced by \\\"$def"
|
|
158
|
+
"s\\\".\",\"type\":\"object\",\"additionalProperties\":{\"$dynamicRef\":\"#meta\"},\"deprecated\":true,\"default\":{}},\""
|
|
159
|
+
"dependencies\":{\"$comment\":\"\\\"dependencies\\\" has been split and replaced by \\\"dependentSchemas\\\" and \\\"depe"
|
|
160
|
+
"ndentRequired\\\" in order to serve their differing semantics.\",\"type\":\"object\",\"additionalProperties\":{\"anyOf\""
|
|
161
|
+
":[{\"$dynamicRef\":\"#meta\"},{\"$ref\":\"meta/validation#/$defs/stringArray\"}]},\"deprecated\":true,\"default\":{}},\""
|
|
162
|
+
"$recursiveAnchor\":{\"$comment\":\"\\\"$recursiveAnchor\\\" has been replaced by \\\"$dynamicAnchor\\\".\",\"$ref\":\"me"
|
|
163
|
+
"ta/core#/$defs/anchorString\",\"deprecated\":true},\"$recursiveRef\":{\"$comment\":\"\\\"$recursiveRef\\\" has been repl"
|
|
164
|
+
"aced by \\\"$dynamicRef\\\".\",\"$ref\":\"meta/core#/$defs/uriReferenceString\",\"deprecated\":true}}}"
|
|
165
|
+
},
|
|
166
|
+
{"https://json-schema.org/draft/2020-12/meta/core",
|
|
167
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/core"
|
|
168
|
+
"\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/core\":true},\"$dynamicAnchor\":\"meta\",\"title\":\"C"
|
|
169
|
+
"ore vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"$ref\":\"#/$defs/uriReferenceS"
|
|
170
|
+
"tring\",\"$comment\":\"Non-empty fragments not allowed.\",\"pattern\":\"^[^#]*#?$\"},\"$schema\":{\"$ref\":\"#/$defs/uri"
|
|
171
|
+
"String\"},\"$ref\":{\"$ref\":\"#/$defs/uriReferenceString\"},\"$anchor\":{\"$ref\":\"#/$defs/anchorString\"},\"$dynamicR"
|
|
172
|
+
"ef\":{\"$ref\":\"#/$defs/uriReferenceString\"},\"$dynamicAnchor\":{\"$ref\":\"#/$defs/anchorString\"},\"$vocabulary\":{"
|
|
173
|
+
"\"type\":\"object\",\"propertyNames\":{\"$ref\":\"#/$defs/uriString\"},\"additionalProperties\":{\"type\":\"boolean\"}},"
|
|
174
|
+
"\"$comment\":{\"type\":\"string\"},\"$defs\":{\"type\":\"object\",\"additionalProperties\":{\"$dynamicRef\":\"#meta\"}}}"
|
|
175
|
+
",\"$defs\":{\"anchorString\":{\"type\":\"string\",\"pattern\":\"^[A-Za-z_][-A-Za-z0-9._]*$\"},\"uriString\":{\"type\":\""
|
|
176
|
+
"string\",\"format\":\"uri\"},\"uriReferenceString\":{\"type\":\"string\",\"format\":\"uri-reference\"}}}"
|
|
177
|
+
},
|
|
178
|
+
{"https://json-schema.org/draft/2020-12/meta/applicator",
|
|
179
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/appli"
|
|
180
|
+
"cator\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/applicator\":true},\"$dynamicAnchor\":\"meta\",\""
|
|
181
|
+
"title\":\"Applicator vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"prefixItems\":{\"$ref"
|
|
182
|
+
"\":\"#/$defs/schemaArray\"},\"items\":{\"$dynamicRef\":\"#meta\"},\"contains\":{\"$dynamicRef\":\"#meta\"},\"additionalP"
|
|
183
|
+
"roperties\":{\"$dynamicRef\":\"#meta\"},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$dynamicRef\":\""
|
|
184
|
+
"#meta\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$dynamicRef\":\"#meta\"}"
|
|
185
|
+
",\"propertyNames\":{\"format\":\"regex\"},\"default\":{}},\"dependentSchemas\":{\"type\":\"object\",\"additionalProperti"
|
|
186
|
+
"es\":{\"$dynamicRef\":\"#meta\"},\"default\":{}},\"propertyNames\":{\"$dynamicRef\":\"#meta\"},\"if\":{\"$dynamicRef\":"
|
|
187
|
+
"\"#meta\"},\"then\":{\"$dynamicRef\":\"#meta\"},\"else\":{\"$dynamicRef\":\"#meta\"},\"allOf\":{\"$ref\":\"#/$defs/schem"
|
|
188
|
+
"aArray\"},\"anyOf\":{\"$ref\":\"#/$defs/schemaArray\"},\"oneOf\":{\"$ref\":\"#/$defs/schemaArray\"},\"not\":{\"$dynamicR"
|
|
189
|
+
"ef\":\"#meta\"}},\"$defs\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$dynamicRef\":\"#meta\"}}}}"
|
|
190
|
+
},
|
|
191
|
+
{"https://json-schema.org/draft/2020-12/meta/validation",
|
|
192
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/valid"
|
|
193
|
+
"ation\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/validation\":true},\"$dynamicAnchor\":\"meta\",\""
|
|
194
|
+
"title\":\"Validation vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"type\":{\"anyOf\":[{\""
|
|
195
|
+
"$ref\":\"#/$defs/simpleTypes\"},{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/simpleTypes\"},\"minItems\":1,\"unique"
|
|
196
|
+
"Items\":true}]},\"const\":true,\"enum\":{\"type\":\"array\",\"items\":true},\"multipleOf\":{\"type\":\"number\",\"exclus"
|
|
197
|
+
"iveMinimum\":0},\"maximum\":{\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimum\":{\"type\":\"num"
|
|
198
|
+
"ber\"},\"exclusiveMinimum\":{\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/$defs/nonNegativeInteger\"},\"minLength\":"
|
|
199
|
+
"{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"maxItems\":{"
|
|
200
|
+
"\"$ref\":\"#/$defs/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\"},\"uniqueItems\":"
|
|
201
|
+
"{\"type\":\"boolean\",\"default\":false},\"maxContains\":{\"$ref\":\"#/$defs/nonNegativeInteger\"},\"minContains\":{\"$r"
|
|
202
|
+
"ef\":\"#/$defs/nonNegativeInteger\",\"default\":1},\"maxProperties\":{\"$ref\":\"#/$defs/nonNegativeInteger\"},\"minProp"
|
|
203
|
+
"erties\":{\"$ref\":\"#/$defs/nonNegativeIntegerDefault0\"},\"required\":{\"$ref\":\"#/$defs/stringArray\"},\"dependentRe"
|
|
204
|
+
"quired\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#/$defs/stringArray\"}}},\"$defs\":{\"nonNegativeInte"
|
|
205
|
+
"ger\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"$ref\":\"#/$defs/nonNegativeInteger\",\"def"
|
|
206
|
+
"ault\":0},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]},\"str"
|
|
207
|
+
"ingArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true,\"default\":[]}}}"
|
|
208
|
+
},
|
|
209
|
+
{"https://json-schema.org/draft/2020-12/meta/meta-data",
|
|
210
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/meta-"
|
|
211
|
+
"data\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/meta-data\":true},\"$dynamicAnchor\":\"meta\",\"ti"
|
|
212
|
+
"tle\":\"Meta-data vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"title\":{\"type\":\"strin"
|
|
213
|
+
"g\"},\"description\":{\"type\":\"string\"},\"default\":true,\"deprecated\":{\"type\":\"boolean\",\"default\":false},\"re"
|
|
214
|
+
"adOnly\":{\"type\":\"boolean\",\"default\":false},\"writeOnly\":{\"type\":\"boolean\",\"default\":false},\"examples\":{"
|
|
215
|
+
"\"type\":\"array\",\"items\":true}}}"
|
|
216
|
+
},
|
|
217
|
+
{"https://json-schema.org/draft/2020-12/meta/content",
|
|
218
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/conte"
|
|
219
|
+
"nt\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/content\":true},\"$dynamicAnchor\":\"meta\",\"title"
|
|
220
|
+
"\":\"Content vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"contentEncoding\":{\"type\":\""
|
|
221
|
+
"string\"},\"contentMediaType\":{\"type\":\"string\"},\"contentSchema\":{\"$dynamicRef\":\"#meta\"}}}"
|
|
222
|
+
},
|
|
223
|
+
{"https://json-schema.org/draft/2020-12/meta/unevaluated",
|
|
224
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/uneva"
|
|
225
|
+
"luated\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/unevaluated\":true},\"$dynamicAnchor\":\"meta\","
|
|
226
|
+
"\"title\":\"Unevaluated applicator vocabulary meta-schema\",\"type\":[\"object\",\"boolean\"],\"properties\":{\"unevalua"
|
|
227
|
+
"tedItems\":{\"$dynamicRef\":\"#meta\"},\"unevaluatedProperties\":{\"$dynamicRef\":\"#meta\"}}}"
|
|
228
|
+
},
|
|
229
|
+
{"https://json-schema.org/draft/2020-12/meta/format-annotation",
|
|
230
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/forma"
|
|
231
|
+
"t-annotation\",\"$vocabulary\":{\"https://json-schema.org/draft/2020-12/vocab/format-annotation\":true},\"$dynamicAnchor"
|
|
232
|
+
"\":\"meta\",\"title\":\"Format vocabulary meta-schema for annotation results\",\"type\":[\"object\",\"boolean\"],\"prope"
|
|
233
|
+
"rties\":{\"format\":{\"type\":\"string\"}}}"
|
|
234
|
+
},
|
|
235
|
+
{"https://json-schema.org/draft/2020-12/meta/format-assertion",
|
|
236
|
+
"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://json-schema.org/draft/2020-12/meta/forma"
|
|
237
|
+
"t-assertion\",\"$dynamicAnchor\":\"meta\",\"title\":\"Format vocabulary meta-schema for assertion results\",\"type\":[\""
|
|
238
|
+
"object\",\"boolean\"],\"properties\":{\"format\":{\"type\":\"string\"}}}"
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const size_t teptris_n_builtin_resources =
|
|
243
|
+
sizeof(teptris_builtin_resources) / sizeof(teptris_builtin_resources[0]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* The official JSON Schema metaschemas as built-in resources. */
|
|
2
|
+
#ifndef TEPTRIS_SCHEMA_METASCHEMAS_H
|
|
3
|
+
#define TEPTRIS_SCHEMA_METASCHEMAS_H
|
|
4
|
+
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
|
|
7
|
+
struct teptris_builtin_resource {
|
|
8
|
+
const char *uri;
|
|
9
|
+
const char *json;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
extern const struct teptris_builtin_resource teptris_builtin_resources[];
|
|
13
|
+
extern const size_t teptris_n_builtin_resources;
|
|
14
|
+
|
|
15
|
+
#endif
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/* The resource model: JSON Schema resources (a base URI + the jv
|
|
2
|
+
* subtree it names), relative-reference joining, and file-backed
|
|
3
|
+
* resource loading. A parser library never touches the network:
|
|
4
|
+
* http(s) targets are rejected by the caller; file-backed resources
|
|
5
|
+
* are size-capped and memoized per canonical path. */
|
|
6
|
+
#include <limits.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
#include "json_read.h"
|
|
12
|
+
#include "refs.h"
|
|
13
|
+
#include "schema_internal.h"
|
|
14
|
+
#include "teptris/memory/arena.h"
|
|
15
|
+
|
|
16
|
+
/* load (or memoize) the file-backed resource named by a base URI */
|
|
17
|
+
jv *sch_load_resource(sctx *c, const char *abs_uri) {
|
|
18
|
+
char path[TEPTRIS_URI_MAX];
|
|
19
|
+
if (!teptris_file_uri_to_path(abs_uri, path, sizeof path)) return NULL;
|
|
20
|
+
for (size_t i = 0; i < c->n_resources; i++) {
|
|
21
|
+
if (strcmp(c->resources[i].abs, abs_uri) == 0) {
|
|
22
|
+
return c->resources[i].root;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (c->n_resources >= 64) return NULL; /* the resource fan-out cap */
|
|
26
|
+
size_t len = 0;
|
|
27
|
+
char *text = malloc(TEPTRIS_RESOURCE_MAX_BYTES);
|
|
28
|
+
if (text == NULL) return NULL;
|
|
29
|
+
FILE *f = fopen(path, "rb");
|
|
30
|
+
if (f == NULL) {
|
|
31
|
+
free(text);
|
|
32
|
+
return NULL;
|
|
33
|
+
}
|
|
34
|
+
len = fread(text, 1, TEPTRIS_RESOURCE_MAX_BYTES, f);
|
|
35
|
+
fclose(f);
|
|
36
|
+
if (len == 0) {
|
|
37
|
+
free(text);
|
|
38
|
+
return NULL;
|
|
39
|
+
}
|
|
40
|
+
char jerr[160] = {0};
|
|
41
|
+
jv *root = json_read(c->a, text, len, jerr, sizeof jerr);
|
|
42
|
+
free(text);
|
|
43
|
+
if (root == NULL) return NULL;
|
|
44
|
+
|
|
45
|
+
if (c->n_resources == c->cap_resources) {
|
|
46
|
+
c->cap_resources = c->cap_resources == 0 ? 8 : c->cap_resources * 2;
|
|
47
|
+
void *nr = teptris_arena_alloc(c->a, c->cap_resources * sizeof(*c->resources));
|
|
48
|
+
if (c->n_resources > 0) {
|
|
49
|
+
memcpy(nr, c->resources, c->n_resources * sizeof(*c->resources));
|
|
50
|
+
}
|
|
51
|
+
c->resources = nr;
|
|
52
|
+
}
|
|
53
|
+
teptris_resource *res = &c->resources[c->n_resources++];
|
|
54
|
+
res->abs = teptris_arena_alloc(c->a, strlen(abs_uri) + 1);
|
|
55
|
+
strcpy((char *)res->abs, abs_uri);
|
|
56
|
+
res->root = root;
|
|
57
|
+
res->node = NULL;
|
|
58
|
+
res->recursive_anchor = false;
|
|
59
|
+
return root;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ---------------------------------------------------- uri joining -- */
|
|
63
|
+
|
|
64
|
+
/* the directory part of a base URI path ("file:///a/b/c.json" ->
|
|
65
|
+
* "file:///a/b/"); the base itself when there is no slash */
|
|
66
|
+
static void uri_dir(const char *base, char *out, size_t cap) {
|
|
67
|
+
if (base == NULL) {
|
|
68
|
+
out[0] = '\0';
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const char *slash = strrchr(base, '/');
|
|
72
|
+
if (slash == NULL) {
|
|
73
|
+
snprintf(out, cap, "%s", base);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
size_t n = (size_t)(slash - base) + 1;
|
|
77
|
+
if (n >= cap) n = cap - 1;
|
|
78
|
+
memcpy(out, base, n);
|
|
79
|
+
out[n] = '\0';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static void remove_dot_segments(char *path) {
|
|
83
|
+
/* RFC 3986 5.2.4 over the whole string; paths here are simple
|
|
84
|
+
* enough that the loop form suffices */
|
|
85
|
+
char *w = path;
|
|
86
|
+
char *r = path;
|
|
87
|
+
while (*r != '\0') {
|
|
88
|
+
if (r[0] == '.' && r[1] == '/' ) {
|
|
89
|
+
r += 2;
|
|
90
|
+
} else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
|
|
91
|
+
r += 3;
|
|
92
|
+
/* pop the last segment of w */
|
|
93
|
+
char *slash = NULL;
|
|
94
|
+
for (char *p = w; *p != '\0'; p++) {
|
|
95
|
+
if (*p == '/') slash = p;
|
|
96
|
+
}
|
|
97
|
+
if (slash != NULL && slash > path) {
|
|
98
|
+
*slash = '\0';
|
|
99
|
+
} else if (slash == path) {
|
|
100
|
+
slash[1] = '\0';
|
|
101
|
+
} else {
|
|
102
|
+
w[0] = '\0';
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
while (*r != '\0' && *r != '/') *w++ = *r++;
|
|
106
|
+
if (*r == '/') *w++ = *r++;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
*w = '\0';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* join a relative reference against a base; scheme:// targets and
|
|
113
|
+
* absolute paths stand alone. NULL when the reference cannot be
|
|
114
|
+
* resolved (caller decides whether that is a rejection) */
|
|
115
|
+
bool teptris_uri_join(const char *base, const char *ref, char *out,
|
|
116
|
+
size_t cap) {
|
|
117
|
+
out[0] = '\0';
|
|
118
|
+
if (ref == NULL) return false;
|
|
119
|
+
if (strncmp(ref, "http://", 7) == 0 || strncmp(ref, "https://", 8) == 0) {
|
|
120
|
+
/* network targets never resolve here */
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
{
|
|
124
|
+
/* any other scheme ("urn:uuid:...", "mailto:...") is an
|
|
125
|
+
* absolute URI: it stands alone and may name an in-memory
|
|
126
|
+
* resource (see the resource table) */
|
|
127
|
+
const char *p = ref;
|
|
128
|
+
if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) {
|
|
129
|
+
while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') ||
|
|
130
|
+
(*p >= '0' && *p <= '9') || *p == '+' || *p == '-' ||
|
|
131
|
+
*p == '.') {
|
|
132
|
+
p++;
|
|
133
|
+
}
|
|
134
|
+
if (*p == ':' && p != ref) {
|
|
135
|
+
snprintf(out, cap, "%s", ref);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (strncmp(ref, "file://", 7) == 0) {
|
|
141
|
+
snprintf(out, cap, "%s", ref);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
if (ref[0] == '/') {
|
|
145
|
+
/* a network-path reference: no base directory applies, but an
|
|
146
|
+
* http(s) base still lends its scheme and authority */
|
|
147
|
+
if (strncmp(base, "http://", 7) == 0 ||
|
|
148
|
+
strncmp(base, "https://", 8) == 0) {
|
|
149
|
+
const char *auth = strstr(base, "://") + 3;
|
|
150
|
+
const char *end = strchr(auth, '/');
|
|
151
|
+
size_t n = end != NULL ? (size_t)(end - base) : strlen(base);
|
|
152
|
+
if (n >= cap || strlen(ref) + n + 1 >= cap) return false;
|
|
153
|
+
memcpy(out, base, n);
|
|
154
|
+
strcpy(out + n, ref);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
/* absolute path: no base directory applies */
|
|
158
|
+
char tmp[TEPTRIS_URI_MAX];
|
|
159
|
+
snprintf(tmp, sizeof tmp, "%s", ref);
|
|
160
|
+
remove_dot_segments(tmp);
|
|
161
|
+
snprintf(out, cap, "file://%s", tmp);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
if (base == NULL || base[0] == '\0') return false;
|
|
165
|
+
if (strncmp(base, "http://", 7) == 0 || strncmp(base, "https://", 8) == 0) {
|
|
166
|
+
/* merge in URI space (RFC 3986 5.3): suite documents name
|
|
167
|
+
* in-memory resources with http-space $ids; resolution merges
|
|
168
|
+
* against that space and only ever hits the resource table —
|
|
169
|
+
* nothing here is ever fetched from the network */
|
|
170
|
+
const char *auth = strstr(base, "://");
|
|
171
|
+
if (auth == NULL) return false;
|
|
172
|
+
/* merge uses the base's directory: up to the LAST slash */
|
|
173
|
+
const char *last_slash = strrchr(auth + 3, '/');
|
|
174
|
+
if (last_slash == NULL) return false;
|
|
175
|
+
size_t n = (size_t)(last_slash - base) + 1;
|
|
176
|
+
if (n >= cap) return false;
|
|
177
|
+
memcpy(out, base, n);
|
|
178
|
+
out[n] = '\0';
|
|
179
|
+
char path_part[TEPTRIS_URI_MAX];
|
|
180
|
+
const char *hash = strchr(ref, '#');
|
|
181
|
+
size_t plen = hash != NULL ? (size_t)(hash - ref) : strlen(ref);
|
|
182
|
+
if (plen >= sizeof path_part) return false;
|
|
183
|
+
memcpy(path_part, ref, plen);
|
|
184
|
+
path_part[plen] = '\0';
|
|
185
|
+
if (strlen(out) + plen + 1 > cap) return false;
|
|
186
|
+
strcat(out, path_part);
|
|
187
|
+
remove_dot_segments(out + n);
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
if (strncmp(base, "file://", 7) != 0) {
|
|
191
|
+
/* a non-file base (an http base that was rewritten away, a
|
|
192
|
+
* bare id) cannot host relative references without fs backing
|
|
193
|
+
* unless the base itself is a plain path */
|
|
194
|
+
snprintf(out, cap, "%s", ref);
|
|
195
|
+
return true; /* resolved against the CWD by the caller */
|
|
196
|
+
}
|
|
197
|
+
char dir[TEPTRIS_URI_MAX];
|
|
198
|
+
uri_dir(base, dir, sizeof dir);
|
|
199
|
+
size_t n = strlen(dir);
|
|
200
|
+
if (n >= cap) return false;
|
|
201
|
+
memcpy(out, dir, n + 1);
|
|
202
|
+
/* the reference may carry a fragment; split it now */
|
|
203
|
+
char path_part[TEPTRIS_URI_MAX];
|
|
204
|
+
const char *hash = strchr(ref, '#');
|
|
205
|
+
size_t plen = hash != NULL ? (size_t)(hash - ref) : strlen(ref);
|
|
206
|
+
if (plen >= sizeof path_part) return false;
|
|
207
|
+
memcpy(path_part, ref, plen);
|
|
208
|
+
path_part[plen] = '\0';
|
|
209
|
+
if (strlen(out) + strlen(path_part) + 1 > cap) return false;
|
|
210
|
+
strcat(out, path_part);
|
|
211
|
+
/* normalize the path part only (after file://) */
|
|
212
|
+
char *path_start = out + 7;
|
|
213
|
+
if (strncmp(out, "file://", 7) == 0) {
|
|
214
|
+
remove_dot_segments(path_start);
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* split "scheme://path#fragment" into the document part and the
|
|
220
|
+
* fragment part (fragment may be NULL/empty) */
|
|
221
|
+
void teptris_uri_split(const char *uri, char *doc, size_t doc_cap,
|
|
222
|
+
char *frag, size_t frag_cap) {
|
|
223
|
+
doc[0] = frag[0] = '\0';
|
|
224
|
+
const char *hash = strchr(uri, '#');
|
|
225
|
+
size_t dlen = hash != NULL ? (size_t)(hash - uri) : strlen(uri);
|
|
226
|
+
if (dlen >= doc_cap) dlen = doc_cap - 1;
|
|
227
|
+
memcpy(doc, uri, dlen);
|
|
228
|
+
doc[dlen] = '\0';
|
|
229
|
+
if (hash != NULL && hash[1] != '\0') {
|
|
230
|
+
snprintf(frag, frag_cap, "%s", hash + 1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* -------------------------------------------------- file resources -- */
|
|
235
|
+
|
|
236
|
+
bool teptris_file_uri_to_path(const char *uri, char *path, size_t cap) {
|
|
237
|
+
if (strncmp(uri, "file://", 7) == 0) {
|
|
238
|
+
snprintf(path, cap, "%s", uri + 7);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
snprintf(path, cap, "%s", uri);
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* The resource model: base URIs, relative-reference joining, and
|
|
2
|
+
* file-backed resource loading. Internal to the schema subsystem. */
|
|
3
|
+
#ifndef TEPTRIS_SCHEMA_REFS_H
|
|
4
|
+
#define TEPTRIS_SCHEMA_REFS_H
|
|
5
|
+
|
|
6
|
+
#include <stdbool.h>
|
|
7
|
+
#include <stddef.h>
|
|
8
|
+
|
|
9
|
+
#define TEPTRIS_URI_MAX 1024
|
|
10
|
+
#define TEPTRIS_RESOURCE_MAX_BYTES (1u << 20)
|
|
11
|
+
|
|
12
|
+
/* join a relative reference against a base URI; the caller owns the
|
|
13
|
+
* rejection policy for http(s) and unbacked bases */
|
|
14
|
+
bool teptris_uri_join(const char *base, const char *ref, char *out,
|
|
15
|
+
size_t cap);
|
|
16
|
+
|
|
17
|
+
/* split "doc#fragment" (fragment may come back empty) */
|
|
18
|
+
void teptris_uri_split(const char *uri, char *doc, size_t doc_cap,
|
|
19
|
+
char *frag, size_t frag_cap);
|
|
20
|
+
|
|
21
|
+
/* file:// URIs to plain paths (plain paths pass through) */
|
|
22
|
+
bool teptris_file_uri_to_path(const char *uri, char *path, size_t cap);
|
|
23
|
+
|
|
24
|
+
#endif
|