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.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CODE_OF_CONDUCT.md +84 -0
  4. data/Dockerfile +17 -0
  5. data/Gemfile +11 -0
  6. data/Gemfile.lock +68 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +156 -0
  9. data/Rakefile +60 -0
  10. data/build-deps +3 -0
  11. data/data/invalid.json +31 -0
  12. data/data/schema.json +150 -0
  13. data/data/valid.json +49 -0
  14. data/ext/fast_json/schema/all_of.c +23 -0
  15. data/ext/fast_json/schema/all_of.h +4 -0
  16. data/ext/fast_json/schema/any_of.c +22 -0
  17. data/ext/fast_json/schema/any_of.h +4 -0
  18. data/ext/fast_json/schema/compiled_schema.c +503 -0
  19. data/ext/fast_json/schema/compiled_schema.h +10 -0
  20. data/ext/fast_json/schema/context.c +78 -0
  21. data/ext/fast_json/schema/error.c +26 -0
  22. data/ext/fast_json/schema/error.h +5 -0
  23. data/ext/fast_json/schema/extconf.rb +7 -0
  24. data/ext/fast_json/schema/formats/custom_format.c +63 -0
  25. data/ext/fast_json/schema/formats/custom_format.h +4 -0
  26. data/ext/fast_json/schema/formats/date.c +48 -0
  27. data/ext/fast_json/schema/formats/date.h +5 -0
  28. data/ext/fast_json/schema/formats/date_time.c +22 -0
  29. data/ext/fast_json/schema/formats/date_time.h +4 -0
  30. data/ext/fast_json/schema/formats/email.c +8 -0
  31. data/ext/fast_json/schema/formats/email.h +4 -0
  32. data/ext/fast_json/schema/formats/format.c +68 -0
  33. data/ext/fast_json/schema/formats/format.h +4 -0
  34. data/ext/fast_json/schema/formats/hostname.c +8 -0
  35. data/ext/fast_json/schema/formats/hostname.h +4 -0
  36. data/ext/fast_json/schema/formats/idn_email.c +8 -0
  37. data/ext/fast_json/schema/formats/idn_email.h +4 -0
  38. data/ext/fast_json/schema/formats/idn_hostname.c +8 -0
  39. data/ext/fast_json/schema/formats/idn_hostname.h +4 -0
  40. data/ext/fast_json/schema/formats/ipv4.c +8 -0
  41. data/ext/fast_json/schema/formats/ipv4.h +4 -0
  42. data/ext/fast_json/schema/formats/ipv6.c +8 -0
  43. data/ext/fast_json/schema/formats/ipv6.h +4 -0
  44. data/ext/fast_json/schema/formats/iri.c +8 -0
  45. data/ext/fast_json/schema/formats/iri.h +4 -0
  46. data/ext/fast_json/schema/formats/iri_reference.c +8 -0
  47. data/ext/fast_json/schema/formats/iri_reference.h +4 -0
  48. data/ext/fast_json/schema/formats/json_pointer.c +8 -0
  49. data/ext/fast_json/schema/formats/json_pointer.h +4 -0
  50. data/ext/fast_json/schema/formats/regex.c +27 -0
  51. data/ext/fast_json/schema/formats/regex.h +4 -0
  52. data/ext/fast_json/schema/formats/relative_json_pointer.c +57 -0
  53. data/ext/fast_json/schema/formats/relative_json_pointer.h +4 -0
  54. data/ext/fast_json/schema/formats/time.c +65 -0
  55. data/ext/fast_json/schema/formats/time.h +5 -0
  56. data/ext/fast_json/schema/formats/uri.c +8 -0
  57. data/ext/fast_json/schema/formats/uri.h +4 -0
  58. data/ext/fast_json/schema/formats/uri_reference.c +8 -0
  59. data/ext/fast_json/schema/formats/uri_reference.h +4 -0
  60. data/ext/fast_json/schema/formats/uri_template.c +8 -0
  61. data/ext/fast_json/schema/formats/uri_template.h +4 -0
  62. data/ext/fast_json/schema/formats/utils/addr_spec_parser.c +342 -0
  63. data/ext/fast_json/schema/formats/utils/addr_spec_parser.h +16 -0
  64. data/ext/fast_json/schema/formats/utils/hostname_parser.c +113 -0
  65. data/ext/fast_json/schema/formats/utils/hostname_parser.h +17 -0
  66. data/ext/fast_json/schema/formats/utils/ip_parser.c +126 -0
  67. data/ext/fast_json/schema/formats/utils/ip_parser.h +25 -0
  68. data/ext/fast_json/schema/formats/utils/json_pointer_parser.c +45 -0
  69. data/ext/fast_json/schema/formats/utils/json_pointer_parser.h +20 -0
  70. data/ext/fast_json/schema/formats/utils/uri_parser.c +605 -0
  71. data/ext/fast_json/schema/formats/utils/uri_parser.h +20 -0
  72. data/ext/fast_json/schema/formats/utils/uri_template_parser.c +235 -0
  73. data/ext/fast_json/schema/formats/utils/uri_template_parser.h +18 -0
  74. data/ext/fast_json/schema/formats/utils/utf8.c +73 -0
  75. data/ext/fast_json/schema/formats/utils/utf8.h +17 -0
  76. data/ext/fast_json/schema/if.c +31 -0
  77. data/ext/fast_json/schema/if.h +4 -0
  78. data/ext/fast_json/schema/is_valid.c +124 -0
  79. data/ext/fast_json/schema/is_valid.h +6 -0
  80. data/ext/fast_json/schema/keywords.c +220 -0
  81. data/ext/fast_json/schema/keywords.h +60 -0
  82. data/ext/fast_json/schema/nested_schemas.c +68 -0
  83. data/ext/fast_json/schema/nested_schemas.h +4 -0
  84. data/ext/fast_json/schema/not.c +11 -0
  85. data/ext/fast_json/schema/not.h +4 -0
  86. data/ext/fast_json/schema/one_of.c +23 -0
  87. data/ext/fast_json/schema/one_of.h +4 -0
  88. data/ext/fast_json/schema/path.c +44 -0
  89. data/ext/fast_json/schema/path.h +5 -0
  90. data/ext/fast_json/schema/properties_val.c +103 -0
  91. data/ext/fast_json/schema/properties_val.h +6 -0
  92. data/ext/fast_json/schema/ref.c +7 -0
  93. data/ext/fast_json/schema/ref.h +4 -0
  94. data/ext/fast_json/schema/ref_resolver.c +85 -0
  95. data/ext/fast_json/schema/ref_resolver.h +5 -0
  96. data/ext/fast_json/schema/schema.c +68 -0
  97. data/ext/fast_json/schema/schema_collection.c +29 -0
  98. data/ext/fast_json/schema/schema_collection.h +3 -0
  99. data/ext/fast_json/schema/types/compiled_schema.h +96 -0
  100. data/ext/fast_json/schema/types/context.h +27 -0
  101. data/ext/fast_json/schema/validate.c +63 -0
  102. data/ext/fast_json/schema/validate.h +19 -0
  103. data/ext/fast_json/schema/validate_array.c +130 -0
  104. data/ext/fast_json/schema/validate_array.h +4 -0
  105. data/ext/fast_json/schema/validate_bool.c +7 -0
  106. data/ext/fast_json/schema/validate_bool.h +4 -0
  107. data/ext/fast_json/schema/validate_integer.c +52 -0
  108. data/ext/fast_json/schema/validate_integer.h +4 -0
  109. data/ext/fast_json/schema/validate_null.c +7 -0
  110. data/ext/fast_json/schema/validate_null.h +4 -0
  111. data/ext/fast_json/schema/validate_number.c +62 -0
  112. data/ext/fast_json/schema/validate_number.h +4 -0
  113. data/ext/fast_json/schema/validate_object.c +159 -0
  114. data/ext/fast_json/schema/validate_object.h +4 -0
  115. data/ext/fast_json/schema/validate_string.c +32 -0
  116. data/ext/fast_json/schema/validate_string.h +4 -0
  117. data/ext/fast_json/schema/value_pointer_caster.h +9 -0
  118. data/fast_json-schema.gemspec +31 -0
  119. data/lib/fast_json/schema/error.rb +16 -0
  120. data/lib/fast_json/schema/version.rb +7 -0
  121. data/lib/fast_json/schema.rb +50 -0
  122. data/makefile +10 -0
  123. 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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ bool set_custom_format_validation_function_for_compiled_schema(CompiledSchema *, VALUE, VALUE);
@@ -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,5 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ bool parse_full_date(const char *s, long len);
5
+ void validate_format_date(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_date_time(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_email(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void set_format_validation_function_for_compiled_schema(CompiledSchema *, VALUE, VALUE);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_hostname(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_idn_email(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_idn_hostname(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_ipv4(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_ipv6(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_iri(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_iri_reference(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_json_pointer(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_regex(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_relative_json_pointer(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,5 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ bool parse_full_time(const char *s, long len);
5
+ void validate_format_time(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_uri(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_uri_reference(VALUE, CompiledSchema *, VALUE, Context *);
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ #include <ruby.h>
2
+ #include "types/compiled_schema.h"
3
+
4
+ void validate_format_uri_template(VALUE, CompiledSchema *, VALUE, Context *);