summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/deps/mruby-iijson
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/.gitignore1
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml2
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/README.md87
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake6
-rwxr-xr-xweb/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb129
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb47
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb23
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/src/json.c641
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb145
-rw-r--r--web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c11
10 files changed, 1092 insertions, 0 deletions
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 <ctype.h>
+#include <inttypes.h>
+#include <string.h>
+
+#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));
+}