Permalink
Browse files

getting SAJ ready for release

  • Loading branch information...
1 parent 87a7a73 commit cbe5b91c3507b33a3d7d7d1d6fef3db8c83c4d43 @ohler55 committed Dec 17, 2012
Showing with 1,443 additions and 44 deletions.
  1. +0 −1 ext/oj/cache.c
  2. +93 −1 ext/oj/oj.c
  3. +9 −0 ext/oj/oj.h
  4. +762 −0 ext/oj/saj.c
  5. +391 −0 ext/oj/tp.x
  6. +1 −0 lib/oj.rb
  7. +5 −42 notes
  8. +102 −0 test/perf_saj.rb
  9. +80 −0 test/test_saj.rb
View
@@ -51,7 +51,6 @@ oj_cache_new(Cache *cache) {
}
(*cache)->key = 0;
(*cache)->value = Qundef;
- //bzero((*cache)->slots, sizeof((*cache)->slots));
memset((*cache)->slots, 0, sizeof((*cache)->slots));
}
View
@@ -65,6 +65,12 @@ ID oj_tv_usec_id;
ID oj_utc_offset_id;
ID oj_write_id;
+ID oj_hash_start_id;
+ID oj_hash_end_id;
+ID oj_array_start_id;
+ID oj_array_end_id;
+ID oj_add_value_id;
+
VALUE oj_bag_class;
VALUE oj_parse_error_class;
VALUE oj_bigdecimal_class;
@@ -416,7 +422,6 @@ load_with_opts(VALUE input, Options copts) {
rb_raise(rb_eArgError, "load() expected a String or IO Object.");
}
}
- // TBD pick SAJ or normal
obj = oj_parse(json, copts);
if (copts->max_stack < len) {
xfree(json);
@@ -544,6 +549,85 @@ to_file(int argc, VALUE *argv, VALUE self) {
return Qnil;
}
+/* call-seq: saj_parse(handler, io)
+ *
+ * Parses an IO stream or file containing an JSON document. Raises an exception
+ * if the JSON is malformed.
+ * @param [Oj::Saj] handler SAJ (responds to Oj::Saj methods) like handler
+ * @param [IO|String] io IO Object to read from
+ */
+static VALUE
+saj_parse(int argc, VALUE *argv, VALUE self) {
+ struct _Options copts = oj_default_options;
+ char *json;
+ size_t len;
+ VALUE input = argv[1];
+
+ if (argc < 2) {
+ rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
+ }
+ if (rb_type(input) == T_STRING) {
+ // the json string gets modified so make a copy of it
+ len = RSTRING_LEN(input) + 1;
+ if (copts.max_stack < len) {
+ json = ALLOC_N(char, len);
+ } else {
+ json = ALLOCA_N(char, len);
+ }
+ strcpy(json, StringValuePtr(input));
+ } else {
+ VALUE clas = rb_obj_class(input);
+ VALUE s;
+
+ if (oj_stringio_class == clas) {
+ s = rb_funcall2(input, oj_string_id, 0, 0);
+ len = RSTRING_LEN(s) + 1;
+ if (copts.max_stack < len) {
+ json = ALLOC_N(char, len);
+ } else {
+ json = ALLOCA_N(char, len);
+ }
+ strcpy(json, StringValuePtr(s));
+#ifndef JRUBY_RUBY
+#if !IS_WINDOWS
+ // JRuby gets confused with what is the real fileno.
+ } else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
+ int fd = FIX2INT(s);
+ ssize_t cnt;
+
+ len = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+ if (copts.max_stack < len) {
+ json = ALLOC_N(char, len + 1);
+ } else {
+ json = ALLOCA_N(char, len + 1);
+ }
+ if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
+ }
+ json[len] = '\0';
+#endif
+#endif
+ } else if (rb_respond_to(input, oj_read_id)) {
+ s = rb_funcall2(input, oj_read_id, 0, 0);
+ len = RSTRING_LEN(s) + 1;
+ if (copts.max_stack < len) {
+ json = ALLOC_N(char, len);
+ } else {
+ json = ALLOCA_N(char, len);
+ }
+ strcpy(json, StringValuePtr(s));
+ } else {
+ rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
+ }
+ }
+ oj_saj_parse(*argv, json);
+ if (copts.max_stack < len) {
+ xfree(json);
+ }
+ return Qnil;
+}
+
// Mimic JSON section
static VALUE
@@ -881,6 +965,8 @@ void Init_oj() {
rb_define_module_function(Oj, "dump", dump, -1);
rb_define_module_function(Oj, "to_file", to_file, -1);
+ rb_define_module_function(Oj, "saj_parse", saj_parse, -1);
+
oj_as_json_id = rb_intern("as_json");
oj_fileno_id = rb_intern("fileno");
oj_instance_variables_id = rb_intern("instance_variables");
@@ -899,6 +985,12 @@ void Init_oj() {
oj_utc_offset_id = rb_intern("utc_offset");
oj_write_id = rb_intern("write");
+ oj_hash_start_id = rb_intern("hash_start");
+ oj_hash_end_id = rb_intern("hash_end");
+ oj_array_start_id = rb_intern("array_start");
+ oj_array_end_id = rb_intern("array_end");
+ oj_add_value_id = rb_intern("add_value");
+
oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
View
@@ -144,6 +144,8 @@ typedef struct _Leaf {
} *Leaf;
extern VALUE oj_parse(char *json, Options options);
+extern void oj_saj_parse(VALUE handler, char *json);
+
extern char* oj_write_obj_to_str(VALUE obj, Options copts);
extern void oj_write_obj_to_file(VALUE obj, const char *path, Options copts);
extern char* oj_write_leaf_to_str(Leaf leaf, Options copts);
@@ -164,6 +166,7 @@ extern rb_encoding *oj_utf8_encoding;
extern VALUE oj_bag_class;
extern VALUE oj_bigdecimal_class;
extern VALUE oj_doc_class;
+extern VALUE oj_parse_error_class;
extern VALUE oj_stringio_class;
extern VALUE oj_struct_class;
extern VALUE oj_time_class;
@@ -185,6 +188,12 @@ extern ID oj_tv_sec_id;
extern ID oj_tv_usec_id;
extern ID oj_utc_offset_id;
+extern ID oj_hash_start_id;
+extern ID oj_hash_end_id;
+extern ID oj_array_start_id;
+extern ID oj_array_end_id;
+extern ID oj_add_value_id;
+
extern Cache oj_class_cache;
extern Cache oj_attr_cache;
Oops, something went wrong.

0 comments on commit cbe5b91

Please sign in to comment.