1 #include "../fbuffer/fbuffer.h" 4 #ifdef HAVE_RUBY_ENCODING_H 5 static VALUE CEncoding_UTF_8;
6 static ID i_encoding, i_encode;
9 static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
11 #ifdef RUBY_INTEGER_UNIFICATION 16 mFloat, mString, mString_Extend,
17 mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18 eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
19 i_SAFE_STATE_PROTOTYPE;
21 static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22 i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23 i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24 i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25 i_buffer_initial_length, i_dup;
56 static const char trailingBytesForUTF8[256] = {
57 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
58 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
59 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
60 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
61 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
62 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
63 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
64 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
72 static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
73 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
85 static unsigned char isLegalUTF8(
const UTF8 *source,
unsigned long length)
88 const UTF8 *srcptr = source+length;
92 case 4:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return 0;
93 case 3:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return 0;
94 case 2:
if ((a = (*--srcptr)) > 0xBF)
return 0;
98 case 0xE0:
if (a < 0xA0)
return 0;
break;
99 case 0xED:
if (a > 0x9F)
return 0;
break;
100 case 0xF0:
if (a < 0x90)
return 0;
break;
101 case 0xF4:
if (a > 0x8F)
return 0;
break;
102 default:
if (a < 0x80)
return 0;
105 case 1:
if (*source >= 0x80 && *source < 0xC2)
return 0;
107 if (*source > 0xF4)
return 0;
112 static void unicode_escape(
char *
buf,
UTF16 character)
114 const char *digits =
"0123456789abcdef";
116 buf[2] = digits[character >> 12];
117 buf[3] = digits[(character >> 8) & 0xf];
118 buf[4] = digits[(character >> 4) & 0xf];
119 buf[5] = digits[character & 0xf];
124 static void unicode_escape_to_buffer(
FBuffer *buffer,
char buf[6],
UTF16 127 unicode_escape(buf, character);
128 fbuffer_append(buffer, buf, 6);
133 static void convert_UTF8_to_JSON_ASCII(
FBuffer *buffer,
VALUE string)
137 char buf[6] = {
'\\',
'u' };
139 while (source < sourceEnd) {
141 unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
142 if (source + extraBytesToRead >= sourceEnd) {
144 "partial character in source, but hit end");
146 if (!isLegalUTF8(source, extraBytesToRead+1)) {
148 "source sequence is illegal/malformed utf-8");
153 switch (extraBytesToRead) {
154 case 5: ch += *source++; ch <<= 6;
155 case 4: ch += *source++; ch <<= 6;
156 case 3: ch += *source++; ch <<= 6;
157 case 2: ch += *source++; ch <<= 6;
158 case 1: ch += *source++; ch <<= 6;
159 case 0: ch += *source++;
161 ch -= offsetsFromUTF8[extraBytesToRead];
166 #if UNI_STRICT_CONVERSION 167 source -= (extraBytesToRead+1);
169 "source sequence is illegal/malformed utf-8");
175 if (ch >= 0x20 && ch <= 0x7f) {
178 fbuffer_append(buffer,
"\\\\", 2);
181 fbuffer_append(buffer,
"\\\"", 2);
184 fbuffer_append_char(buffer, (
char)ch);
190 fbuffer_append(buffer,
"\\n", 2);
193 fbuffer_append(buffer,
"\\r", 2);
196 fbuffer_append(buffer,
"\\t", 2);
199 fbuffer_append(buffer,
"\\f", 2);
202 fbuffer_append(buffer,
"\\b", 2);
205 unicode_escape_to_buffer(buffer, buf, (
UTF16) ch);
211 #if UNI_STRICT_CONVERSION 212 source -= (extraBytesToRead+1);
214 "source sequence is illegal/malformed utf8");
232 static void convert_UTF8_to_JSON(
FBuffer *buffer,
VALUE string)
236 const char *escape =
NULL;
239 char buf[6] = {
'\\',
'u' };
241 for (start = 0, end = 0; end <
len;) {
243 c = (
unsigned char) *p;
267 unicode_escape(buf, (
UTF16) *p);
284 unsigned short clen = trailingBytesForUTF8[c] + 1;
285 if (end + clen > len) {
287 "partial character in source, but hit end");
289 if (!isLegalUTF8((
UTF8 *) p, clen)) {
291 "source sequence is illegal/malformed utf-8");
299 fbuffer_append(buffer, ptr + start, end - start);
300 fbuffer_append(buffer, escape, escape_len);
304 fbuffer_append(buffer, ptr + start, end - start);
307 static char *fstrndup(
const char *ptr,
unsigned long len) {
309 if (len <= 0)
return NULL;
311 memcpy(result, ptr, len);
352 #ifdef RUBY_INTEGER_UNIFICATION 425 static VALUE mString_to_json_raw_object(
VALUE self)
443 VALUE obj = mString_to_json_raw_object(
self);
445 return mHash_to_json(argc, argv, obj);
505 state = cState_from_state_s(cState, state);
506 return cState_partial_generate(state,
string);
509 static void State_free(
void *ptr)
523 static size_t State_memsize(
const void *ptr)
526 size_t size =
sizeof(*state);
538 #ifdef NEW_TYPEDDATA_WRAPPER 540 "JSON/Generator/State",
541 {
NULL, State_free, State_memsize,},
542 #ifdef RUBY_TYPED_FREE_IMMEDIATELY 553 &JSON_Generator_State_type, state);
609 tmp =
ID2SYM(i_max_nesting);
613 if (
RTEST(max_nesting)) {
631 tmp =
ID2SYM(i_buffer_initial_length);
634 if (
RTEST(buffer_initial_length)) {
637 initial_length =
FIX2LONG(buffer_initial_length);
648 static void set_state_ivars(
VALUE hash,
VALUE state)
670 set_state_ivars(result,
self);
711 return rb_funcall(
self, i_send, 2, name_writer, value);
722 char *indent = state->
indent;
729 long depth = ++state->
depth;
732 if (max_nesting != 0 && depth > max_nesting) {
733 fbuffer_free(buffer);
734 rb_raise(eNestingError,
"nesting of %ld is too deep", --state->
depth);
736 fbuffer_append_char(buffer,
'{');
739 if (i > 0) fbuffer_append(buffer, delim, delim_len);
741 fbuffer_append(buffer, object_nl, object_nl_len);
744 for (j = 0; j < depth; j++) {
745 fbuffer_append(buffer, indent, indent_len);
751 generate_json(buffer, Vstate, state, key_to_s);
752 fbuffer_append(buffer, delim2, delim2_len);
753 generate_json(buffer, Vstate, state,
rb_hash_aref(obj, key));
755 depth = --state->
depth;
757 fbuffer_append(buffer, object_nl, object_nl_len);
759 for (j = 0; j < depth; j++) {
760 fbuffer_append(buffer, indent, indent_len);
764 fbuffer_append_char(buffer,
'}');
771 char *indent = state->
indent;
776 long depth = ++state->
depth;
778 if (max_nesting != 0 && depth > max_nesting) {
779 fbuffer_free(buffer);
780 rb_raise(eNestingError,
"nesting of %ld is too deep", --state->
depth);
782 fbuffer_append_char(buffer,
'[');
783 if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len);
785 if (i > 0) fbuffer_append(buffer, delim, delim_len);
787 for (j = 0; j < depth; j++) {
788 fbuffer_append(buffer, indent, indent_len);
791 generate_json(buffer, Vstate, state,
rb_ary_entry(obj, i));
793 state->
depth = --depth;
795 fbuffer_append(buffer, array_nl, array_nl_len);
797 for (j = 0; j < depth; j++) {
798 fbuffer_append(buffer, indent, indent_len);
802 fbuffer_append_char(buffer,
']');
807 fbuffer_append_char(buffer,
'"');
808 #ifdef HAVE_RUBY_ENCODING_H 809 obj =
rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
812 convert_UTF8_to_JSON_ASCII(buffer, obj);
814 convert_UTF8_to_JSON(buffer, obj);
816 fbuffer_append_char(buffer,
'"');
821 fbuffer_append(buffer,
"null", 4);
826 fbuffer_append(buffer,
"false", 5);
831 fbuffer_append(buffer,
"true", 4);
836 fbuffer_append_long(buffer,
FIX2LONG(obj));
842 fbuffer_append_str(buffer, tmp);
845 #ifdef RUBY_INTEGER_UNIFICATION 849 generate_json_fixnum(buffer, Vstate, state, obj);
851 generate_json_bignum(buffer, Vstate, state, obj);
861 fbuffer_free(buffer);
863 }
else if (
isnan(value)) {
864 fbuffer_free(buffer);
868 fbuffer_append_str(buffer, tmp);
876 generate_json_object(buffer, Vstate, state, obj);
878 generate_json_array(buffer, Vstate, state, obj);
880 generate_json_string(buffer, Vstate, state, obj);
881 }
else if (obj ==
Qnil) {
882 generate_json_null(buffer, Vstate, state, obj);
883 }
else if (obj ==
Qfalse) {
884 generate_json_false(buffer, Vstate, state, obj);
885 }
else if (obj ==
Qtrue) {
886 generate_json_true(buffer, Vstate, state, obj);
888 generate_json_fixnum(buffer, Vstate, state, obj);
890 generate_json_bignum(buffer, Vstate, state, obj);
892 generate_json_float(buffer, Vstate, state, obj);
896 fbuffer_append_str(buffer, tmp);
900 generate_json_string(buffer, Vstate, state, tmp);
937 FBuffer *buffer = cState_prepare_buffer(
self);
939 generate_json(buffer,
self, state, obj);
940 return fbuffer_to_s(buffer);
952 VALUE result = cState_partial_generate(
self, obj);
983 if (!
NIL_P(opts)) cState_configure(
self, opts);
997 if (obj == orig)
return obj;
1028 if (
NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1029 CJSON_SAFE_STATE_PROTOTYPE =
rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1031 return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1224 static VALUE cState_check_circular_p(
VALUE self)
1309 static VALUE cState_buffer_initial_length(
VALUE self)
1321 static VALUE cState_buffer_initial_length_set(
VALUE self,
VALUE buffer_initial_length)
1323 long initial_length;
1326 initial_length =
FIX2LONG(buffer_initial_length);
1327 if (initial_length > 0) {
1369 rb_define_method(cState,
"buffer_initial_length", cState_buffer_initial_length, 0);
1370 rb_define_method(cState,
"buffer_initial_length=", cState_buffer_initial_length_set, 1);
1386 #ifdef RUBY_INTEGER_UNIFICATION 1401 rb_define_method(mString,
"to_json_raw_object", mString_to_json_raw_object, 0);
1403 rb_define_method(mString_Extend,
"json_create", mString_Extend_json_create, 1);
1417 i_space_before =
rb_intern(
"space_before");
1420 i_max_nesting =
rb_intern(
"max_nesting");
1424 i_buffer_initial_length =
rb_intern(
"buffer_initial_length");
1432 i_respond_to_p =
rb_intern(
"respond_to?");
1436 #ifdef HAVE_RUBY_ENCODING_H 1441 i_SAFE_STATE_PROTOTYPE =
rb_intern(
"SAFE_STATE_PROTOTYPE");
1442 CJSON_SAFE_STATE_PROTOTYPE =
Qnil;
RUBY_EXTERN VALUE rb_cString
VALUE rb_ary_entry(VALUE ary, long offset)
RUBY_EXTERN VALUE rb_cFloat
#define RUBY_TYPED_FREE_IMMEDIATELY
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
void rb_raise(VALUE exc, const char *fmt,...)
#define option_given_p(opts, key)
VALUE rb_str_concat(VALUE, VALUE)
#define RB_OBJ_STRING(obj)
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
VALUE rb_iv_get(VALUE, const char *)
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_ivar_get(VALUE, ID)
void Init_generator(void)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Tries to convert an object into another type.
VALUE rb_path2class(const char *)
#define FBUFFER_INITIAL_LENGTH_DEFAULT
long buffer_initial_length
VALUE rb_obj_class(VALUE)
call-seq: obj.class -> class
#define RB_TYPE_P(obj, type)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
call-seq: obj.is_a?(class) -> true or false obj.kind_of?(class) -> true or false
VALUE rb_require(const char *)
#define rb_intern_str(string)
VALUE rb_class_name(VALUE)
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
VALUE rb_str_substr(VALUE, long, long)
RUBY_EXTERN VALUE rb_cObject
VALUE rb_str_cat2(VALUE, const char *)
#define MEMCPY(p1, p2, type, n)
RUBY_EXTERN int isinf(double)
VALUE rb_const_get(VALUE, ID)
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
RUBY_EXTERN VALUE rb_cRegexp
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
VALUE rb_ivar_set(VALUE, ID, VALUE)
unsigned char buf[MIME_BUF_SIZE]
#define UNI_SUR_HIGH_START
int rb_respond_to(VALUE, ID)
register unsigned int len
VALUE rb_define_module_under(VALUE outer, const char *name)
#define StringValueCStr(v)
#define GENERATE_JSON(type)
VALUE rb_hash_aref(VALUE hash, VALUE key)
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
#define GET_STATE_TO(self, state)
#define TypedData_Make_Struct(klass, type, data_type, sval)
#define UNI_SUR_LOW_START
#define UNI_REPLACEMENT_CHAR
VALUE rb_str_intern(VALUE)
VALUE rb_define_module(const char *name)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
#define rb_obj_instance_variables(object)
VALUE rb_str_new(const char *, long)