#include #include #include #include "../flydata.h" extern "C" { #ifdef _WIN32 _declspec(dllexport) #endif void Init_json_ext(); } inline void add_json_value(const char* buf, long buf_len, bool quote, std::stringstream& ss) { if (quote) { ss.put('\"'); } const char* ptr = 0; long len = 0; const char* esc_str = 0; for (long i = 0; i < buf_len; i++) { if (!ptr) { ptr = buf + i; len = 0; } switch (buf[i]) { case '\"': esc_str = "\\\""; case '\\': esc_str = "\\\\"; case '/': esc_str = "\\/"; case '\b': esc_str = "\\b"; case '\f': esc_str = "\\f"; case '\n': esc_str = "\\n"; case '\r': esc_str = "\\r"; case '\t': esc_str = "\\t"; if (len > 0) { ss.write(ptr, len); } ss.write(esc_str, 2); ptr = 0; len = 0; break; default: len++; break; } } if (len > 0) { ss.write(ptr, len); } if (quote) { ss.put('\"'); } } inline void add_json_value(VALUE value, std::stringstream& ss) { switch(TYPE(value)) { case T_STRING: add_json_value(RSTRING_PTR(value), RSTRING_LEN(value), true, ss); break; case T_NIL: add_json_value("null", 4, false, ss); break; case T_TRUE: add_json_value("true", 4, false, ss); break; case T_FALSE: add_json_value("false", 5, false, ss); break; default: VALUE v = rb_funcall(value, rb_intern("to_s"), 0); add_json_value(RSTRING_PTR(v), RSTRING_LEN(v), true, ss); break; } } inline void add_kv_pair(VALUE key, VALUE value, std::stringstream& ss) { if (TYPE(key) != T_STRING) { key = rb_funcall(key, rb_intern("to_s"), 0); } add_json_value(key, ss); ss.put(':'); add_json_value(value, ss); } static VALUE rb_json_generate_kv_pairs(VALUE self, VALUE key_ary, VALUE value_ary) { long key_len = RARRAY_LEN(key_ary); long value_len = RARRAY_LEN(value_ary); if (key_len != value_len) { rb_raise(rb_eArgError, "length of arrays must match"); } std::stringstream ss; ss << "{"; for (long i = 0; i < key_len; i++) { if (i > 0) { ss << ","; } VALUE key = rb_ary_entry(key_ary, i); VALUE value = rb_ary_entry(value_ary, i); add_kv_pair(key, value, ss); } ss << "}"; std::string str = ss.str(); VALUE json = rb_str_new(str.data(), str.size()); int enc = rb_enc_find_index("UTF-8"); rb_enc_associate_index(json, enc); return json; } void Init_json_ext() { VALUE mJSON = rb_define_module("JSON"); rb_define_singleton_method(mJSON, "generate_kv_pairs", __F(&rb_json_generate_kv_pairs), 2); }