static FBuffer *cState_prepare_buffer(VALUE self) { FBuffer *buffer; GET_STATE(self); buffer = fbuffer_alloc(state->buffer_initial_length); if (state->object_delim) { fbuffer_clear(state->object_delim); } else { state->object_delim = fbuffer_alloc(16); } fbuffer_append_char(state->object_delim, ','); if (state->object_delim2) { fbuffer_clear(state->object_delim2); } else { state->object_delim2 = fbuffer_alloc(16); } fbuffer_append_char(state->object_delim2, ':'); if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len); if (state->array_delim) { fbuffer_clear(state->array_delim); } else { state->array_delim = fbuffer_alloc(16); } fbuffer_append_char(state->array_delim, ','); if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len); return buffer; }
static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) { char *array_nl = state->array_nl; long array_nl_len = state->array_nl_len; char *indent = state->indent; long indent_len = state->indent_len; long max_nesting = state->max_nesting; char *delim = FBUFFER_PTR(state->array_delim); long delim_len = FBUFFER_LEN(state->array_delim); long depth = ++state->depth; int i, j; if (max_nesting != 0 && depth > max_nesting) { fbuffer_free(buffer); rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); } fbuffer_append_char(buffer, '['); if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len); for(i = 0; i < RARRAY_LEN(obj); i++) { if (i > 0) fbuffer_append(buffer, delim, delim_len); if (indent) { for (j = 0; j < depth; j++) { fbuffer_append(buffer, indent, indent_len); } } generate_json(buffer, Vstate, state, rb_ary_entry(obj, i)); } state->depth = --depth; if (array_nl) { fbuffer_append(buffer, array_nl, array_nl_len); if (indent) { for (j = 0; j < depth; j++) { fbuffer_append(buffer, indent, indent_len); } } } fbuffer_append_char(buffer, ']'); }
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) { char *object_nl = state->object_nl; long object_nl_len = state->object_nl_len; char *indent = state->indent; long indent_len = state->indent_len; long max_nesting = state->max_nesting; char *delim = FBUFFER_PTR(state->object_delim); long delim_len = FBUFFER_LEN(state->object_delim); char *delim2 = FBUFFER_PTR(state->object_delim2); long delim2_len = FBUFFER_LEN(state->object_delim2); long depth = ++state->depth; int i, j; VALUE key, key_to_s, keys; if (max_nesting != 0 && depth > max_nesting) { fbuffer_free(buffer); rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); } fbuffer_append_char(buffer, '{'); keys = rb_funcall(obj, i_keys, 0); for(i = 0; i < RARRAY_LEN(keys); i++) { if (i > 0) fbuffer_append(buffer, delim, delim_len); if (object_nl) { fbuffer_append(buffer, object_nl, object_nl_len); } if (indent) { for (j = 0; j < depth; j++) { fbuffer_append(buffer, indent, indent_len); } } key = rb_ary_entry(keys, i); key_to_s = rb_funcall(key, i_to_s, 0); Check_Type(key_to_s, T_STRING); generate_json(buffer, Vstate, state, key_to_s); fbuffer_append(buffer, delim2, delim2_len); generate_json(buffer, Vstate, state, rb_hash_aref(obj, key)); } depth = --state->depth; if (object_nl) { fbuffer_append(buffer, object_nl, object_nl_len); if (indent) { for (j = 0; j < depth; j++) { fbuffer_append(buffer, indent, indent_len); } } } fbuffer_append_char(buffer, '}'); }
/* Converts string to a JSON string in FBuffer buffer, where only the * characters required by the JSON standard are JSON escaped. The remaining * characters (should be UTF8) are just passed through and appended to the * result. */ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) { const char *ptr = RSTRING_PTR(string), *p; int len = RSTRING_LEN(string), start = 0, end = 0; const char *escape = NULL; int escape_len; unsigned char c; char buf[6] = { '\\', 'u' }; for (start = 0, end = 0; end < len;) { p = ptr + end; c = (unsigned char) *p; if (c < 0x20) { switch (c) { case '\n': escape = "\\n"; escape_len = 2; break; case '\r': escape = "\\r"; escape_len = 2; break; case '\t': escape = "\\t"; escape_len = 2; break; case '\f': escape = "\\f"; escape_len = 2; break; case '\b': escape = "\\b"; escape_len = 2; break; default: unicode_escape(buf, (UTF16) *p); escape = buf; escape_len = 6; break; } } else { switch (c) { case '\\': escape = "\\\\"; escape_len = 2; break; case '"': escape = "\\\""; escape_len = 2; break; default: end++; continue; break; } } fbuffer_append(buffer, ptr + start, end - start); fbuffer_append(buffer, escape, escape_len); start = ++end; escape = NULL; } fbuffer_append(buffer, ptr + start, end - start); }
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII * and control characters are JSON escaped. */ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string) { const UTF8 *source = (UTF8 *) RSTRING_PTR(string); const UTF8 *sourceEnd = source + RSTRING_LEN(string); char buf[6] = { '\\', 'u' }; while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { rb_raise(rb_path2class("JSON::GeneratorError"), "partial character in source, but hit end"); } if (!isLegalUTF8(source, extraBytesToRead+1)) { rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8"); } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { #if UNI_STRICT_CONVERSION source -= (extraBytesToRead+1); /* return to the illegal value itself */ rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8"); #else unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR); #endif } else { /* normal case */ if (ch >= 0x20 && ch <= 0x7f) { switch (ch) { case '\\': fbuffer_append(buffer, "\\\\", 2); break; case '"': fbuffer_append(buffer, "\\\"", 2); break; default: fbuffer_append_char(buffer, (char)ch); break; } } else { switch (ch) { case '\n': fbuffer_append(buffer, "\\n", 2); break; case '\r': fbuffer_append(buffer, "\\r", 2); break; case '\t': fbuffer_append(buffer, "\\t", 2); break; case '\f': fbuffer_append(buffer, "\\f", 2); break; case '\b': fbuffer_append(buffer, "\\b", 2); break; default: unicode_escape_to_buffer(buffer, buf, (UTF16) ch); break; } } } } else if (ch > UNI_MAX_UTF16) { #if UNI_STRICT_CONVERSION source -= (extraBytesToRead+1); /* return to the start */ rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf8"); #else unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR); #endif } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ ch -= halfBase; unicode_escape_to_buffer(buffer, buf, (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START)); unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START)); } } }
/* Escapes the UTF16 character and stores the result in the buffer buf, then * the buffer buf іs appended to the FBuffer buffer. */ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character) { unicode_escape(buf, character); fbuffer_append(buffer, buf, 6); }
static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) { fbuffer_append(buffer, "true", 4); }
static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) { fbuffer_append(buffer, "false", 5); }
/* Converts string to a JSON string in FBuffer buffer, where only the * characters required by the JSON standard are JSON escaped. The remaining * characters (should be UTF8) are just passed through and appended to the * result. */ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) { const char *ptr = RSTRING_PTR(string), *p; unsigned long len = RSTRING_LEN(string), start = 0, end = 0; const char *escape = NULL; int escape_len; unsigned char c; char buf[6] = { '\\', 'u' }; for (start = 0, end = 0; end < len;) { p = ptr + end; c = (unsigned char) *p; if (c < 0x20) { switch (c) { case '\n': escape = "\\n"; escape_len = 2; break; case '\r': escape = "\\r"; escape_len = 2; break; case '\t': escape = "\\t"; escape_len = 2; break; case '\f': escape = "\\f"; escape_len = 2; break; case '\b': escape = "\\b"; escape_len = 2; break; default: unicode_escape(buf, (UTF16) *p); escape = buf; escape_len = 6; break; } } else { switch (c) { case '\\': escape = "\\\\"; escape_len = 2; break; case '"': escape = "\\\""; escape_len = 2; break; default: { unsigned short clen = trailingBytesForUTF8[c] + 1; if (end + clen > len) { rb_raise(rb_path2class("JSON::GeneratorError"), "partial character in source, but hit end"); } if (!isLegalUTF8((UTF8 *) p, clen)) { rb_raise(rb_path2class("JSON::GeneratorError"), "source sequence is illegal/malformed utf-8"); } end += clen; } continue; break; } } fbuffer_append(buffer, ptr + start, end - start); fbuffer_append(buffer, escape, escape_len); start = ++end; escape = NULL; } fbuffer_append(buffer, ptr + start, end - start); }