ext/yajl/yajl_ext.c in yajl-ruby-1.1.0 vs ext/yajl/yajl_ext.c in yajl-ruby-1.2.0

- old
+ new

@@ -52,10 +52,29 @@ } } } } +static char *yajl_raise_encode_error_for_status(yajl_gen_status status, VALUE obj) { + switch (status) { + case yajl_gen_keys_must_be_strings: + rb_raise(cEncodeError, "YAJL internal error: attempted use of non-string object as key"); + case yajl_max_depth_exceeded: + rb_raise(cEncodeError, "Max nesting depth of %d exceeded", YAJL_MAX_DEPTH); + case yajl_gen_in_error_state: + rb_raise(cEncodeError, "YAJL internal error: a generator function (yajl_gen_XXX) was called while in an error state"); + case yajl_gen_generation_complete: + rb_raise(cEncodeError, "YAJL internal error: attempted to encode to an already-complete document"); + case yajl_gen_invalid_number: + rb_raise(cEncodeError, "Invalid number: cannot encode Infinity, -Infinity, or NaN"); + case yajl_gen_no_buf: + rb_raise(cEncodeError, "YAJL internal error: yajl_gen_get_buf was called, but a print callback was specified, so no internal buffer is available"); + default: + return NULL; + } +} + static void yajl_set_static_value(void * ctx, VALUE val) { yajl_parser_wrapper * wrapper; VALUE lastEntry, hash; int len; @@ -94,14 +113,14 @@ static void yajl_encoder_wrapper_free(void * wrapper) { yajl_encoder_wrapper * w = wrapper; if (w) { if (w->indentString) { - free(w->indentString); + xfree(w->indentString); } yajl_gen_free(w->encoder); - free(w); + xfree(w); } } static void yajl_encoder_wrapper_mark(void * wrapper) { yajl_encoder_wrapper * w = wrapper; @@ -109,10 +128,13 @@ rb_gc_mark(w->on_progress_callback); rb_gc_mark(w->terminator); } } +#define CHECK_STATUS(call) \ + if ((status = (call)) != yajl_gen_status_ok) { break; } + void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) { VALUE str, outBuff, otherObj; yajl_encoder_wrapper * w = wrapper; yajl_gen_status status; int idx = 0; @@ -121,10 +143,13 @@ unsigned int len; VALUE keys, entry, keyStr; if (io != Qnil || w->on_progress_callback != Qnil) { status = yajl_gen_get_buf(w->encoder, &buffer, &len); + if (status != yajl_gen_status_ok) { + yajl_raise_encode_error_for_status(status, obj); + } if (len >= WRITE_BUFSIZE) { outBuff = rb_str_new((const char *)buffer, len); if (io != Qnil) { rb_io_write(io, outBuff); } else if (w->on_progress_callback != Qnil) { @@ -134,11 +159,11 @@ } } switch (TYPE(obj)) { case T_HASH: - status = yajl_gen_map_open(w->encoder); + CHECK_STATUS(yajl_gen_map_open(w->encoder)); /* TODO: itterate through keys in the hash */ keys = rb_funcall(obj, intern_keys, 0); for(idx=0; idx<RARRAY_LEN(keys); idx++) { entry = rb_ary_entry(keys, idx); @@ -147,68 +172,73 @@ yajl_encode_part(w, keyStr, io); /* the value */ yajl_encode_part(w, rb_hash_aref(obj, entry), io); } - status = yajl_gen_map_close(w->encoder); + CHECK_STATUS(yajl_gen_map_close(w->encoder)); break; case T_ARRAY: - status = yajl_gen_array_open(w->encoder); + CHECK_STATUS(yajl_gen_array_open(w->encoder)); for(idx=0; idx<RARRAY_LEN(obj); idx++) { otherObj = rb_ary_entry(obj, idx); yajl_encode_part(w, otherObj, io); } - status = yajl_gen_array_close(w->encoder); + CHECK_STATUS(yajl_gen_array_close(w->encoder)); break; case T_NIL: - status = yajl_gen_null(w->encoder); + CHECK_STATUS(yajl_gen_null(w->encoder)); break; case T_TRUE: - status = yajl_gen_bool(w->encoder, 1); + CHECK_STATUS(yajl_gen_bool(w->encoder, 1)); break; case T_FALSE: - status = yajl_gen_bool(w->encoder, 0); + CHECK_STATUS(yajl_gen_bool(w->encoder, 0)); break; case T_FIXNUM: case T_FLOAT: case T_BIGNUM: str = rb_funcall(obj, intern_to_s, 0); cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); if (memcmp(cptr, "NaN", 3) == 0 || memcmp(cptr, "Infinity", 8) == 0 || memcmp(cptr, "-Infinity", 9) == 0) { rb_raise(cEncodeError, "'%s' is an invalid number", cptr); } - status = yajl_gen_number(w->encoder, cptr, len); + CHECK_STATUS(yajl_gen_number(w->encoder, cptr, len)); break; case T_STRING: cptr = RSTRING_PTR(obj); len = RSTRING_LEN(obj); - status = yajl_gen_string(w->encoder, (const unsigned char *)cptr, len); + CHECK_STATUS(yajl_gen_string(w->encoder, (const unsigned char *)cptr, len)); break; default: if (rb_respond_to(obj, intern_to_json)) { str = rb_funcall(obj, intern_to_json, 0); Check_Type(str, T_STRING); cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); - status = yajl_gen_number(w->encoder, cptr, len); + CHECK_STATUS(yajl_gen_number(w->encoder, cptr, len)); } else { str = rb_funcall(obj, intern_to_s, 0); Check_Type(str, T_STRING); cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); - status = yajl_gen_string(w->encoder, (const unsigned char *)cptr, len); + CHECK_STATUS(yajl_gen_string(w->encoder, (const unsigned char *)cptr, len)); } break; } + + if (status != yajl_gen_status_ok) { + yajl_raise_encode_error_for_status(status, obj); + rb_raise(cEncodeError, "Encountered unknown YAJL status %d during JSON generation", status); + } } void yajl_parser_wrapper_free(void * wrapper) { yajl_parser_wrapper * w = wrapper; if (w) { yajl_free(w->parser); - free(w); + xfree(w); } } void yajl_parser_wrapper_mark(void * wrapper) { yajl_parser_wrapper * w = wrapper; @@ -382,11 +412,11 @@ allowComments = 0; } if (rb_hash_aref(opts, sym_check_utf8) == Qfalse) { checkUTF8 = 0; } - if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) { + if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue || rb_hash_aref(opts, sym_symbolize_names) == Qtrue) { symbolizeKeys = 1; } } cfg = (yajl_parser_config){allowComments, checkUTF8}; @@ -572,11 +602,11 @@ if (indent != Qnil) { #ifdef HAVE_RUBY_ENCODING_H indent = rb_str_export_to_enc(indent, utf8Encoding); #endif Check_Type(indent, T_STRING); - indentString = (unsigned char*)malloc(RSTRING_LEN(indent)+1); + indentString = (unsigned char*)xmalloc(RSTRING_LEN(indent)+1); memcpy(indentString, RSTRING_PTR(indent), RSTRING_LEN(indent)); indentString[RSTRING_LEN(indent)] = '\0'; actualIndent = indentString; } } @@ -861,10 +891,12 @@ /* Ruby Extension initializer */ void Init_yajl() { mYajl = rb_define_module("Yajl"); + rb_define_const(mYajl, "MAX_DEPTH", INT2NUM(YAJL_MAX_DEPTH)); + cParseError = rb_define_class_under(mYajl, "ParseError", rb_eStandardError); cEncodeError = rb_define_class_under(mYajl, "EncodeError", rb_eStandardError); cParser = rb_define_class_under(mYajl, "Parser", rb_cObject); rb_define_singleton_method(cParser, "new", rb_yajl_parser_new, -1); @@ -896,9 +928,10 @@ sym_pretty = ID2SYM(rb_intern("pretty")); sym_indent = ID2SYM(rb_intern("indent")); sym_html_safe = ID2SYM(rb_intern("html_safe")); sym_terminator = ID2SYM(rb_intern("terminator")); sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys")); + sym_symbolize_names = ID2SYM(rb_intern("symbolize_names")); #ifdef HAVE_RUBY_ENCODING_H utf8Encoding = rb_utf8_encoding(); #endif }