fast_json-schema 0.1.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 +7 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Dockerfile +17 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +68 -0
- data/LICENSE.txt +21 -0
- data/README.md +156 -0
- data/Rakefile +60 -0
- data/build-deps +3 -0
- data/data/invalid.json +31 -0
- data/data/schema.json +150 -0
- data/data/valid.json +49 -0
- data/ext/fast_json/schema/all_of.c +23 -0
- data/ext/fast_json/schema/all_of.h +4 -0
- data/ext/fast_json/schema/any_of.c +22 -0
- data/ext/fast_json/schema/any_of.h +4 -0
- data/ext/fast_json/schema/compiled_schema.c +503 -0
- data/ext/fast_json/schema/compiled_schema.h +10 -0
- data/ext/fast_json/schema/context.c +78 -0
- data/ext/fast_json/schema/error.c +26 -0
- data/ext/fast_json/schema/error.h +5 -0
- data/ext/fast_json/schema/extconf.rb +7 -0
- data/ext/fast_json/schema/formats/custom_format.c +63 -0
- data/ext/fast_json/schema/formats/custom_format.h +4 -0
- data/ext/fast_json/schema/formats/date.c +48 -0
- data/ext/fast_json/schema/formats/date.h +5 -0
- data/ext/fast_json/schema/formats/date_time.c +22 -0
- data/ext/fast_json/schema/formats/date_time.h +4 -0
- data/ext/fast_json/schema/formats/email.c +8 -0
- data/ext/fast_json/schema/formats/email.h +4 -0
- data/ext/fast_json/schema/formats/format.c +68 -0
- data/ext/fast_json/schema/formats/format.h +4 -0
- data/ext/fast_json/schema/formats/hostname.c +8 -0
- data/ext/fast_json/schema/formats/hostname.h +4 -0
- data/ext/fast_json/schema/formats/idn_email.c +8 -0
- data/ext/fast_json/schema/formats/idn_email.h +4 -0
- data/ext/fast_json/schema/formats/idn_hostname.c +8 -0
- data/ext/fast_json/schema/formats/idn_hostname.h +4 -0
- data/ext/fast_json/schema/formats/ipv4.c +8 -0
- data/ext/fast_json/schema/formats/ipv4.h +4 -0
- data/ext/fast_json/schema/formats/ipv6.c +8 -0
- data/ext/fast_json/schema/formats/ipv6.h +4 -0
- data/ext/fast_json/schema/formats/iri.c +8 -0
- data/ext/fast_json/schema/formats/iri.h +4 -0
- data/ext/fast_json/schema/formats/iri_reference.c +8 -0
- data/ext/fast_json/schema/formats/iri_reference.h +4 -0
- data/ext/fast_json/schema/formats/json_pointer.c +8 -0
- data/ext/fast_json/schema/formats/json_pointer.h +4 -0
- data/ext/fast_json/schema/formats/regex.c +27 -0
- data/ext/fast_json/schema/formats/regex.h +4 -0
- data/ext/fast_json/schema/formats/relative_json_pointer.c +57 -0
- data/ext/fast_json/schema/formats/relative_json_pointer.h +4 -0
- data/ext/fast_json/schema/formats/time.c +65 -0
- data/ext/fast_json/schema/formats/time.h +5 -0
- data/ext/fast_json/schema/formats/uri.c +8 -0
- data/ext/fast_json/schema/formats/uri.h +4 -0
- data/ext/fast_json/schema/formats/uri_reference.c +8 -0
- data/ext/fast_json/schema/formats/uri_reference.h +4 -0
- data/ext/fast_json/schema/formats/uri_template.c +8 -0
- data/ext/fast_json/schema/formats/uri_template.h +4 -0
- data/ext/fast_json/schema/formats/utils/addr_spec_parser.c +342 -0
- data/ext/fast_json/schema/formats/utils/addr_spec_parser.h +16 -0
- data/ext/fast_json/schema/formats/utils/hostname_parser.c +113 -0
- data/ext/fast_json/schema/formats/utils/hostname_parser.h +17 -0
- data/ext/fast_json/schema/formats/utils/ip_parser.c +126 -0
- data/ext/fast_json/schema/formats/utils/ip_parser.h +25 -0
- data/ext/fast_json/schema/formats/utils/json_pointer_parser.c +45 -0
- data/ext/fast_json/schema/formats/utils/json_pointer_parser.h +20 -0
- data/ext/fast_json/schema/formats/utils/uri_parser.c +605 -0
- data/ext/fast_json/schema/formats/utils/uri_parser.h +20 -0
- data/ext/fast_json/schema/formats/utils/uri_template_parser.c +235 -0
- data/ext/fast_json/schema/formats/utils/uri_template_parser.h +18 -0
- data/ext/fast_json/schema/formats/utils/utf8.c +73 -0
- data/ext/fast_json/schema/formats/utils/utf8.h +17 -0
- data/ext/fast_json/schema/if.c +31 -0
- data/ext/fast_json/schema/if.h +4 -0
- data/ext/fast_json/schema/is_valid.c +124 -0
- data/ext/fast_json/schema/is_valid.h +6 -0
- data/ext/fast_json/schema/keywords.c +220 -0
- data/ext/fast_json/schema/keywords.h +60 -0
- data/ext/fast_json/schema/nested_schemas.c +68 -0
- data/ext/fast_json/schema/nested_schemas.h +4 -0
- data/ext/fast_json/schema/not.c +11 -0
- data/ext/fast_json/schema/not.h +4 -0
- data/ext/fast_json/schema/one_of.c +23 -0
- data/ext/fast_json/schema/one_of.h +4 -0
- data/ext/fast_json/schema/path.c +44 -0
- data/ext/fast_json/schema/path.h +5 -0
- data/ext/fast_json/schema/properties_val.c +103 -0
- data/ext/fast_json/schema/properties_val.h +6 -0
- data/ext/fast_json/schema/ref.c +7 -0
- data/ext/fast_json/schema/ref.h +4 -0
- data/ext/fast_json/schema/ref_resolver.c +85 -0
- data/ext/fast_json/schema/ref_resolver.h +5 -0
- data/ext/fast_json/schema/schema.c +68 -0
- data/ext/fast_json/schema/schema_collection.c +29 -0
- data/ext/fast_json/schema/schema_collection.h +3 -0
- data/ext/fast_json/schema/types/compiled_schema.h +96 -0
- data/ext/fast_json/schema/types/context.h +27 -0
- data/ext/fast_json/schema/validate.c +63 -0
- data/ext/fast_json/schema/validate.h +19 -0
- data/ext/fast_json/schema/validate_array.c +130 -0
- data/ext/fast_json/schema/validate_array.h +4 -0
- data/ext/fast_json/schema/validate_bool.c +7 -0
- data/ext/fast_json/schema/validate_bool.h +4 -0
- data/ext/fast_json/schema/validate_integer.c +52 -0
- data/ext/fast_json/schema/validate_integer.h +4 -0
- data/ext/fast_json/schema/validate_null.c +7 -0
- data/ext/fast_json/schema/validate_null.h +4 -0
- data/ext/fast_json/schema/validate_number.c +62 -0
- data/ext/fast_json/schema/validate_number.h +4 -0
- data/ext/fast_json/schema/validate_object.c +159 -0
- data/ext/fast_json/schema/validate_object.h +4 -0
- data/ext/fast_json/schema/validate_string.c +32 -0
- data/ext/fast_json/schema/validate_string.h +4 -0
- data/ext/fast_json/schema/value_pointer_caster.h +9 -0
- data/fast_json-schema.gemspec +31 -0
- data/lib/fast_json/schema/error.rb +16 -0
- data/lib/fast_json/schema/version.rb +7 -0
- data/lib/fast_json/schema.rb +50 -0
- data/makefile +10 -0
- metadata +164 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#include "custom_format.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
struct custom_call_args {
|
|
5
|
+
VALUE callable;
|
|
6
|
+
VALUE data;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
static VALUE call_custom_validator(VALUE arg_ptr) {
|
|
10
|
+
struct custom_call_args *args = (struct custom_call_args *)arg_ptr;
|
|
11
|
+
|
|
12
|
+
return rb_funcall(args->callable, rb_intern("call"), 1, args->data);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static void validate_custom_format(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
16
|
+
int state = 0;
|
|
17
|
+
struct custom_call_args args = { compiled_schema->custom_format_callable_val, data };
|
|
18
|
+
VALUE result = rb_protect(call_custom_validator, (VALUE)&args, &state);
|
|
19
|
+
|
|
20
|
+
const char *error_key = RSTRING_PTR(compiled_schema->custom_format_error_key_val);
|
|
21
|
+
|
|
22
|
+
if(state) {
|
|
23
|
+
rb_set_errinfo(Qnil);
|
|
24
|
+
|
|
25
|
+
yield_error(compiled_schema, data, context, error_key);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(!RTEST(result))
|
|
30
|
+
yield_error(compiled_schema, data, context, error_key);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static VALUE custom_format_validation_callable_for(VALUE format_val, VALUE custom_formats) {
|
|
34
|
+
if(NIL_P(custom_formats) || custom_formats == Qundef)
|
|
35
|
+
return Qundef;
|
|
36
|
+
|
|
37
|
+
VALUE callable = rb_hash_aref(custom_formats, format_val);
|
|
38
|
+
|
|
39
|
+
if(NIL_P(callable))
|
|
40
|
+
return Qundef;
|
|
41
|
+
|
|
42
|
+
return callable;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static VALUE custom_format_error_key_for(VALUE format_val) {
|
|
46
|
+
VALUE error_key = rb_str_new_cstr("format_");
|
|
47
|
+
rb_str_append(error_key, format_val);
|
|
48
|
+
rb_str_freeze(error_key);
|
|
49
|
+
|
|
50
|
+
return error_key;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
bool set_custom_format_validation_function_for_compiled_schema(CompiledSchema *compiled_schema, VALUE format_val, VALUE custom_formats) {
|
|
54
|
+
VALUE callable = custom_format_validation_callable_for(format_val, custom_formats);
|
|
55
|
+
|
|
56
|
+
if(Qundef == callable) return false;
|
|
57
|
+
|
|
58
|
+
compiled_schema->format_validation_function = validate_custom_format;
|
|
59
|
+
compiled_schema->custom_format_callable_val = callable;
|
|
60
|
+
compiled_schema->custom_format_error_key_val = custom_format_error_key_for(format_val);
|
|
61
|
+
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#include "date.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Days in each month of the year.
|
|
8
|
+
* February has 28 days in a common year and 29 days in a leap year(See `days_in_month` function for more details).
|
|
9
|
+
*/
|
|
10
|
+
static const int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
11
|
+
|
|
12
|
+
static bool is_leap_year(int year) {
|
|
13
|
+
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static int days_in_month(int year, int month) {
|
|
17
|
+
if(month == 2 && is_leap_year(year)) return 29;
|
|
18
|
+
|
|
19
|
+
return days[month - 1];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Strict RFC 3339 full-date parser: YYYY-MM-DD
|
|
24
|
+
* Returns true if valid, false otherwise.
|
|
25
|
+
*/
|
|
26
|
+
bool parse_full_date(const char *s, long len) {
|
|
27
|
+
if(len != 10) return false;
|
|
28
|
+
|
|
29
|
+
if(!IS_DIGIT(s[0]) || !IS_DIGIT(s[1]) || !IS_DIGIT(s[2]) || !IS_DIGIT(s[3])) return false;
|
|
30
|
+
if(s[4] != '-') return false;
|
|
31
|
+
if(!IS_DIGIT(s[5]) || !IS_DIGIT(s[6])) return false;
|
|
32
|
+
if(s[7] != '-') return false;
|
|
33
|
+
if(!IS_DIGIT(s[8]) || !IS_DIGIT(s[9])) return false;
|
|
34
|
+
|
|
35
|
+
int year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
|
|
36
|
+
int month = (s[5] - '0') * 10 + (s[6] - '0');
|
|
37
|
+
int day = (s[8] - '0') * 10 + (s[9] - '0');
|
|
38
|
+
|
|
39
|
+
if(month < 1 || month > 12) return false;
|
|
40
|
+
if(day < 1 || day > days_in_month(year, month)) return false;
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void validate_format_date(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
46
|
+
if(!parse_full_date(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
47
|
+
yield_error(compiled_schema, data, context, "format_date");
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include "date_time.h"
|
|
2
|
+
#include "date.h"
|
|
3
|
+
#include "time.h"
|
|
4
|
+
#include "error.h"
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Strict RFC 3339 date-time: full-date "T" full-time
|
|
8
|
+
* Only uppercase "T" separator is accepted.
|
|
9
|
+
*/
|
|
10
|
+
void validate_format_date_time(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
11
|
+
const char *s = RSTRING_PTR(data);
|
|
12
|
+
long len = RSTRING_LEN(data);
|
|
13
|
+
|
|
14
|
+
if(len < 12 || s[10] != 'T')
|
|
15
|
+
return yield_error(compiled_schema, data, context, "format_date_time");
|
|
16
|
+
|
|
17
|
+
if(!parse_full_date(s, 10))
|
|
18
|
+
return yield_error(compiled_schema, data, context, "format_date_time");
|
|
19
|
+
|
|
20
|
+
if(!parse_full_time(s + 11, len - 11))
|
|
21
|
+
return yield_error(compiled_schema, data, context, "format_date_time");
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "email.h"
|
|
2
|
+
#include "formats/utils/addr_spec_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_email(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_addr_spec(RSTRING_PTR(data), RSTRING_LEN(data), false))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_email");
|
|
8
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#include "format.h"
|
|
2
|
+
#include "date.h"
|
|
3
|
+
#include "time.h"
|
|
4
|
+
#include "date_time.h"
|
|
5
|
+
#include "email.h"
|
|
6
|
+
#include "idn_email.h"
|
|
7
|
+
#include "hostname.h"
|
|
8
|
+
#include "idn_hostname.h"
|
|
9
|
+
#include "ipv4.h"
|
|
10
|
+
#include "ipv6.h"
|
|
11
|
+
#include "uri.h"
|
|
12
|
+
#include "uri_reference.h"
|
|
13
|
+
#include "iri.h"
|
|
14
|
+
#include "iri_reference.h"
|
|
15
|
+
#include "uri_template.h"
|
|
16
|
+
#include "regex.h"
|
|
17
|
+
#include "json_pointer.h"
|
|
18
|
+
#include "relative_json_pointer.h"
|
|
19
|
+
#include "custom_format.h"
|
|
20
|
+
|
|
21
|
+
static void no_op_format_validate(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static format_validation_function built_in_format_validation_function_for(VALUE format_val) {
|
|
26
|
+
const char *format_str = StringValueCStr(format_val);
|
|
27
|
+
|
|
28
|
+
if(strcmp(format_str, "date") == 0) return validate_format_date;
|
|
29
|
+
if(strcmp(format_str, "time") == 0) return validate_format_time;
|
|
30
|
+
if(strcmp(format_str, "date-time") == 0) return validate_format_date_time;
|
|
31
|
+
if(strcmp(format_str, "email") == 0) return validate_format_email;
|
|
32
|
+
if(strcmp(format_str, "idn-email") == 0) return validate_format_idn_email;
|
|
33
|
+
if(strcmp(format_str, "hostname") == 0) return validate_format_hostname;
|
|
34
|
+
if(strcmp(format_str, "idn-hostname") == 0) return validate_format_idn_hostname;
|
|
35
|
+
if(strcmp(format_str, "ipv4") == 0) return validate_format_ipv4;
|
|
36
|
+
if(strcmp(format_str, "ipv6") == 0) return validate_format_ipv6;
|
|
37
|
+
if(strcmp(format_str, "uri") == 0) return validate_format_uri;
|
|
38
|
+
if(strcmp(format_str, "uri-reference") == 0) return validate_format_uri_reference;
|
|
39
|
+
if(strcmp(format_str, "iri") == 0) return validate_format_iri;
|
|
40
|
+
if(strcmp(format_str, "iri-reference") == 0) return validate_format_iri_reference;
|
|
41
|
+
if(strcmp(format_str, "uri-template") == 0) return validate_format_uri_template;
|
|
42
|
+
if(strcmp(format_str, "regex") == 0) return validate_format_regex;
|
|
43
|
+
if(strcmp(format_str, "json-pointer") == 0) return validate_format_json_pointer;
|
|
44
|
+
if(strcmp(format_str, "relative-json-pointer") == 0) return validate_format_relative_json_pointer;
|
|
45
|
+
|
|
46
|
+
return no_op_format_validate;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static bool set_built_in_format_validation_function_for_compiled_schema(CompiledSchema *compiled_schema, VALUE format_val) {
|
|
50
|
+
compiled_schema->format_validation_function = built_in_format_validation_function_for(format_val);
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static void set_no_op_format_validation_function_for_compiled_schema(CompiledSchema *compiled_schema) {
|
|
56
|
+
compiled_schema->format_validation_function = no_op_format_validate;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
void set_format_validation_function_for_compiled_schema(CompiledSchema *compiled_schema, VALUE format_val, VALUE custom_formats) {
|
|
60
|
+
if(!RB_TYPE_P(format_val, T_STRING)) {
|
|
61
|
+
set_no_op_format_validation_function_for_compiled_schema(compiled_schema);
|
|
62
|
+
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
set_custom_format_validation_function_for_compiled_schema(compiled_schema, format_val, custom_formats) ||
|
|
67
|
+
set_built_in_format_validation_function_for_compiled_schema(compiled_schema, format_val);
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "hostname.h"
|
|
2
|
+
#include "formats/utils/hostname_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_hostname(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_hostname(RSTRING_PTR(data), RSTRING_LEN(data), false))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_hostname");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "idn_email.h"
|
|
2
|
+
#include "formats/utils/addr_spec_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_idn_email(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_addr_spec(RSTRING_PTR(data), RSTRING_LEN(data), true))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_idn_email");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "idn_hostname.h"
|
|
2
|
+
#include "formats/utils/hostname_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_idn_hostname(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_hostname(RSTRING_PTR(data), RSTRING_LEN(data), true))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_idn_hostname");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "ipv4.h"
|
|
2
|
+
#include "formats/utils/ip_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_ipv4(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_ipv4(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_ipv4");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "ipv6.h"
|
|
2
|
+
#include "formats/utils/ip_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_ipv6(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_ipv6(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_ipv6");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "iri.h"
|
|
2
|
+
#include "formats/utils/uri_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_iri(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_uri_reference(RSTRING_PTR(data), RSTRING_LEN(data), true, true))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_iri");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "iri_reference.h"
|
|
2
|
+
#include "formats/utils/uri_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_iri_reference(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_uri_reference(RSTRING_PTR(data), RSTRING_LEN(data), false, true))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_iri_reference");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "json_pointer.h"
|
|
2
|
+
#include "formats/utils/json_pointer_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_json_pointer(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_json_pointer(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_json_pointer");
|
|
8
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#include "regex.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* JSON Schema section 7.3.8 cites ECMA-262 section 21.2 as the regex dialect.
|
|
8
|
+
*
|
|
9
|
+
* This implementation delegates to Ruby's Regexp.new (Onigmo engine), which
|
|
10
|
+
* differs from strict ECMA-262 in some edge cases.
|
|
11
|
+
*
|
|
12
|
+
* The divergence matches the behavior of other Ruby JSON Schema validators.
|
|
13
|
+
*/
|
|
14
|
+
static VALUE try_compile_regex(VALUE data) {
|
|
15
|
+
return rb_reg_new_str(data, 0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void validate_format_regex(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
19
|
+
int state = 0;
|
|
20
|
+
rb_protect(try_compile_regex, data, &state);
|
|
21
|
+
|
|
22
|
+
if(state) {
|
|
23
|
+
rb_set_errinfo(Qnil);
|
|
24
|
+
|
|
25
|
+
yield_error(compiled_schema, data, context, "format_regex");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#include "relative_json_pointer.h"
|
|
2
|
+
#include "formats/utils/json_pointer_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
#include <stdbool.h>
|
|
6
|
+
|
|
7
|
+
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* draft-handrews-relative-json-pointer-02 section 3 Relative JSON Pointer parser.
|
|
11
|
+
*
|
|
12
|
+
* relative-json-pointer = non-negative-integer ( "#" / json-pointer )
|
|
13
|
+
* non-negative-integer = "0" / non-zero-digit *DIGIT
|
|
14
|
+
*
|
|
15
|
+
* The integer prefix may not have leading zeros (e.g. "01" is invalid).
|
|
16
|
+
* The trailing portion may be "#" (key/index reference) or a valid JSON
|
|
17
|
+
* Pointer including the empty string ("0" alone is valid).
|
|
18
|
+
*/
|
|
19
|
+
static bool parse_relative_json_pointer(const char *s, long len) {
|
|
20
|
+
if(len == 0) return false;
|
|
21
|
+
|
|
22
|
+
long pos = 0;
|
|
23
|
+
unsigned char first = (unsigned char)s[0];
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* Non-negative integer prefix
|
|
27
|
+
*/
|
|
28
|
+
if(first == '0') {
|
|
29
|
+
pos = 1;
|
|
30
|
+
} else if(first >= '1' && first <= '9') {
|
|
31
|
+
pos = 1;
|
|
32
|
+
|
|
33
|
+
while(pos < len && IS_DIGIT((unsigned char)s[pos])) pos++;
|
|
34
|
+
} else {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* Integer prefix only
|
|
40
|
+
*/
|
|
41
|
+
if(pos == len) return true;
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* "#" alone
|
|
45
|
+
*/
|
|
46
|
+
if(s[pos] == '#') return pos + 1 == len;
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* A valid JSON Pointer
|
|
50
|
+
*/
|
|
51
|
+
return parse_json_pointer(s + pos, len - pos);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void validate_format_relative_json_pointer(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
55
|
+
if(!parse_relative_json_pointer(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
56
|
+
yield_error(compiled_schema, data, context, "format_relative_json_pointer");
|
|
57
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#include "time.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Strict RFC 3339 full-time parser: HH:MM:SS[.fraction](Z|(+|-)HH:MM)
|
|
8
|
+
* Returns true if valid, false otherwise.
|
|
9
|
+
*/
|
|
10
|
+
bool parse_full_time(const char *s, long len) {
|
|
11
|
+
if(len < 9) return false;
|
|
12
|
+
|
|
13
|
+
if(!IS_DIGIT(s[0]) || !IS_DIGIT(s[1])) return false;
|
|
14
|
+
if(s[2] != ':') return false;
|
|
15
|
+
if(!IS_DIGIT(s[3]) || !IS_DIGIT(s[4])) return false;
|
|
16
|
+
if(s[5] != ':') return false;
|
|
17
|
+
if(!IS_DIGIT(s[6]) || !IS_DIGIT(s[7])) return false;
|
|
18
|
+
|
|
19
|
+
int hour = (s[0] - '0') * 10 + (s[1] - '0');
|
|
20
|
+
int minute = (s[3] - '0') * 10 + (s[4] - '0');
|
|
21
|
+
int second = (s[6] - '0') * 10 + (s[7] - '0');
|
|
22
|
+
|
|
23
|
+
if(hour > 23) return false;
|
|
24
|
+
if(minute > 59) return false;
|
|
25
|
+
if(second > 60) return false; // 60 is allowed for leap second per RFC 3339
|
|
26
|
+
|
|
27
|
+
long pos = 8;
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Fractional part calculation.
|
|
31
|
+
* Fractional part is optional(See RFC 3339 for more details).
|
|
32
|
+
*/
|
|
33
|
+
if(s[pos] == '.') {
|
|
34
|
+
pos++;
|
|
35
|
+
|
|
36
|
+
long fraction_start = pos;
|
|
37
|
+
|
|
38
|
+
while(pos < len && IS_DIGIT(s[pos])) pos++;
|
|
39
|
+
|
|
40
|
+
if(pos == fraction_start) return false; // empty fractional part(`12:34:56.`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if(pos >= len) return false;
|
|
44
|
+
|
|
45
|
+
if(s[pos] == 'Z') return pos == len - 1;
|
|
46
|
+
|
|
47
|
+
if(s[pos] != '+' && s[pos] != '-') return false;
|
|
48
|
+
if(len - pos != 6) return false;
|
|
49
|
+
if(!IS_DIGIT(s[pos + 1]) || !IS_DIGIT(s[pos + 2])) return false;
|
|
50
|
+
if(s[pos + 3] != ':') return false;
|
|
51
|
+
if(!IS_DIGIT(s[pos + 4]) || !IS_DIGIT(s[pos + 5])) return false;
|
|
52
|
+
|
|
53
|
+
int offset_hour = (s[pos + 1] - '0') * 10 + (s[pos + 2] - '0');
|
|
54
|
+
int offset_minute = (s[pos + 4] - '0') * 10 + (s[pos + 5] - '0');
|
|
55
|
+
|
|
56
|
+
if(offset_hour > 23) return false;
|
|
57
|
+
if(offset_minute > 59) return false;
|
|
58
|
+
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void validate_format_time(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
63
|
+
if(!parse_full_time(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
64
|
+
yield_error(compiled_schema, data, context, "format_time");
|
|
65
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "uri.h"
|
|
2
|
+
#include "formats/utils/uri_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_uri(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_uri_reference(RSTRING_PTR(data), RSTRING_LEN(data), true, false))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_uri");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "uri_reference.h"
|
|
2
|
+
#include "formats/utils/uri_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_uri_reference(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_uri_reference(RSTRING_PTR(data), RSTRING_LEN(data), false, false))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_uri_reference");
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#include "uri_template.h"
|
|
2
|
+
#include "formats/utils/uri_template_parser.h"
|
|
3
|
+
#include "error.h"
|
|
4
|
+
|
|
5
|
+
void validate_format_uri_template(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
6
|
+
if(!parse_uri_template(RSTRING_PTR(data), RSTRING_LEN(data)))
|
|
7
|
+
yield_error(compiled_schema, data, context, "format_uri_template");
|
|
8
|
+
}
|