From be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 04:57:58 +0200 Subject: Adding upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/deps/mruby-iijson/.gitignore | 1 + .../h2o/libh2o/deps/mruby-iijson/.travis.yml | 2 + web/server/h2o/libh2o/deps/mruby-iijson/README.md | 87 +++ .../h2o/libh2o/deps/mruby-iijson/mrbgem.rake | 6 + .../h2o/libh2o/deps/mruby-iijson/mrblib/json.rb | 129 +++++ .../h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb | 47 ++ .../h2o/libh2o/deps/mruby-iijson/run_test.rb | 23 + web/server/h2o/libh2o/deps/mruby-iijson/src/json.c | 641 +++++++++++++++++++++ .../h2o/libh2o/deps/mruby-iijson/test/json.rb | 145 +++++ .../h2o/libh2o/deps/mruby-iijson/test/testjson.c | 11 + 10 files changed, 1092 insertions(+) create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/.gitignore create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/README.md create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake create mode 100755 web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/src/json.c create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb create mode 100644 web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c (limited to 'web/server/h2o/libh2o/deps/mruby-iijson') diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore b/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore new file mode 100644 index 00000000..ceeb05b4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml b/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml new file mode 100644 index 00000000..ffe22728 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/README.md b/web/server/h2o/libh2o/deps/mruby-iijson/README.md new file mode 100644 index 00000000..bbbfeba6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/README.md @@ -0,0 +1,87 @@ +# mruby-iijson +[![Build Status](https://travis-ci.org/iij/mruby-iijson.svg?branch=master)](https://travis-ci.org/iij/mruby-iijson) + +"mruby-iijson" is JSON module for mruby. + + +## Implemented Methods: + - [JSON.dump](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-dump) + - [JSON.generate](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-generate) + - [JSON.load](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-load) + - [JSON.parse](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-parse) + - `Array#to_json`, `Fixnum#to_json`, `Float#to_json`, `Hash#to_json`, `String#to_json`, ... + +## Example: + +```Ruby +str = '{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } +}' +p JSON.parse(str) + +h = { + :precision => "zip", + :Latitude => 37.7668, + :Longitude => -122.3959, + :Address => "", + :City => "SAN FRANCISCO", + :State => "CA", + :Zip => "94107", + :Country => "US" +} +p h.to_json +puts JSON.generate(h, {:pretty_print => true, :indent_with => 2}) +``` + +``` +{"Image"=>{"Width"=>800, "Height"=>600, "Title"=>"View from 15th Floor", "Thumbnail"=>{"Url"=>"http://www.example.com/image/481989943", "Height"=>125, "Width"=>"100"}, "IDs"=>[116, 943, 234, 38793]}} +"{\"precision\":\"zip\",\"Latitude\":37.766800000000003,\"Longitude\":-122.3959,\"Address\":\"\",\"City\":\"SAN FRANCISCO\",\"State\":\"CA\",\"Zip\":\"94107\",\"Country\":\"US\"}" +{ + "precision": "zip", + "Latitude": 37.766800000000003, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" +} +``` + + +## Caveats + + - JSON.generate won't return if input Array/Hash has circular reference. + + +## License + +Copyright (c) 2014 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake new file mode 100644 index 00000000..fef1c3dd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-iijson') do |spec| + spec.license = 'MIT' + spec.author = 'Internet Initiative Japan Inc.' + + spec.add_dependency "mruby-sprintf", :core => "mruby-sprintf" +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb new file mode 100755 index 00000000..87b5a6bd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb @@ -0,0 +1,129 @@ +module JSON + def self.dump(object, io=nil, limit=nil) + state = {} + state[:max_nesting] = limit if limit + begin + js = JSON.generate(object, nil, state) + rescue JSON::NestingError + raise ArgumentError, "exceeded depth limit" + end + if io + io.write js + io + else + js + end + end + + def self.generate(obj, options=nil, state=nil) + options = (options || {}).to_hash unless options.is_a? Hash + options[:pretty_print] ||= false + options[:indent_with] ||= 2 + state = (state || {}).to_hash unless state.is_a? Hash + state[:max_nesting] ||= 100 + state[:nesting] = 0 + self.generate0(obj, options, state) + end + + def self.generate0(obj, options, state) + if state[:nesting] >= state[:max_nesting] + raise JSON::NestingError, "nesting of #{state[:nesting]} is too deep" + end + + pretty = options[:pretty_print] + + if pretty + indent = options[:indent_with].class == Fixnum ? " " * options[:indent_with] : options[:indent_with] + else + indent = "" + end + + nl = pretty ? "\n" : "" + + if obj == false + return "false" + + elsif obj == nil + return "null" + + elsif obj == true + return "true" + + elsif obj.is_a? Hash + members = [] + state[:nesting] += 1 + obj.each { |k, v| + members << JSON.generate0(k, options, state) + ":" + (pretty ? " " : "") + JSON.generate0(v, options, state) + } + if pretty + members.map! { |k| (indent * state[:nesting]) + "#{k}" }.join("_") + end + state[:nesting] -= 1 + return "{" + nl + members.join("," + nl) + nl + (indent * state[:nesting]) + "}" + + elsif obj.is_a? Array + state[:nesting] += 1 + members = obj.map { |v| JSON.generate0(v, options, state) } + if pretty + members.map! { |k| (indent * state[:nesting]) + "#{k}" }.join("_") + end + state[:nesting] -= 1 + return "[" + nl + members.join("," + nl) + nl + (indent * state[:nesting]) + "]" + + elsif obj.is_a? Fixnum + return obj.to_s + + elsif obj.is_a? Float + if obj.infinite? or obj.nan? + raise GeneratorError, "#{obj.to_s} not allowed in JSON" + end + sprintf "%.17g", obj + + else + a = [] + obj.to_s.each_char { |ch| + a << if ch < "\x20" + case ch + when "\x08" + "\\b" + when "\x0c" + "\\f" + when "\x0a" + "\\n" + when "\x0d" + "\\r" + when "\x09" + "\\t" + else + raise GeneratorError, "cannot convert #{ch.inspect} to JSON" + end + elsif ch == '"' + '\\"' + elsif ch == '\\' + "\\\\" + else + ch + end + } + return '"' + a.join + '"' + end + end + + def self.load(source) # TODO: proc, options + source = source.read unless source.is_a? String + JSON.parse source + end + + class JSONError < StandardError; end + class GeneratorError < JSONError; end + class ParserError < JSONError; end + class NestingError < ParserError; end +end + +unless Float.method_defined? :nan? + class Float + def nan? + not (self == self) + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb new file mode 100644 index 00000000..ee97ac2c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb @@ -0,0 +1,47 @@ +class Array + def to_json + JSON.generate(self) + end +end + +class FalseClass + def to_json + JSON.generate(self) + end +end + +class Fixnum + def to_json + JSON.generate(self) + end +end + +class Float + def to_json + JSON.generate(self) + end +end + +class Hash + def to_json + JSON.generate(self) + end +end + +class NilClass + def to_json + JSON.generate(self) + end +end + +class String + def to_json + JSON.generate(self) + end +end + +class TrueClass + def to_json + JSON.generate(self) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb b/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb new file mode 100644 index 00000000..dece5070 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c b/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c new file mode 100644 index 00000000..6836e090 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c @@ -0,0 +1,641 @@ +#include +#include +#include + +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/hash.h" +#include "mruby/string.h" +#include "mruby/value.h" + +#define E_JSON_PARSER_ERROR (mrb_class_get_under(mrb, mrb_module_get(mrb, "JSON"), "ParserError")) + +#define JSON_EOF -1 + +#define DEFAULT_MAX_NESTING 100 + +struct json_parser { + mrb_state *mrb; + mrb_value src; + unsigned int cursor; + unsigned int lineno; + int nesting; + + int max_nesting; +}; + +static void json_check_nesting(struct json_parser *); +static int json_delimiter_p(char ch); +static int json_getc(struct json_parser *); +static void json_skip_ws(struct json_parser *); +static void json_ungetc(struct json_parser *); +static int json_unicode2utf8(uint32_t, char *); +static int json_whitespace_p(char ch); + +static int json_parse_array(struct json_parser *, mrb_value *); +static int json_parse_object(struct json_parser *, mrb_value *); +static int json_parse_number2(struct json_parser *, int, mrb_value *, mrb_int, int); +static int json_parse_string(struct json_parser *, mrb_value *); +static int json_parse_value(struct json_parser *, mrb_value *); + +#if MRUBY_RELEASE_NO < 10000 +static struct RClass * +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get(mrb, name); +} +#endif +#if !defined(MRB_PRId) +#if defined(MRB_INT64) +# define MRB_PRId PRId64 +#elif defined(MRB_INT16) +# define MRB_PRId PRId16 +#else +# define MRB_PRId PRId32 +#endif +#endif /* !defined(MRB_PRId) */ + +static void +json_check_nesting(struct json_parser *parser) +{ + mrb_state *mrb = parser->mrb; + + if (parser->max_nesting != -1) { + if (parser->nesting >= parser->max_nesting) { + // +1 for compatibility with CRuby + mrb_raisef(mrb, E_JSON_PARSER_ERROR, "nesting of %S is too deep", mrb_fixnum_value(parser->nesting+1)); + } + } +} + +static int +json_delimiter_p(char ch) +{ + return (json_whitespace_p(ch) || ch == ',' || ch == ']' || ch == '}'); +} + +static int +json_getc(struct json_parser *parser) +{ + if (parser->cursor < RSTRING_LEN(parser->src)) { + unsigned char ch = RSTRING_PTR(parser->src)[parser->cursor]; + parser->cursor++; + return ch; + } else { + return JSON_EOF; + } +} + +static int +json_parse_readstring(struct json_parser *parser, const char *str) +{ + size_t len; + int ch; + + len = strlen(str); + if (parser->cursor + len > RSTRING_LEN(parser->src)) + return 0; + if (memcmp(str, RSTRING_PTR(parser->src) + parser->cursor, len) != 0) + return -1; + parser->cursor += len; + if (parser->cursor == RSTRING_LEN(parser->src)) + return 1; + ch = RSTRING_PTR(parser->src)[parser->cursor]; + if (!json_delimiter_p(ch)) + return -1; + return 1; +} + +static void +json_skip_ws(struct json_parser *parser) +{ + int ch; + + do { + ch = json_getc(parser); + if (ch == 0x0a) + parser->lineno++; + } while (json_whitespace_p(ch)); + if (ch != JSON_EOF) { + json_ungetc(parser); + } +} + +static void +json_ungetc(struct json_parser *parser) +{ + if (parser->cursor > 0) + parser->cursor--; +} + +static int +json_unicode2utf8(uint32_t unicode, char *cp) +{ + int n = 0; + if (unicode < 0x80) { + cp[n++] = unicode; + } else if (unicode < 0x800) { + cp[n++] = 0xc0 + (unicode >> 6); + cp[n++] = 0x80 + (unicode & 0x3f); + } else if (unicode < 0x10000) { + cp[n++] = 0xe0 + (unicode >> 12); + cp[n++] = 0x80 + ((unicode >> 6) & 0x3f); + cp[n++] = 0x80 + (unicode & 0x3f); + } else { + cp[n++] = 0xf0 + (unicode >> 18); + cp[n++] = 0x80 + ((unicode >> 12) & 0x3f); + cp[n++] = 0x80 + ((unicode >> 6) & 0x3f); + cp[n++] = 0x80 + (unicode & 0x3f); + } + return n; +} + +static int +json_whitespace_p(char ch) +{ + return (ch == 0x20 || ch == 0x09 || ch == 0x0a || ch == 0x0d); +} + +static int +json_parse_array(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value ary, v; + int ch; + + json_check_nesting(parser); + + ary = mrb_ary_new(mrb); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == ']') { /* easy case */ + *result = ary; + return 1; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "JSON_EOF in array(1)"); + } + json_ungetc(parser); + + while (1) { + parser->nesting++; + if (json_parse_value(parser, &v) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in array"); + } + parser->nesting--; + + mrb_ary_push(mrb, ary, v); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == ']') { + break; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "JSON_EOF in array(2)"); + } + if (ch != ',') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "not ',' in array"); + } + } + *result = ary; + return 1; +} + +static int +json_parse_object(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value h, k, v; + int ch; + + json_check_nesting(parser); + + h = mrb_hash_new(mrb); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == '}') { /* easy case */ + *result = h; + return 1; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(1)"); + } + json_ungetc(parser); + + while (1) { + parser->nesting++; + if (json_parse_value(parser, &k) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in object key"); + } + parser->nesting--; + if (! mrb_string_p(k)) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "key is not a string"); + } + + json_skip_ws(parser); + + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(2)"); + } + if (ch != ':') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no ':' in object"); + } + + parser->nesting++; + if (json_parse_value(parser, &v) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in object value"); + } + parser->nesting--; + + mrb_hash_set(mrb, h, k, v); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == '}') { + break; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(3)"); + } + if (ch != ',') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no ',' in object"); + } + } + *result = h; + return 1; +} + +static int +json_parse_number(struct json_parser *parser, int ch, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_int num; + int d, sign; + + if (ch == '-') { + sign = -1; + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no character following minus"); + } + if (!isdigit(ch)) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "character following minus is not a digit"); + } + } else { + sign = 1; + } + num = (ch - '0') * sign; + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + break; + } + if (isdigit(ch)) { + if (num == 0) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "leading zeros are not allowed"); + } + d = (ch - '0') * sign; + if (num < MRB_INT_MIN / 10 || + (num == MRB_INT_MIN / 10 && d < MRB_INT_MIN - num * 10) || + num > MRB_INT_MAX / 10 || + (num == MRB_INT_MAX / 10 && d > MRB_INT_MAX - num * 10)) { + return json_parse_number2(parser, ch, result, num, sign); + } + num = num * 10 + d; + } else if (ch == '.' || ch == 'e' || ch == 'E') { + return json_parse_number2(parser, ch, result, num, sign); + } else if (json_delimiter_p(ch)) { + json_ungetc(parser); + break; + } else { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid number"); + } + } + *result = mrb_fixnum_value(num); + return 1; +} + +static int +json_parse_number2(struct json_parser *parser, int ch, mrb_value *result, mrb_int num, int sign) +{ + mrb_state *mrb = parser->mrb; + double d; + int i, state; + char buf[64]; + + /* + * "-"? ("0" | [1-9] digit* ) ("." digit+ )? ([eE][-+] digit+)? + * state: 000000 111 222222 33334444 555555 + */ + i = snprintf(buf, sizeof(buf), "%s%"MRB_PRId"%c", + (num == 0 && sign < 0) ? "-" : "", + num, ch); + + if (isdigit(ch)) + state = 0; + else if (ch == '.') + state = 1; + else /* (ch == 'e' || ch == 'E') */ + state = 3; + + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) + break; + switch (state) { + case 0: + if (isdigit(ch)) + ; /* read more digits */ + else if (ch == '.') + state = 1; + else if (ch == 'e' || ch == 'E') + state = 3; + else if (json_delimiter_p(ch)) { + json_ungetc(parser); + state = -1; + } else + goto formaterr; + break; + case 1: + if (!isdigit(ch)) + goto formaterr; + state = 2; + break; + case 2: + if (isdigit(ch)) + ; /* read more digits */ + else if (ch == 'e' || ch == 'E') + state = 3; + else if (json_delimiter_p(ch)) { + json_ungetc(parser); + state = -1; + } else + goto formaterr; + break; + case 3: + if (ch == '-' || ch == '+') + state = 4; + else if (isdigit(ch)) + state = 5; + else + goto formaterr; + break; + case 4: + if (!isdigit(ch)) + goto formaterr; + state = 5; + break; + case 5: + default: + if (isdigit(ch)) + ; /* read more digits */ + else { + json_ungetc(parser); + state = -1; + } + break; + } + if (state == -1) + break; + if (i == sizeof(buf) - 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "floating point number too long"); + } + buf[i++] = ch; + } + buf[i] = '\0'; + sscanf(buf, "%lf", &d); + *result = mrb_float_value(mrb, d); + return 1; + +formaterr: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "floating point number error"); + return -1; +} + +static int +json_parse_string(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value str; + uint32_t unicode; + uint16_t utf16; + int ch, i, n; + char *cp; + + str = mrb_str_buf_new(mrb, 30); + cp = RSTRING_PTR(str); + n = 0; + unicode = 0; + + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in string"); + } + + if (ch == '"') { + break; + } else if (ch == '\\') { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF following escape char"); + } + switch (ch) { + case '"': + case '\\': + case '/': + break; + case 'b': + ch = 0x08; + break; + case 'f': + ch = 0x0c; + break; + case 'n': + ch = 0x0a; + break; + case 'r': + ch = 0x0d; + break; + case 't': + ch = 0x09; + break; + case 'u': + utf16 = 0; + for (i = 0; i < 4; i++) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid unicode escape"); + } + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'A' && ch <= 'F') { + ch = (ch - 'A') + 10; + } else if (ch >= 'a' && ch <= 'f') { + ch = (ch - 'a') + 10; + } else { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid unicode character"); + } + utf16 *= 16; + utf16 += ch; + } + + if (n + 8 >= RSTRING_CAPA(str)) { + mrb_str_resize(mrb, str, RSTRING_CAPA(str)*2); + cp = RSTRING_PTR(str); + } + + if ((utf16 & 0xf800) == 0xd800) { + if ((utf16 & 0xfc00) == 0xd800) { + /* high surrogate */ + unicode = utf16; + continue; + } else { + /* low surrogate */ + if (unicode > 0) { + unicode = ((unicode & 0x03ff) + 0x040) << 10; + unicode += utf16 & 0x03ff; + } else { + /* error: low surrogate comes first... */ + } + } + } else { + if (unicode > 0) { + /* error: high surrogate not followed by low surrogate */ + n += json_unicode2utf8(unicode, &cp[n]); + } + unicode = utf16; + } + + n += json_unicode2utf8(unicode, &cp[n]); + unicode = 0; + continue; + default: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid escape char"); + break; + } + } else if (ch < 0x20) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid char"); + } + + if (n + 1 == RSTRING_CAPA(str)) { + mrb_str_resize(mrb, str, RSTRING_CAPA(str)*2); + cp = RSTRING_PTR(str); + } + cp[n++] = ch; + } + cp[n] = '\0'; + mrb_str_resize(mrb, str, n); + *result = str; + return 1; +} + +static int +json_parse_value(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + int ch; + + do { + ch = json_getc(parser); + if (ch == JSON_EOF) + return 0; + } while (json_whitespace_p(ch)); + + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': + if (json_parse_number(parser, ch, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "number...?"); + } + break; + + case '"': + if (json_parse_string(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "string...?"); + } + break; + + case '[': + if (json_parse_array(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "array...?"); + } + break; + + case '{': + if (json_parse_object(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "object...?"); + } + break; + + case 'f': + if (json_parse_readstring(parser, "alse") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected f"); + } + *result = mrb_false_value(); + break; + + case 'n': + if (json_parse_readstring(parser, "ull") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected n"); + } + *result = mrb_nil_value(); + break; + + case 't': + if (json_parse_readstring(parser, "rue") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected t"); + } + *result = mrb_true_value(); + break; + + default: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected character"); + } + + return 1; +} + +static mrb_value +mrb_json_parse(mrb_state *mrb, mrb_value mod) +{ + struct json_parser parser; + mrb_value obj, options, source; + + mrb_get_args(mrb, "S|H", &source, &options); + + parser.mrb = mrb; + parser.src = source; + parser.cursor = 0; + parser.lineno = 0; + parser.nesting = 0; + parser.max_nesting = DEFAULT_MAX_NESTING; + + if (json_parse_value(&parser, &obj) == 0) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no JSON value"); + } + + // if we have extra characters: + // unexpected token at '3' (JSON::ParserError) + + return obj; +} + +void +mrb_mruby_iijson_gem_init(mrb_state *mrb) +{ + struct RClass *m; + + m = mrb_define_module(mrb, "JSON"); + mrb_define_module_function(mrb, m, "parse", mrb_json_parse, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); +} + +void +mrb_mruby_iijson_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb new file mode 100644 index 00000000..5b1e759c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb @@ -0,0 +1,145 @@ +assert('JSON.dump') do + class JsonTestIo + def initialize + @buf = "" + end + def write(str) + @buf += str + end + attr_reader :buf + end + assert_equal "[1]", JSON.dump([1]) + + jio = JsonTestIo.new + JSON.dump(["abc"], jio) + assert_equal '["abc"]', jio.buf + + assert_raise(ArgumentError) do + JSON.dump({:a => {:b => {} } }, nil, 2) + end + JSON.dump({:a=>{:b=>{}}}, nil, 3) # should not raise +end + +assert('JSON.generate: false') do + assert_equal "false", JSON.generate(false) +end + +assert('JSON.generate: null') do + assert_equal "null", JSON.generate(nil) +end + +assert('JSON.generate: true') do + assert_equal "true", JSON.generate(true) +end + +assert('JSON.generate: object') do + assert_equal '{"key":"value"}', JSON.generate({ "key" => "value" }) + assert_equal '{"ten":10}', JSON.generate({ :ten => 10 }) +end + +assert('JSON.generate: array') do + assert_equal '[null,1,"two"]', JSON.generate([ nil, 1, "two"]) +end + +assert('JSON.generate: number (Fixnum)') do + str = JSON.generate [1] + assert_equal "[1]", str +end + +assert('JSON.generate: number (Float)') do + str = JSON.generate [134.625] + assert_equal "[134.625]", str +end + +assert('JSON.generate: string') do + assert_equal "\"abc\"", JSON.generate("abc") + assert_equal "\"\\\"\\\\/\\b\\f\\n\\r\\t\"", + JSON.generate("\x22\x5c\x2f\x08\x0c\x0a\x0d\x09") +end + +assert('JSON.load') do + assert_equal [1,2,3], JSON.load("[1,2,3]") + + class JsonTestReader + def read + '{"abc":123}' + end + end + assert_equal({"abc"=>123}, JSON.load(JsonTestReader.new)) +end + +assert('JSON.parse: text from RFC4726') do + str = '{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } + }' + hash = { + "Image" => { + "Width" => 800, + "Height" => 600, + "Title" => "View from 15th Floor", + "Thumbnail" => { + "Url" => "http://www.example.com/image/481989943", + "Height" => 125, + "Width" => "100" + }, + "IDs" => [116, 943, 234, 38793] + } + } + assert_equal hash, JSON.parse(str) + + # We cannot compare `str` with `JSON.generate(hash)` because Hash entries + # will be in a random order. + assert_equal hash, JSON.parse(JSON.generate(hash)) +end + +assert('JSON::ParserError') do + assert_raise(JSON::ParserError) do + JSON.parse "[xxx]" + end +end + +assert('JSON.parse: empty string is not a valid JSON text') do + assert_raise(JSON::ParserError) do + JSON.parse "" + end +end + +assert('JSON.parse: parsing numbers around MRB_INT_MIN/MRB_INT_MAX') do + int_min = TestJSON::MRB_INT_MIN + int_max = TestJSON::MRB_INT_MAX + + assert_kind_of Fixnum, JSON.load(int_min.to_s) + assert_equal int_min, JSON.load(int_min.to_s) + + assert_kind_of Fixnum, JSON.load(int_max.to_s) + assert_equal int_max, JSON.load(int_max.to_s) + + assert_kind_of Float, JSON.load((int_min-1).to_s) + assert_float (int_min-1)/int_min, JSON.load((int_min-1).to_s)/int_min + + assert_kind_of Float, JSON.load((int_max+1).to_s) + assert_float (int_max+1)/int_max, JSON.load((int_max+1).to_s)/int_max +end + +assert('#to_json') do + assert_equal 'false', false.to_json + assert_equal 'null', nil.to_json + assert_equal 'true', true.to_json + assert_equal '1', 1.to_json + assert_equal '3.125', 3.125.to_json + assert_equal '"str"', "str".to_json + assert_equal '["one",2]', [ "one", 2 ].to_json + assert_equal '{"a":1}', { "a" => 1 }.to_json + assert_equal TestJSON::MRB_INT_MIN.to_s, TestJSON::MRB_INT_MIN.to_json + assert_equal TestJSON::MRB_INT_MAX.to_s, TestJSON::MRB_INT_MAX.to_json +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c b/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c new file mode 100644 index 00000000..f254e8bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c @@ -0,0 +1,11 @@ +#include "mruby.h" +#include "mruby/value.h" +#include "mruby/variable.h" + +void +mrb_mruby_iijson_gem_test(mrb_state* mrb) +{ + struct RClass *c = mrb_define_module(mrb, "TestJSON"); + mrb_const_set(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "MRB_INT_MIN"), mrb_fixnum_value(MRB_INT_MIN)); + mrb_const_set(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "MRB_INT_MAX"), mrb_fixnum_value(MRB_INT_MAX)); +} -- cgit v1.2.3