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
}