diff options
Diffstat (limited to 'ext/json/generator')
-rw-r--r-- | ext/json/generator/depend | 41 | ||||
-rw-r--r-- | ext/json/generator/generator.c | 149 | ||||
-rw-r--r-- | ext/json/generator/generator.h | 13 |
3 files changed, 155 insertions, 48 deletions
diff --git a/ext/json/generator/depend b/ext/json/generator/depend index 6787d492ca..f47e5f3a70 100644 --- a/ext/json/generator/depend +++ b/ext/json/generator/depend @@ -5,6 +5,20 @@ generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h generator.o: $(RUBY_EXTCONF_H) generator.o: $(arch_hdrdir)/ruby/config.h generator.o: $(hdrdir)/ruby.h +generator.o: $(hdrdir)/ruby/assert.h +generator.o: $(hdrdir)/ruby/backward.h +generator.o: $(hdrdir)/ruby/backward/2/assume.h +generator.o: $(hdrdir)/ruby/backward/2/attributes.h +generator.o: $(hdrdir)/ruby/backward/2/bool.h +generator.o: $(hdrdir)/ruby/backward/2/inttypes.h +generator.o: $(hdrdir)/ruby/backward/2/limits.h +generator.o: $(hdrdir)/ruby/backward/2/long_long.h +generator.o: $(hdrdir)/ruby/backward/2/stdalign.h +generator.o: $(hdrdir)/ruby/backward/2/stdarg.h +generator.o: $(hdrdir)/ruby/defines.h +generator.o: $(hdrdir)/ruby/encoding.h +generator.o: $(hdrdir)/ruby/intern.h +generator.o: $(hdrdir)/ruby/internal/abi.h generator.o: $(hdrdir)/ruby/internal/anyargs.h generator.o: $(hdrdir)/ruby/internal/arithmetic.h generator.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -42,6 +56,7 @@ generator.o: $(hdrdir)/ruby/internal/attr/noexcept.h generator.o: $(hdrdir)/ruby/internal/attr/noinline.h generator.o: $(hdrdir)/ruby/internal/attr/nonnull.h generator.o: $(hdrdir)/ruby/internal/attr/noreturn.h +generator.o: $(hdrdir)/ruby/internal/attr/packed_struct.h generator.o: $(hdrdir)/ruby/internal/attr/pure.h generator.o: $(hdrdir)/ruby/internal/attr/restrict.h generator.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h @@ -75,6 +90,15 @@ generator.o: $(hdrdir)/ruby/internal/core/rtypeddata.h generator.o: $(hdrdir)/ruby/internal/ctype.h generator.o: $(hdrdir)/ruby/internal/dllexport.h generator.o: $(hdrdir)/ruby/internal/dosish.h +generator.o: $(hdrdir)/ruby/internal/encoding/coderange.h +generator.o: $(hdrdir)/ruby/internal/encoding/ctype.h +generator.o: $(hdrdir)/ruby/internal/encoding/encoding.h +generator.o: $(hdrdir)/ruby/internal/encoding/pathname.h +generator.o: $(hdrdir)/ruby/internal/encoding/re.h +generator.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +generator.o: $(hdrdir)/ruby/internal/encoding/string.h +generator.o: $(hdrdir)/ruby/internal/encoding/symbol.h +generator.o: $(hdrdir)/ruby/internal/encoding/transcode.h generator.o: $(hdrdir)/ruby/internal/error.h generator.o: $(hdrdir)/ruby/internal/eval.h generator.o: $(hdrdir)/ruby/internal/event.h @@ -102,7 +126,6 @@ generator.o: $(hdrdir)/ruby/internal/intern/enumerator.h generator.o: $(hdrdir)/ruby/internal/intern/error.h generator.o: $(hdrdir)/ruby/internal/intern/eval.h generator.o: $(hdrdir)/ruby/internal/intern/file.h -generator.o: $(hdrdir)/ruby/internal/intern/gc.h generator.o: $(hdrdir)/ruby/internal/intern/hash.h generator.o: $(hdrdir)/ruby/internal/intern/io.h generator.o: $(hdrdir)/ruby/internal/intern/load.h @@ -133,32 +156,18 @@ generator.o: $(hdrdir)/ruby/internal/memory.h generator.o: $(hdrdir)/ruby/internal/method.h generator.o: $(hdrdir)/ruby/internal/module.h generator.o: $(hdrdir)/ruby/internal/newobj.h -generator.o: $(hdrdir)/ruby/internal/rgengc.h generator.o: $(hdrdir)/ruby/internal/scan_args.h generator.o: $(hdrdir)/ruby/internal/special_consts.h generator.o: $(hdrdir)/ruby/internal/static_assert.h generator.o: $(hdrdir)/ruby/internal/stdalign.h generator.o: $(hdrdir)/ruby/internal/stdbool.h +generator.o: $(hdrdir)/ruby/internal/stdckdint.h generator.o: $(hdrdir)/ruby/internal/symbol.h generator.o: $(hdrdir)/ruby/internal/value.h generator.o: $(hdrdir)/ruby/internal/value_type.h generator.o: $(hdrdir)/ruby/internal/variable.h generator.o: $(hdrdir)/ruby/internal/warning_push.h generator.o: $(hdrdir)/ruby/internal/xmalloc.h -generator.o: $(hdrdir)/ruby/assert.h -generator.o: $(hdrdir)/ruby/backward.h -generator.o: $(hdrdir)/ruby/backward/2/assume.h -generator.o: $(hdrdir)/ruby/backward/2/attributes.h -generator.o: $(hdrdir)/ruby/backward/2/bool.h -generator.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -generator.o: $(hdrdir)/ruby/backward/2/inttypes.h -generator.o: $(hdrdir)/ruby/backward/2/limits.h -generator.o: $(hdrdir)/ruby/backward/2/long_long.h -generator.o: $(hdrdir)/ruby/backward/2/stdalign.h -generator.o: $(hdrdir)/ruby/backward/2/stdarg.h -generator.o: $(hdrdir)/ruby/defines.h -generator.o: $(hdrdir)/ruby/encoding.h -generator.o: $(hdrdir)/ruby/intern.h generator.o: $(hdrdir)/ruby/missing.h generator.o: $(hdrdir)/ruby/onigmo.h generator.o: $(hdrdir)/ruby/oniguruma.h diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index e3a83472e1..6d78284bc4 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -16,7 +16,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before, i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only, i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth, - i_buffer_initial_length, i_dup, i_escape_slash; + i_buffer_initial_length, i_dup, i_script_safe, i_escape_slash, i_strict; /* * Copyright 2001-2004 Unicode, Inc. @@ -124,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII * and control characters are JSON escaped. */ -static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash) +static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe) { const UTF8 *source = (UTF8 *) RSTRING_PTR(string); const UTF8 *sourceEnd = source + RSTRING_LEN(string); @@ -175,7 +175,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escap fbuffer_append(buffer, "\\\"", 2); break; case '/': - if(escape_slash) { + if(script_safe) { fbuffer_append(buffer, "\\/", 2); break; } @@ -228,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escap * characters required by the JSON standard are JSON escaped. The remaining * characters (should be UTF8) are just passed through and appended to the * result. */ -static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash) +static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe) { const char *ptr = RSTRING_PTR(string), *p; unsigned long len = RSTRING_LEN(string), start = 0, end = 0; @@ -280,7 +280,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slas escape_len = 2; break; case '/': - if(escape_slash) { + if(script_safe) { escape = "\\/"; escape_len = 2; break; @@ -294,6 +294,22 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slas rb_raise(rb_path2class("JSON::GeneratorError"), "partial character in source, but hit end"); } + + if (script_safe && c == 0xE2) { + unsigned char c2 = (unsigned char) *(p+1); + unsigned char c3 = (unsigned char) *(p+2); + if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9)) { + fbuffer_append(buffer, ptr + start, end - start); + start = end = (end + clen); + if (c3 == 0xA8) { + fbuffer_append(buffer, "\\u2028", 6); + } else { + fbuffer_append(buffer, "\\u2029", 6); + } + continue; + } + } + if (!isLegalUTF8((UTF8 *) p, clen)) { rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8"); @@ -478,6 +494,7 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) */ static VALUE mString_included_s(VALUE self, VALUE modul) { VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend); + rb_call_super(1, &modul); return result; } @@ -726,8 +743,14 @@ static VALUE cState_configure(VALUE self, VALUE opts) state->allow_nan = RTEST(tmp); tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only)); state->ascii_only = RTEST(tmp); - tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash)); - state->escape_slash = RTEST(tmp); + tmp = rb_hash_aref(opts, ID2SYM(i_script_safe)); + state->script_safe = RTEST(tmp); + if (!state->script_safe) { + tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash)); + state->script_safe = RTEST(tmp); + } + tmp = rb_hash_aref(opts, ID2SYM(i_strict)); + state->strict = RTEST(tmp); return self; } @@ -762,7 +785,8 @@ static VALUE cState_to_h(VALUE self) rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse); rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse); rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting)); - rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse); + rb_hash_aset(result, ID2SYM(i_script_safe), state->script_safe ? Qtrue : Qfalse); + rb_hash_aset(result, ID2SYM(i_strict), state->strict ? Qtrue : Qfalse); rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth)); rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length)); return result; @@ -843,7 +867,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg) if (klass == rb_cString) { key_to_s = key; } else if (klass == rb_cSymbol) { - key_to_s = rb_id2str(SYM2ID(key)); + key_to_s = rb_sym2str(key); } else { key_to_s = rb_funcall(key, i_to_s, 0); } @@ -868,7 +892,6 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S struct hash_foreach_arg arg; if (max_nesting != 0 && depth > max_nesting) { - fbuffer_free(buffer); rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); } fbuffer_append_char(buffer, '{'); @@ -903,7 +926,6 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St long depth = ++state->depth; int i, j; if (max_nesting != 0 && depth > max_nesting) { - fbuffer_free(buffer); rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); } fbuffer_append_char(buffer, '['); @@ -947,9 +969,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S } #endif if (state->ascii_only) { - convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash); + convert_UTF8_to_JSON_ASCII(buffer, obj, state->script_safe); } else { - convert_UTF8_to_JSON(buffer, obj, state->escape_slash); + convert_UTF8_to_JSON(buffer, obj, state->script_safe); } fbuffer_append_char(buffer, '"'); } @@ -996,11 +1018,9 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St VALUE tmp = rb_funcall(obj, i_to_s, 0); if (!allow_nan) { if (isinf(value)) { - fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } else if (isnan(value)) { - fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } } fbuffer_append_str(buffer, tmp); @@ -1028,6 +1048,8 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s generate_json_bignum(buffer, Vstate, state, obj); } else if (klass == rb_cFloat) { generate_json_float(buffer, Vstate, state, obj); + } else if (state->strict) { + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj))); } else if (rb_respond_to(obj, i_to_json)) { tmp = rb_funcall(obj, i_to_json, 1, Vstate); Check_Type(tmp, T_STRING); @@ -1070,11 +1092,45 @@ static FBuffer *cState_prepare_buffer(VALUE self) return buffer; } +struct generate_json_data { + FBuffer *buffer; + VALUE vstate; + JSON_Generator_State *state; + VALUE obj; +}; + +static VALUE generate_json_try(VALUE d) +{ + struct generate_json_data *data = (struct generate_json_data *)d; + + generate_json(data->buffer, data->vstate, data->state, data->obj); + + return Qnil; +} + +static VALUE generate_json_rescue(VALUE d, VALUE exc) +{ + struct generate_json_data *data = (struct generate_json_data *)d; + fbuffer_free(data->buffer); + + rb_exc_raise(exc); + + return Qundef; +} + static VALUE cState_partial_generate(VALUE self, VALUE obj) { FBuffer *buffer = cState_prepare_buffer(self); GET_STATE(self); - generate_json(buffer, self, state, obj); + + struct generate_json_data data = { + .buffer = buffer, + .vstate = self, + .state = state, + .obj = obj + }; + rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); + return fbuffer_to_s(buffer); } @@ -1390,27 +1446,58 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth) } /* - * call-seq: escape_slash + * call-seq: script_safe * * If this boolean is true, the forward slashes will be escaped in * the json output. */ -static VALUE cState_escape_slash(VALUE self) +static VALUE cState_script_safe(VALUE self) { GET_STATE(self); - return state->escape_slash ? Qtrue : Qfalse; + return state->script_safe ? Qtrue : Qfalse; } /* - * call-seq: escape_slash=(depth) + * call-seq: script_safe=(enable) * * This sets whether or not the forward slashes will be escaped in * the json output. */ -static VALUE cState_escape_slash_set(VALUE self, VALUE enable) +static VALUE cState_script_safe_set(VALUE self, VALUE enable) +{ + GET_STATE(self); + state->script_safe = RTEST(enable); + return Qnil; +} + +/* + * call-seq: strict + * + * If this boolean is false, types unsupported by the JSON format will + * be serialized as strings. + * If this boolean is true, types unsupported by the JSON format will + * raise a JSON::GeneratorError. + */ +static VALUE cState_strict(VALUE self) +{ + GET_STATE(self); + return state->strict ? Qtrue : Qfalse; +} + +/* + * call-seq: strict=(enable) + * + * This sets whether or not to serialize types unsupported by the + * JSON format as strings. + * If this boolean is false, types unsupported by the JSON format will + * be serialized as strings. + * If this boolean is true, types unsupported by the JSON format will + * raise a JSON::GeneratorError. + */ +static VALUE cState_strict_set(VALUE self, VALUE enable) { GET_STATE(self); - state->escape_slash = RTEST(enable); + state->strict = RTEST(enable); return Qnil; } @@ -1530,9 +1617,15 @@ void Init_generator(void) rb_define_method(cState, "array_nl=", cState_array_nl_set, 1); rb_define_method(cState, "max_nesting", cState_max_nesting, 0); rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1); - rb_define_method(cState, "escape_slash", cState_escape_slash, 0); - rb_define_method(cState, "escape_slash?", cState_escape_slash, 0); - rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1); + rb_define_method(cState, "script_safe", cState_script_safe, 0); + rb_define_method(cState, "script_safe?", cState_script_safe, 0); + rb_define_method(cState, "script_safe=", cState_script_safe_set, 1); + rb_define_alias(cState, "escape_slash", "script_safe"); + rb_define_alias(cState, "escape_slash?", "script_safe?"); + rb_define_alias(cState, "escape_slash=", "script_safe="); + rb_define_method(cState, "strict", cState_strict, 0); + rb_define_method(cState, "strict?", cState_strict, 0); + rb_define_method(cState, "strict=", cState_strict_set, 1); rb_define_method(cState, "check_circular?", cState_check_circular_p, 0); rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0); rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0); @@ -1589,7 +1682,9 @@ void Init_generator(void) i_object_nl = rb_intern("object_nl"); i_array_nl = rb_intern("array_nl"); i_max_nesting = rb_intern("max_nesting"); + i_script_safe = rb_intern("script_safe"); i_escape_slash = rb_intern("escape_slash"); + i_strict = rb_intern("strict"); i_allow_nan = rb_intern("allow_nan"); i_ascii_only = rb_intern("ascii_only"); i_depth = rb_intern("depth"); diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h index 3ebd622554..1a736b84dd 100644 --- a/ext/json/generator/generator.h +++ b/ext/json/generator/generator.h @@ -49,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL; static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length); static void unicode_escape(char *buf, UTF16 character); static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character); -static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash); -static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash); +static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe); +static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe); static char *fstrndup(const char *ptr, unsigned long len); /* ruby api and some helpers */ @@ -72,7 +72,8 @@ typedef struct JSON_Generator_StateStruct { long max_nesting; char allow_nan; char ascii_only; - char escape_slash; + char script_safe; + char strict; long depth; long buffer_initial_length; } JSON_Generator_State; @@ -151,8 +152,10 @@ static VALUE cState_allow_nan_p(VALUE self); static VALUE cState_ascii_only_p(VALUE self); static VALUE cState_depth(VALUE self); static VALUE cState_depth_set(VALUE self, VALUE depth); -static VALUE cState_escape_slash(VALUE self); -static VALUE cState_escape_slash_set(VALUE self, VALUE depth); +static VALUE cState_script_safe(VALUE self); +static VALUE cState_script_safe_set(VALUE self, VALUE depth); +static VALUE cState_strict(VALUE self); +static VALUE cState_strict_set(VALUE self, VALUE strict); static FBuffer *cState_prepare_buffer(VALUE self); #ifndef ZALLOC #define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type))) |