json 2.6.2 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of json might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/BSDL +22 -0
- data/CHANGES.md +144 -17
- data/LEGAL +8 -0
- data/README.md +67 -224
- data/ext/json/ext/fbuffer/fbuffer.h +110 -92
- data/ext/json/ext/generator/extconf.rb +8 -2
- data/ext/json/ext/generator/generator.c +1020 -806
- data/ext/json/ext/parser/extconf.rb +7 -27
- data/ext/json/ext/parser/parser.c +1343 -3212
- data/json.gemspec +48 -52
- data/lib/json/add/bigdecimal.rb +39 -10
- data/lib/json/add/complex.rb +29 -6
- data/lib/json/add/core.rb +1 -1
- data/lib/json/add/date.rb +27 -7
- data/lib/json/add/date_time.rb +26 -9
- data/lib/json/add/exception.rb +25 -7
- data/lib/json/add/ostruct.rb +32 -9
- data/lib/json/add/range.rb +33 -8
- data/lib/json/add/rational.rb +28 -6
- data/lib/json/add/regexp.rb +26 -8
- data/lib/json/add/set.rb +25 -6
- data/lib/json/add/struct.rb +29 -7
- data/lib/json/add/symbol.rb +34 -7
- data/lib/json/add/time.rb +29 -15
- data/lib/json/common.rb +418 -128
- data/lib/json/ext/generator/state.rb +106 -0
- data/lib/json/ext.rb +34 -4
- data/lib/json/generic_object.rb +7 -3
- data/lib/json/truffle_ruby/generator.rb +690 -0
- data/lib/json/version.rb +3 -7
- data/lib/json.rb +25 -21
- metadata +15 -26
- data/VERSION +0 -1
- data/ext/json/ext/generator/depend +0 -1
- data/ext/json/ext/generator/generator.h +0 -174
- data/ext/json/ext/parser/depend +0 -1
- data/ext/json/ext/parser/parser.h +0 -96
- data/ext/json/ext/parser/parser.rl +0 -986
- data/ext/json/extconf.rb +0 -3
- data/lib/json/pure/generator.rb +0 -479
- data/lib/json/pure/parser.rb +0 -337
- data/lib/json/pure.rb +0 -15
- /data/{LICENSE → COPYING} +0 -0
| @@ -1,324 +1,417 @@ | |
| 1 | 
            +
            #include "ruby.h"
         | 
| 1 2 | 
             
            #include "../fbuffer/fbuffer.h"
         | 
| 2 | 
            -
            #include "generator.h"
         | 
| 3 3 |  | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 4 | 
            +
            #include <math.h>
         | 
| 5 | 
            +
            #include <ctype.h>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            /* ruby api and some helpers */
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            typedef struct JSON_Generator_StateStruct {
         | 
| 10 | 
            +
                VALUE indent;
         | 
| 11 | 
            +
                VALUE space;
         | 
| 12 | 
            +
                VALUE space_before;
         | 
| 13 | 
            +
                VALUE object_nl;
         | 
| 14 | 
            +
                VALUE array_nl;
         | 
| 15 | 
            +
                VALUE as_json;
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                long max_nesting;
         | 
| 18 | 
            +
                long depth;
         | 
| 19 | 
            +
                long buffer_initial_length;
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                bool allow_nan;
         | 
| 22 | 
            +
                bool ascii_only;
         | 
| 23 | 
            +
                bool script_safe;
         | 
| 24 | 
            +
                bool strict;
         | 
| 25 | 
            +
            } JSON_Generator_State;
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            #ifndef RB_UNLIKELY
         | 
| 28 | 
            +
            #define RB_UNLIKELY(cond) (cond)
         | 
| 10 29 | 
             
            #endif
         | 
| 11 | 
            -
                         mFloat, mString, mString_Extend,
         | 
| 12 | 
            -
                         mTrueClass, mFalseClass, mNilClass, eGeneratorError,
         | 
| 13 | 
            -
                         eNestingError;
         | 
| 14 30 |  | 
| 15 | 
            -
            static  | 
| 16 | 
            -
                      i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
         | 
| 17 | 
            -
                      i_pack, i_unpack, i_create_id, i_extend, i_key_p,
         | 
| 18 | 
            -
                      i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
         | 
| 19 | 
            -
                      i_buffer_initial_length, i_dup, i_escape_slash;
         | 
| 31 | 
            +
            static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
         | 
| 20 32 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
              | 
| 23 | 
            -
              | 
| 24 | 
            -
             * Disclaimer
         | 
| 25 | 
            -
             *
         | 
| 26 | 
            -
             * This source code is provided as is by Unicode, Inc. No claims are
         | 
| 27 | 
            -
             * made as to fitness for any particular purpose. No warranties of any
         | 
| 28 | 
            -
             * kind are expressed or implied. The recipient agrees to determine
         | 
| 29 | 
            -
             * applicability of information provided. If this file has been
         | 
| 30 | 
            -
             * purchased on magnetic or optical media from Unicode, Inc., the
         | 
| 31 | 
            -
             * sole remedy for any claim will be exchange of defective media
         | 
| 32 | 
            -
             * within 90 days of receipt.
         | 
| 33 | 
            -
             *
         | 
| 34 | 
            -
             * Limitations on Rights to Redistribute This Code
         | 
| 35 | 
            -
             *
         | 
| 36 | 
            -
             * Unicode, Inc. hereby grants the right to freely use the information
         | 
| 37 | 
            -
             * supplied in this file in the creation of products supporting the
         | 
| 38 | 
            -
             * Unicode Standard, and to make copies of this file in any form
         | 
| 39 | 
            -
             * for internal or external distribution as long as this notice
         | 
| 40 | 
            -
             * remains attached.
         | 
| 41 | 
            -
             */
         | 
| 33 | 
            +
            static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
         | 
| 34 | 
            +
            static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
         | 
| 35 | 
            +
                         sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
         | 
| 42 36 |  | 
| 43 | 
            -
             | 
| 44 | 
            -
              | 
| 45 | 
            -
              | 
| 46 | 
            -
             | 
| 47 | 
            -
              | 
| 48 | 
            -
             * | 
| 49 | 
            -
              | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                 | 
| 57 | 
            -
                 | 
| 58 | 
            -
                 | 
| 37 | 
            +
             | 
| 38 | 
            +
            #define GET_STATE_TO(self, state) \
         | 
| 39 | 
            +
                TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            #define GET_STATE(self)                       \
         | 
| 42 | 
            +
                JSON_Generator_State *state;              \
         | 
| 43 | 
            +
                GET_STATE_TO(self, state)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            struct generate_json_data;
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            struct generate_json_data {
         | 
| 50 | 
            +
                FBuffer *buffer;
         | 
| 51 | 
            +
                VALUE vstate;
         | 
| 52 | 
            +
                JSON_Generator_State *state;
         | 
| 53 | 
            +
                VALUE obj;
         | 
| 54 | 
            +
                generator_func func;
         | 
| 59 55 | 
             
            };
         | 
| 60 56 |  | 
| 61 | 
            -
             | 
| 62 | 
            -
              | 
| 63 | 
            -
              | 
| 64 | 
            -
             *  | 
| 65 | 
            -
              | 
| 66 | 
            -
            static  | 
| 67 | 
            -
             | 
| 57 | 
            +
            static VALUE cState_from_state_s(VALUE self, VALUE opts);
         | 
| 58 | 
            +
            static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
         | 
| 59 | 
            +
            static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 60 | 
            +
            static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 61 | 
            +
            static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 62 | 
            +
            static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 63 | 
            +
            static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 64 | 
            +
            static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 65 | 
            +
            static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 66 | 
            +
            #ifdef RUBY_INTEGER_UNIFICATION
         | 
| 67 | 
            +
            static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 68 | 
            +
            #endif
         | 
| 69 | 
            +
            static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 70 | 
            +
            static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 71 | 
            +
            static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 72 | 
            +
            static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
         | 
| 68 73 |  | 
| 69 | 
            -
             | 
| 70 | 
            -
             * Utility routine to tell whether a sequence of bytes is legal UTF-8.
         | 
| 71 | 
            -
             * This must be called with the length pre-determined by the first byte.
         | 
| 72 | 
            -
             * If not calling this from ConvertUTF8to*, then the length can be set by:
         | 
| 73 | 
            -
             *  length = trailingBytesForUTF8[*source]+1;
         | 
| 74 | 
            -
             * and the sequence is illegal right away if there aren't that many bytes
         | 
| 75 | 
            -
             * available.
         | 
| 76 | 
            -
             * If presented with a length > 4, this returns 0.  The Unicode
         | 
| 77 | 
            -
             * definition of UTF-8 goes up to 4-byte sequences.
         | 
| 78 | 
            -
             */
         | 
| 79 | 
            -
            static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length)
         | 
| 80 | 
            -
            {
         | 
| 81 | 
            -
                UTF8 a;
         | 
| 82 | 
            -
                const UTF8 *srcptr = source+length;
         | 
| 83 | 
            -
                switch (length) {
         | 
| 84 | 
            -
                    default: return 0;
         | 
| 85 | 
            -
                             /* Everything else falls through when "1"... */
         | 
| 86 | 
            -
                    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
         | 
| 87 | 
            -
                    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
         | 
| 88 | 
            -
                    case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                                switch (*source) {
         | 
| 91 | 
            -
                                    /* no fall-through in this inner switch */
         | 
| 92 | 
            -
                                    case 0xE0: if (a < 0xA0) return 0; break;
         | 
| 93 | 
            -
                                    case 0xED: if (a > 0x9F) return 0; break;
         | 
| 94 | 
            -
                                    case 0xF0: if (a < 0x90) return 0; break;
         | 
| 95 | 
            -
                                    case 0xF4: if (a > 0x8F) return 0; break;
         | 
| 96 | 
            -
                                    default:   if (a < 0x80) return 0;
         | 
| 97 | 
            -
                                }
         | 
| 74 | 
            +
            static int usascii_encindex, utf8_encindex, binary_encindex;
         | 
| 98 75 |  | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 76 | 
            +
            #ifdef RBIMPL_ATTR_NORETURN
         | 
| 77 | 
            +
            RBIMPL_ATTR_NORETURN()
         | 
| 78 | 
            +
            #endif
         | 
| 79 | 
            +
            static void raise_generator_error_str(VALUE invalid_object, VALUE str)
         | 
| 80 | 
            +
            {
         | 
| 81 | 
            +
                VALUE exc = rb_exc_new_str(eGeneratorError, str);
         | 
| 82 | 
            +
                rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
         | 
| 83 | 
            +
                rb_exc_raise(exc);
         | 
| 103 84 | 
             
            }
         | 
| 104 85 |  | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 86 | 
            +
            #ifdef RBIMPL_ATTR_NORETURN
         | 
| 87 | 
            +
            RBIMPL_ATTR_NORETURN()
         | 
| 88 | 
            +
            #endif
         | 
| 89 | 
            +
            #ifdef RBIMPL_ATTR_FORMAT
         | 
| 90 | 
            +
            RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
         | 
| 91 | 
            +
            #endif
         | 
| 92 | 
            +
            static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
         | 
| 107 93 | 
             
            {
         | 
| 108 | 
            -
                 | 
| 109 | 
            -
             | 
| 110 | 
            -
                 | 
| 111 | 
            -
                 | 
| 112 | 
            -
                 | 
| 113 | 
            -
                buf[5] = digits[character & 0xf];
         | 
| 94 | 
            +
                va_list args;
         | 
| 95 | 
            +
                va_start(args, fmt);
         | 
| 96 | 
            +
                VALUE str = rb_vsprintf(fmt, args);
         | 
| 97 | 
            +
                va_end(args);
         | 
| 98 | 
            +
                raise_generator_error_str(invalid_object, str);
         | 
| 114 99 | 
             
            }
         | 
| 115 100 |  | 
| 116 | 
            -
             | 
| 117 | 
            -
              | 
| 118 | 
            -
            static  | 
| 119 | 
            -
             | 
| 101 | 
            +
            // 0 - single byte char that don't need to be escaped.
         | 
| 102 | 
            +
            // (x | 8) - char that needs to be escaped.
         | 
| 103 | 
            +
            static const unsigned char CHAR_LENGTH_MASK = 7;
         | 
| 104 | 
            +
            static const unsigned char ESCAPE_MASK = 8;
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            typedef struct _search_state {
         | 
| 107 | 
            +
                const char *ptr;
         | 
| 108 | 
            +
                const char *end;
         | 
| 109 | 
            +
                const char *cursor;
         | 
| 110 | 
            +
                FBuffer *buffer;
         | 
| 111 | 
            +
            } search_state;
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            static inline void search_flush(search_state *search)
         | 
| 120 114 | 
             
            {
         | 
| 121 | 
            -
                 | 
| 122 | 
            -
                 | 
| 115 | 
            +
                fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
         | 
| 116 | 
            +
                search->cursor = search->ptr;
         | 
| 123 117 | 
             
            }
         | 
| 124 118 |  | 
| 125 | 
            -
             | 
| 126 | 
            -
              | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
                 | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 119 | 
            +
            static const unsigned char escape_table_basic[256] = {
         | 
| 120 | 
            +
                // ASCII Control Characters
         | 
| 121 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 122 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 123 | 
            +
                // ASCII Characters
         | 
| 124 | 
            +
                 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
         | 
| 125 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 126 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 127 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
         | 
| 128 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 129 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 130 | 
            +
            };
         | 
| 132 131 |  | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
                    if ( | 
| 137 | 
            -
                         | 
| 138 | 
            -
             | 
| 132 | 
            +
            static inline unsigned char search_escape_basic(search_state *search)
         | 
| 133 | 
            +
            {
         | 
| 134 | 
            +
                while (search->ptr < search->end) {
         | 
| 135 | 
            +
                    if (RB_UNLIKELY(escape_table_basic[(const unsigned char)*search->ptr])) {
         | 
| 136 | 
            +
                        search_flush(search);
         | 
| 137 | 
            +
                        return 1;
         | 
| 138 | 
            +
                    } else {
         | 
| 139 | 
            +
                        search->ptr++;
         | 
| 139 140 | 
             
                    }
         | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 141 | 
            +
                }
         | 
| 142 | 
            +
                search_flush(search);
         | 
| 143 | 
            +
                return 0;
         | 
| 144 | 
            +
            }
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            static inline void escape_UTF8_char_basic(search_state *search) {
         | 
| 147 | 
            +
                const unsigned char ch = (unsigned char)*search->ptr;
         | 
| 148 | 
            +
                switch (ch) {
         | 
| 149 | 
            +
                    case '"':  fbuffer_append(search->buffer, "\\\"", 2); break;
         | 
| 150 | 
            +
                    case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
         | 
| 151 | 
            +
                    case '/':  fbuffer_append(search->buffer, "\\/", 2);  break;
         | 
| 152 | 
            +
                    case '\b': fbuffer_append(search->buffer, "\\b", 2);  break;
         | 
| 153 | 
            +
                    case '\f': fbuffer_append(search->buffer, "\\f", 2);  break;
         | 
| 154 | 
            +
                    case '\n': fbuffer_append(search->buffer, "\\n", 2);  break;
         | 
| 155 | 
            +
                    case '\r': fbuffer_append(search->buffer, "\\r", 2);  break;
         | 
| 156 | 
            +
                    case '\t': fbuffer_append(search->buffer, "\\t", 2);  break;
         | 
| 157 | 
            +
                    default: {
         | 
| 158 | 
            +
                        const char *hexdig = "0123456789abcdef";
         | 
| 159 | 
            +
                        char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
         | 
| 160 | 
            +
                        scratch[4] = hexdig[(ch >> 4) & 0xf];
         | 
| 161 | 
            +
                        scratch[5] = hexdig[ch & 0xf];
         | 
| 162 | 
            +
                        fbuffer_append(search->buffer, scratch, 6);
         | 
| 163 | 
            +
                        break;
         | 
| 143 164 | 
             
                    }
         | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 165 | 
            +
                }
         | 
| 166 | 
            +
                search->ptr++;
         | 
| 167 | 
            +
                search->cursor = search->ptr;
         | 
| 168 | 
            +
            }
         | 
| 169 | 
            +
             | 
| 170 | 
            +
            /* Converts in_string to a JSON string (without the wrapping '"'
         | 
| 171 | 
            +
             * characters) in FBuffer out_buffer.
         | 
| 172 | 
            +
             *
         | 
| 173 | 
            +
             * Character are JSON-escaped according to:
         | 
| 174 | 
            +
             *
         | 
| 175 | 
            +
             * - Always: ASCII control characters (0x00-0x1F), dquote, and
         | 
| 176 | 
            +
             *   backslash.
         | 
| 177 | 
            +
             *
         | 
| 178 | 
            +
             * - If out_ascii_only: non-ASCII characters (>0x7F)
         | 
| 179 | 
            +
             *
         | 
| 180 | 
            +
             * - If script_safe: forwardslash (/), line separator (U+2028), and
         | 
| 181 | 
            +
             *   paragraph separator (U+2029)
         | 
| 182 | 
            +
             *
         | 
| 183 | 
            +
             * Everything else (should be UTF-8) is just passed through and
         | 
| 184 | 
            +
             * appended to the result.
         | 
| 185 | 
            +
             */
         | 
| 186 | 
            +
            static inline void convert_UTF8_to_JSON(search_state *search)
         | 
| 187 | 
            +
            {
         | 
| 188 | 
            +
                while (search_escape_basic(search)) {
         | 
| 189 | 
            +
                    escape_UTF8_char_basic(search);
         | 
| 190 | 
            +
                }
         | 
| 191 | 
            +
            }
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) {
         | 
| 194 | 
            +
                const unsigned char ch = (unsigned char)*search->ptr;
         | 
| 195 | 
            +
                switch (ch_len) {
         | 
| 196 | 
            +
                    case 1: {
         | 
| 197 | 
            +
                        switch (ch) {
         | 
| 198 | 
            +
                            case '"':  fbuffer_append(search->buffer, "\\\"", 2); break;
         | 
| 199 | 
            +
                            case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
         | 
| 200 | 
            +
                            case '/':  fbuffer_append(search->buffer, "\\/", 2);  break;
         | 
| 201 | 
            +
                            case '\b': fbuffer_append(search->buffer, "\\b", 2);  break;
         | 
| 202 | 
            +
                            case '\f': fbuffer_append(search->buffer, "\\f", 2);  break;
         | 
| 203 | 
            +
                            case '\n': fbuffer_append(search->buffer, "\\n", 2);  break;
         | 
| 204 | 
            +
                            case '\r': fbuffer_append(search->buffer, "\\r", 2);  break;
         | 
| 205 | 
            +
                            case '\t': fbuffer_append(search->buffer, "\\t", 2);  break;
         | 
| 206 | 
            +
                            default: {
         | 
| 207 | 
            +
                                const char *hexdig = "0123456789abcdef";
         | 
| 208 | 
            +
                                char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
         | 
| 209 | 
            +
                                scratch[4] = hexdig[(ch >> 4) & 0xf];
         | 
| 210 | 
            +
                                scratch[5] = hexdig[ch & 0xf];
         | 
| 211 | 
            +
                                fbuffer_append(search->buffer, scratch, 6);
         | 
| 212 | 
            +
                                break;
         | 
| 213 | 
            +
                            }
         | 
| 214 | 
            +
                        }
         | 
| 215 | 
            +
                        break;
         | 
| 154 216 | 
             
                    }
         | 
| 155 | 
            -
                     | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
                        /* UTF-16 surrogate values are illegal in UTF-32 */
         | 
| 159 | 
            -
                        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
         | 
| 160 | 
            -
            #if UNI_STRICT_CONVERSION
         | 
| 161 | 
            -
                            source -= (extraBytesToRead+1); /* return to the illegal value itself */
         | 
| 162 | 
            -
                            rb_raise(rb_path2class("JSON::GeneratorError"),
         | 
| 163 | 
            -
                                    "source sequence is illegal/malformed utf-8");
         | 
| 164 | 
            -
            #else
         | 
| 165 | 
            -
                            unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
         | 
| 166 | 
            -
            #endif
         | 
| 217 | 
            +
                    case 3: {
         | 
| 218 | 
            +
                        if (search->ptr[2] & 1) {
         | 
| 219 | 
            +
                            fbuffer_append(search->buffer, "\\u2029", 6);
         | 
| 167 220 | 
             
                        } else {
         | 
| 168 | 
            -
                             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 221 | 
            +
                            fbuffer_append(search->buffer, "\\u2028", 6);
         | 
| 222 | 
            +
                        }
         | 
| 223 | 
            +
                        break;
         | 
| 224 | 
            +
                    }
         | 
| 225 | 
            +
                }
         | 
| 226 | 
            +
                search->cursor = (search->ptr += ch_len);
         | 
| 227 | 
            +
            }
         | 
| 228 | 
            +
             | 
| 229 | 
            +
            static const unsigned char script_safe_escape_table[256] = {
         | 
| 230 | 
            +
                // ASCII Control Characters
         | 
| 231 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 232 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 233 | 
            +
                // ASCII Characters
         | 
| 234 | 
            +
                 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, // '"' and '/'
         | 
| 235 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 236 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 237 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
         | 
| 238 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 239 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 240 | 
            +
                // Continuation byte
         | 
| 241 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 242 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 243 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 244 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 245 | 
            +
                // First byte of a 2-byte code point
         | 
| 246 | 
            +
                 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
         | 
| 247 | 
            +
                 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
         | 
| 248 | 
            +
                // First byte of a 3-byte code point
         | 
| 249 | 
            +
                 3, 3,11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE2 is the start of \u2028 and \u2029
         | 
| 250 | 
            +
                //First byte of a 4+ byte code point
         | 
| 251 | 
            +
                 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
         | 
| 252 | 
            +
            };
         | 
| 253 | 
            +
             | 
| 254 | 
            +
            static inline unsigned char search_script_safe_escape(search_state *search)
         | 
| 255 | 
            +
            {
         | 
| 256 | 
            +
                while (search->ptr < search->end) {
         | 
| 257 | 
            +
                    unsigned char ch = (unsigned char)*search->ptr;
         | 
| 258 | 
            +
                    unsigned char ch_len = script_safe_escape_table[ch];
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                    if (RB_UNLIKELY(ch_len)) {
         | 
| 261 | 
            +
                        if (ch_len & ESCAPE_MASK) {
         | 
| 262 | 
            +
                            if (RB_UNLIKELY(ch_len == 11)) {
         | 
| 263 | 
            +
                                const unsigned char *uptr = (const unsigned char *)search->ptr;
         | 
| 264 | 
            +
                                if (!(uptr[1] == 0x80 && (uptr[2] >> 1) == 0x54)) {
         | 
| 265 | 
            +
                                    search->ptr += 3;
         | 
| 266 | 
            +
                                    continue;
         | 
| 206 267 | 
             
                                }
         | 
| 207 268 | 
             
                            }
         | 
| 269 | 
            +
                            search_flush(search);
         | 
| 270 | 
            +
                            return ch_len & CHAR_LENGTH_MASK;
         | 
| 271 | 
            +
                        } else {
         | 
| 272 | 
            +
                            search->ptr += ch_len;
         | 
| 208 273 | 
             
                        }
         | 
| 209 | 
            -
                    } else if (ch > UNI_MAX_UTF16) {
         | 
| 210 | 
            -
            #if UNI_STRICT_CONVERSION
         | 
| 211 | 
            -
                        source -= (extraBytesToRead+1); /* return to the start */
         | 
| 212 | 
            -
                        rb_raise(rb_path2class("JSON::GeneratorError"),
         | 
| 213 | 
            -
                                "source sequence is illegal/malformed utf8");
         | 
| 214 | 
            -
            #else
         | 
| 215 | 
            -
                        unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
         | 
| 216 | 
            -
            #endif
         | 
| 217 274 | 
             
                    } else {
         | 
| 218 | 
            -
                         | 
| 219 | 
            -
                        ch -= halfBase;
         | 
| 220 | 
            -
                        unicode_escape_to_buffer(buffer, buf, (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START));
         | 
| 221 | 
            -
                        unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
         | 
| 275 | 
            +
                        search->ptr++;
         | 
| 222 276 | 
             
                    }
         | 
| 223 277 | 
             
                }
         | 
| 224 | 
            -
                 | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
              | 
| 229 | 
            -
             | 
| 230 | 
            -
              | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
                 | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 237 | 
            -
                 | 
| 238 | 
            -
             | 
| 239 | 
            -
             | 
| 240 | 
            -
             | 
| 241 | 
            -
             | 
| 242 | 
            -
             | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 245 | 
            -
             | 
| 246 | 
            -
             | 
| 247 | 
            -
             | 
| 248 | 
            -
             | 
| 249 | 
            -
             | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 253 | 
            -
             | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 257 | 
            -
             | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 263 | 
            -
             | 
| 264 | 
            -
             | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 267 | 
            -
             | 
| 268 | 
            -
             | 
| 269 | 
            -
             | 
| 278 | 
            +
                search_flush(search);
         | 
| 279 | 
            +
                return 0;
         | 
| 280 | 
            +
            }
         | 
| 281 | 
            +
             | 
| 282 | 
            +
            static void convert_UTF8_to_script_safe_JSON(search_state *search)
         | 
| 283 | 
            +
            {
         | 
| 284 | 
            +
                unsigned char ch_len;
         | 
| 285 | 
            +
                while ((ch_len = search_script_safe_escape(search))) {
         | 
| 286 | 
            +
                    escape_UTF8_char(search, ch_len);
         | 
| 287 | 
            +
                }
         | 
| 288 | 
            +
            }
         | 
| 289 | 
            +
             | 
| 290 | 
            +
            static const unsigned char ascii_only_escape_table[256] = {
         | 
| 291 | 
            +
                // ASCII Control Characters
         | 
| 292 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 293 | 
            +
                 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
         | 
| 294 | 
            +
                // ASCII Characters
         | 
| 295 | 
            +
                 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
         | 
| 296 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 297 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 298 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
         | 
| 299 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 300 | 
            +
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         | 
| 301 | 
            +
                // Continuation byte
         | 
| 302 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 303 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 304 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 305 | 
            +
                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         | 
| 306 | 
            +
                // First byte of a  2-byte code point
         | 
| 307 | 
            +
                 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
         | 
| 308 | 
            +
                 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
         | 
| 309 | 
            +
                // First byte of a 3-byte code point
         | 
| 310 | 
            +
                 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
         | 
| 311 | 
            +
                //First byte of a 4+ byte code point
         | 
| 312 | 
            +
                 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
         | 
| 313 | 
            +
            };
         | 
| 314 | 
            +
             | 
| 315 | 
            +
            static inline unsigned char search_ascii_only_escape(search_state *search, const unsigned char escape_table[256])
         | 
| 316 | 
            +
            {
         | 
| 317 | 
            +
                while (search->ptr < search->end) {
         | 
| 318 | 
            +
                    unsigned char ch = (unsigned char)*search->ptr;
         | 
| 319 | 
            +
                    unsigned char ch_len = escape_table[ch];
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                    if (RB_UNLIKELY(ch_len)) {
         | 
| 322 | 
            +
                        search_flush(search);
         | 
| 323 | 
            +
                        return ch_len & CHAR_LENGTH_MASK;
         | 
| 324 | 
            +
                    } else {
         | 
| 325 | 
            +
                        search->ptr++;
         | 
| 326 | 
            +
                    }
         | 
| 327 | 
            +
                }
         | 
| 328 | 
            +
                search_flush(search);
         | 
| 329 | 
            +
                return 0;
         | 
| 330 | 
            +
            }
         | 
| 331 | 
            +
             | 
| 332 | 
            +
            static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) {
         | 
| 333 | 
            +
                const unsigned char ch = (unsigned char)*search->ptr;
         | 
| 334 | 
            +
                switch (ch_len) {
         | 
| 335 | 
            +
                    case 1: {
         | 
| 336 | 
            +
                        switch (ch) {
         | 
| 337 | 
            +
                            case '"':  fbuffer_append(search->buffer, "\\\"", 2); break;
         | 
| 338 | 
            +
                            case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
         | 
| 339 | 
            +
                            case '/':  fbuffer_append(search->buffer, "\\/", 2);  break;
         | 
| 340 | 
            +
                            case '\b': fbuffer_append(search->buffer, "\\b", 2);  break;
         | 
| 341 | 
            +
                            case '\f': fbuffer_append(search->buffer, "\\f", 2);  break;
         | 
| 342 | 
            +
                            case '\n': fbuffer_append(search->buffer, "\\n", 2);  break;
         | 
| 343 | 
            +
                            case '\r': fbuffer_append(search->buffer, "\\r", 2);  break;
         | 
| 344 | 
            +
                            case '\t': fbuffer_append(search->buffer, "\\t", 2);  break;
         | 
| 345 | 
            +
                            default: {
         | 
| 346 | 
            +
                                const char *hexdig = "0123456789abcdef";
         | 
| 347 | 
            +
                                char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
         | 
| 348 | 
            +
                                scratch[4] = hexdig[(ch >> 4) & 0xf];
         | 
| 349 | 
            +
                                scratch[5] = hexdig[ch & 0xf];
         | 
| 350 | 
            +
                                fbuffer_append(search->buffer, scratch, 6);
         | 
| 270 351 | 
             
                                break;
         | 
| 352 | 
            +
                            }
         | 
| 271 353 | 
             
                        }
         | 
| 272 | 
            -
             | 
| 273 | 
            -
             | 
| 274 | 
            -
             | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 354 | 
            +
                        break;
         | 
| 355 | 
            +
                    }
         | 
| 356 | 
            +
                    default: {
         | 
| 357 | 
            +
                        const char *hexdig = "0123456789abcdef";
         | 
| 358 | 
            +
                        char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                        uint32_t wchar = 0;
         | 
| 361 | 
            +
             | 
| 362 | 
            +
                        switch(ch_len) {
         | 
| 363 | 
            +
                            case 2:
         | 
| 364 | 
            +
                                wchar = ch & 0x1F;
         | 
| 277 365 | 
             
                                break;
         | 
| 278 | 
            -
                            case  | 
| 279 | 
            -
                                 | 
| 280 | 
            -
                                escape_len = 2;
         | 
| 366 | 
            +
                            case 3:
         | 
| 367 | 
            +
                                wchar = ch & 0x0F;
         | 
| 281 368 | 
             
                                break;
         | 
| 282 | 
            -
                            case  | 
| 283 | 
            -
                                 | 
| 284 | 
            -
                                    escape = "\\/";
         | 
| 285 | 
            -
                                    escape_len = 2;
         | 
| 286 | 
            -
                                    break;
         | 
| 287 | 
            -
                                }
         | 
| 288 | 
            -
                            default:
         | 
| 289 | 
            -
                                {
         | 
| 290 | 
            -
                                    unsigned short clen = 1;
         | 
| 291 | 
            -
                                    if (!ascii_only) {
         | 
| 292 | 
            -
                                        clen += trailingBytesForUTF8[c];
         | 
| 293 | 
            -
                                        if (end + clen > len) {
         | 
| 294 | 
            -
                                            rb_raise(rb_path2class("JSON::GeneratorError"),
         | 
| 295 | 
            -
                                                    "partial character in source, but hit end");
         | 
| 296 | 
            -
                                        }
         | 
| 297 | 
            -
                                        if (!isLegalUTF8((UTF8 *) p, clen)) {
         | 
| 298 | 
            -
                                            rb_raise(rb_path2class("JSON::GeneratorError"),
         | 
| 299 | 
            -
                                                    "source sequence is illegal/malformed utf-8");
         | 
| 300 | 
            -
                                        }
         | 
| 301 | 
            -
                                    }
         | 
| 302 | 
            -
                                    end += clen;
         | 
| 303 | 
            -
                                }
         | 
| 304 | 
            -
                                continue;
         | 
| 369 | 
            +
                            case 4:
         | 
| 370 | 
            +
                                wchar = ch & 0x07;
         | 
| 305 371 | 
             
                                break;
         | 
| 306 372 | 
             
                        }
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                        for (short i = 1; i < ch_len; i++) {
         | 
| 375 | 
            +
                            wchar = (wchar << 6) | (search->ptr[i] & 0x3F);
         | 
| 376 | 
            +
                        }
         | 
| 377 | 
            +
             | 
| 378 | 
            +
                        if (wchar <= 0xFFFF) {
         | 
| 379 | 
            +
                            scratch[2] = hexdig[wchar >> 12];
         | 
| 380 | 
            +
                            scratch[3] = hexdig[(wchar >> 8) & 0xf];
         | 
| 381 | 
            +
                            scratch[4] = hexdig[(wchar >> 4) & 0xf];
         | 
| 382 | 
            +
                            scratch[5] = hexdig[wchar & 0xf];
         | 
| 383 | 
            +
                            fbuffer_append(search->buffer, scratch, 6);
         | 
| 384 | 
            +
                        } else {
         | 
| 385 | 
            +
                            uint16_t hi, lo;
         | 
| 386 | 
            +
                            wchar -= 0x10000;
         | 
| 387 | 
            +
                            hi = 0xD800 + (uint16_t)(wchar >> 10);
         | 
| 388 | 
            +
                            lo = 0xDC00 + (uint16_t)(wchar & 0x3FF);
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                            scratch[2] = hexdig[hi >> 12];
         | 
| 391 | 
            +
                            scratch[3] = hexdig[(hi >> 8) & 0xf];
         | 
| 392 | 
            +
                            scratch[4] = hexdig[(hi >> 4) & 0xf];
         | 
| 393 | 
            +
                            scratch[5] = hexdig[hi & 0xf];
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                            scratch[8] = hexdig[lo >> 12];
         | 
| 396 | 
            +
                            scratch[9] = hexdig[(lo >> 8) & 0xf];
         | 
| 397 | 
            +
                            scratch[10] = hexdig[(lo >> 4) & 0xf];
         | 
| 398 | 
            +
                            scratch[11] = hexdig[lo & 0xf];
         | 
| 399 | 
            +
             | 
| 400 | 
            +
                            fbuffer_append(search->buffer, scratch, 12);
         | 
| 401 | 
            +
                        }
         | 
| 402 | 
            +
             | 
| 403 | 
            +
                        break;
         | 
| 307 404 | 
             
                    }
         | 
| 308 | 
            -
                    fbuffer_append(buffer, ptr + start, end - start);
         | 
| 309 | 
            -
                    fbuffer_append(buffer, escape, escape_len);
         | 
| 310 | 
            -
                    start = ++end;
         | 
| 311 | 
            -
                    escape = NULL;
         | 
| 312 405 | 
             
                }
         | 
| 313 | 
            -
                 | 
| 406 | 
            +
                search->cursor = (search->ptr += ch_len);
         | 
| 314 407 | 
             
            }
         | 
| 315 408 |  | 
| 316 | 
            -
            static  | 
| 317 | 
            -
             | 
| 318 | 
            -
             | 
| 319 | 
            -
             | 
| 320 | 
            -
             | 
| 321 | 
            -
             | 
| 409 | 
            +
            static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned char escape_table[256])
         | 
| 410 | 
            +
            {
         | 
| 411 | 
            +
                unsigned char ch_len;
         | 
| 412 | 
            +
                while ((ch_len = search_ascii_only_escape(search, escape_table))) {
         | 
| 413 | 
            +
                    full_escape_UTF8_char(search, ch_len);
         | 
| 414 | 
            +
                }
         | 
| 322 415 | 
             
            }
         | 
| 323 416 |  | 
| 324 417 | 
             
            /*
         | 
| @@ -413,7 +506,9 @@ static char *fstrndup(const char *ptr, unsigned long len) { | |
| 413 506 | 
             
             */
         | 
| 414 507 | 
             
            static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 415 508 | 
             
            {
         | 
| 416 | 
            -
                 | 
| 509 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 510 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 511 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
         | 
| 417 512 | 
             
            }
         | 
| 418 513 |  | 
| 419 514 | 
             
            /*
         | 
| @@ -425,7 +520,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self) | |
| 425 520 | 
             
             * produced JSON string output further.
         | 
| 426 521 | 
             
             */
         | 
| 427 522 | 
             
            static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
         | 
| 428 | 
            -
                 | 
| 523 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 524 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 525 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
         | 
| 429 526 | 
             
            }
         | 
| 430 527 |  | 
| 431 528 | 
             
            #ifdef RUBY_INTEGER_UNIFICATION
         | 
| @@ -436,7 +533,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) { | |
| 436 533 | 
             
             */
         | 
| 437 534 | 
             
            static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 438 535 | 
             
            {
         | 
| 439 | 
            -
                 | 
| 536 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 537 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 538 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
         | 
| 440 539 | 
             
            }
         | 
| 441 540 |  | 
| 442 541 | 
             
            #else
         | 
| @@ -447,7 +546,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self) | |
| 447 546 | 
             
             */
         | 
| 448 547 | 
             
            static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 449 548 | 
             
            {
         | 
| 450 | 
            -
                 | 
| 549 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 550 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 551 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
         | 
| 451 552 | 
             
            }
         | 
| 452 553 |  | 
| 453 554 | 
             
            /*
         | 
| @@ -457,7 +558,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self) | |
| 457 558 | 
             
             */
         | 
| 458 559 | 
             
            static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 459 560 | 
             
            {
         | 
| 460 | 
            -
                 | 
| 561 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 562 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 563 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
         | 
| 461 564 | 
             
            }
         | 
| 462 565 | 
             
            #endif
         | 
| 463 566 |  | 
| @@ -468,7 +571,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self) | |
| 468 571 | 
             
             */
         | 
| 469 572 | 
             
            static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 470 573 | 
             
            {
         | 
| 471 | 
            -
                 | 
| 574 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 575 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 576 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
         | 
| 472 577 | 
             
            }
         | 
| 473 578 |  | 
| 474 579 | 
             
            /*
         | 
| @@ -478,6 +583,7 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) | |
| 478 583 | 
             
             */
         | 
| 479 584 | 
             
            static VALUE mString_included_s(VALUE self, VALUE modul) {
         | 
| 480 585 | 
             
                VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
         | 
| 586 | 
            +
                rb_call_super(1, &modul);
         | 
| 481 587 | 
             
                return result;
         | 
| 482 588 | 
             
            }
         | 
| 483 589 |  | 
| @@ -490,7 +596,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) { | |
| 490 596 | 
             
             */
         | 
| 491 597 | 
             
            static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 492 598 | 
             
            {
         | 
| 493 | 
            -
                 | 
| 599 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 600 | 
            +
                VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
         | 
| 601 | 
            +
                return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
         | 
| 494 602 | 
             
            }
         | 
| 495 603 |  | 
| 496 604 | 
             
            /*
         | 
| @@ -507,7 +615,7 @@ static VALUE mString_to_json_raw_object(VALUE self) | |
| 507 615 | 
             
                VALUE result = rb_hash_new();
         | 
| 508 616 | 
             
                rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
         | 
| 509 617 | 
             
                ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
         | 
| 510 | 
            -
                rb_hash_aset(result,  | 
| 618 | 
            +
                rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
         | 
| 511 619 | 
             
                return result;
         | 
| 512 620 | 
             
            }
         | 
| 513 621 |  | 
| @@ -545,7 +653,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o) | |
| 545 653 | 
             
             */
         | 
| 546 654 | 
             
            static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 547 655 | 
             
            {
         | 
| 548 | 
            -
                 | 
| 656 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 657 | 
            +
                return rb_utf8_str_new("true", 4);
         | 
| 549 658 | 
             
            }
         | 
| 550 659 |  | 
| 551 660 | 
             
            /*
         | 
| @@ -555,7 +664,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self) | |
| 555 664 | 
             
             */
         | 
| 556 665 | 
             
            static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 557 666 | 
             
            {
         | 
| 558 | 
            -
                 | 
| 667 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 668 | 
            +
                return rb_utf8_str_new("false", 5);
         | 
| 559 669 | 
             
            }
         | 
| 560 670 |  | 
| 561 671 | 
             
            /*
         | 
| @@ -565,7 +675,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self) | |
| 565 675 | 
             
             */
         | 
| 566 676 | 
             
            static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
         | 
| 567 677 | 
             
            {
         | 
| 568 | 
            -
                 | 
| 678 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 679 | 
            +
                return rb_utf8_str_new("null", 4);
         | 
| 569 680 | 
             
            }
         | 
| 570 681 |  | 
| 571 682 | 
             
            /*
         | 
| @@ -582,36 +693,40 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self) | |
| 582 693 | 
             
                rb_scan_args(argc, argv, "01", &state);
         | 
| 583 694 | 
             
                Check_Type(string, T_STRING);
         | 
| 584 695 | 
             
                state = cState_from_state_s(cState, state);
         | 
| 585 | 
            -
                return cState_partial_generate(state, string);
         | 
| 696 | 
            +
                return cState_partial_generate(state, string, generate_json_string, Qfalse);
         | 
| 697 | 
            +
            }
         | 
| 698 | 
            +
             | 
| 699 | 
            +
            static void State_mark(void *ptr)
         | 
| 700 | 
            +
            {
         | 
| 701 | 
            +
                JSON_Generator_State *state = ptr;
         | 
| 702 | 
            +
                rb_gc_mark_movable(state->indent);
         | 
| 703 | 
            +
                rb_gc_mark_movable(state->space);
         | 
| 704 | 
            +
                rb_gc_mark_movable(state->space_before);
         | 
| 705 | 
            +
                rb_gc_mark_movable(state->object_nl);
         | 
| 706 | 
            +
                rb_gc_mark_movable(state->array_nl);
         | 
| 707 | 
            +
                rb_gc_mark_movable(state->as_json);
         | 
| 708 | 
            +
            }
         | 
| 709 | 
            +
             | 
| 710 | 
            +
            static void State_compact(void *ptr)
         | 
| 711 | 
            +
            {
         | 
| 712 | 
            +
                JSON_Generator_State *state = ptr;
         | 
| 713 | 
            +
                state->indent = rb_gc_location(state->indent);
         | 
| 714 | 
            +
                state->space = rb_gc_location(state->space);
         | 
| 715 | 
            +
                state->space_before = rb_gc_location(state->space_before);
         | 
| 716 | 
            +
                state->object_nl = rb_gc_location(state->object_nl);
         | 
| 717 | 
            +
                state->array_nl = rb_gc_location(state->array_nl);
         | 
| 718 | 
            +
                state->as_json = rb_gc_location(state->as_json);
         | 
| 586 719 | 
             
            }
         | 
| 587 720 |  | 
| 588 721 | 
             
            static void State_free(void *ptr)
         | 
| 589 722 | 
             
            {
         | 
| 590 723 | 
             
                JSON_Generator_State *state = ptr;
         | 
| 591 | 
            -
                if (state->indent) ruby_xfree(state->indent);
         | 
| 592 | 
            -
                if (state->space) ruby_xfree(state->space);
         | 
| 593 | 
            -
                if (state->space_before) ruby_xfree(state->space_before);
         | 
| 594 | 
            -
                if (state->object_nl) ruby_xfree(state->object_nl);
         | 
| 595 | 
            -
                if (state->array_nl) ruby_xfree(state->array_nl);
         | 
| 596 | 
            -
                if (state->array_delim) fbuffer_free(state->array_delim);
         | 
| 597 | 
            -
                if (state->object_delim) fbuffer_free(state->object_delim);
         | 
| 598 | 
            -
                if (state->object_delim2) fbuffer_free(state->object_delim2);
         | 
| 599 724 | 
             
                ruby_xfree(state);
         | 
| 600 725 | 
             
            }
         | 
| 601 726 |  | 
| 602 727 | 
             
            static size_t State_memsize(const void *ptr)
         | 
| 603 728 | 
             
            {
         | 
| 604 | 
            -
                 | 
| 605 | 
            -
                size_t size = sizeof(*state);
         | 
| 606 | 
            -
                if (state->indent) size += state->indent_len + 1;
         | 
| 607 | 
            -
                if (state->space) size += state->space_len + 1;
         | 
| 608 | 
            -
                if (state->space_before) size += state->space_before_len + 1;
         | 
| 609 | 
            -
                if (state->object_nl) size += state->object_nl_len + 1;
         | 
| 610 | 
            -
                if (state->array_nl) size += state->array_nl_len + 1;
         | 
| 611 | 
            -
                if (state->array_delim) size += FBUFFER_CAPA(state->array_delim);
         | 
| 612 | 
            -
                if (state->object_delim) size += FBUFFER_CAPA(state->object_delim);
         | 
| 613 | 
            -
                if (state->object_delim2) size += FBUFFER_CAPA(state->object_delim2);
         | 
| 614 | 
            -
                return size;
         | 
| 729 | 
            +
                return sizeof(JSON_Generator_State);
         | 
| 615 730 | 
             
            }
         | 
| 616 731 |  | 
| 617 732 | 
             
            #ifndef HAVE_RB_EXT_RACTOR_SAFE
         | 
| @@ -619,193 +734,57 @@ static size_t State_memsize(const void *ptr) | |
| 619 734 | 
             
            #   define RUBY_TYPED_FROZEN_SHAREABLE 0
         | 
| 620 735 | 
             
            #endif
         | 
| 621 736 |  | 
| 622 | 
            -
            #ifdef NEW_TYPEDDATA_WRAPPER
         | 
| 623 737 | 
             
            static const rb_data_type_t JSON_Generator_State_type = {
         | 
| 624 738 | 
             
                "JSON/Generator/State",
         | 
| 625 | 
            -
                { | 
| 626 | 
            -
             | 
| 739 | 
            +
                {
         | 
| 740 | 
            +
                    .dmark = State_mark,
         | 
| 741 | 
            +
                    .dfree = State_free,
         | 
| 742 | 
            +
                    .dsize = State_memsize,
         | 
| 743 | 
            +
                    .dcompact = State_compact,
         | 
| 744 | 
            +
                },
         | 
| 627 745 | 
             
                0, 0,
         | 
| 628 | 
            -
                RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
         | 
| 629 | 
            -
            #endif
         | 
| 746 | 
            +
                RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
         | 
| 630 747 | 
             
            };
         | 
| 631 | 
            -
            #endif
         | 
| 632 | 
            -
             | 
| 633 | 
            -
            static VALUE cState_s_allocate(VALUE klass)
         | 
| 634 | 
            -
            {
         | 
| 635 | 
            -
                JSON_Generator_State *state;
         | 
| 636 | 
            -
                return TypedData_Make_Struct(klass, JSON_Generator_State,
         | 
| 637 | 
            -
            				 &JSON_Generator_State_type, state);
         | 
| 638 | 
            -
            }
         | 
| 639 748 |  | 
| 640 | 
            -
             | 
| 641 | 
            -
             * call-seq: configure(opts)
         | 
| 642 | 
            -
             *
         | 
| 643 | 
            -
             * Configure this State instance with the Hash _opts_, and return
         | 
| 644 | 
            -
             * itself.
         | 
| 645 | 
            -
             */
         | 
| 646 | 
            -
            static VALUE cState_configure(VALUE self, VALUE opts)
         | 
| 749 | 
            +
            static void state_init(JSON_Generator_State *state)
         | 
| 647 750 | 
             
            {
         | 
| 648 | 
            -
                VALUE tmp;
         | 
| 649 | 
            -
                GET_STATE(self);
         | 
| 650 | 
            -
                tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash");
         | 
| 651 | 
            -
                if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
         | 
| 652 | 
            -
                opts = tmp;
         | 
| 653 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_indent));
         | 
| 654 | 
            -
                if (RTEST(tmp)) {
         | 
| 655 | 
            -
                    unsigned long len;
         | 
| 656 | 
            -
                    Check_Type(tmp, T_STRING);
         | 
| 657 | 
            -
                    len = RSTRING_LEN(tmp);
         | 
| 658 | 
            -
                    state->indent = fstrndup(RSTRING_PTR(tmp), len + 1);
         | 
| 659 | 
            -
                    state->indent_len = len;
         | 
| 660 | 
            -
                }
         | 
| 661 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_space));
         | 
| 662 | 
            -
                if (RTEST(tmp)) {
         | 
| 663 | 
            -
                    unsigned long len;
         | 
| 664 | 
            -
                    Check_Type(tmp, T_STRING);
         | 
| 665 | 
            -
                    len = RSTRING_LEN(tmp);
         | 
| 666 | 
            -
                    state->space = fstrndup(RSTRING_PTR(tmp), len + 1);
         | 
| 667 | 
            -
                    state->space_len = len;
         | 
| 668 | 
            -
                }
         | 
| 669 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
         | 
| 670 | 
            -
                if (RTEST(tmp)) {
         | 
| 671 | 
            -
                    unsigned long len;
         | 
| 672 | 
            -
                    Check_Type(tmp, T_STRING);
         | 
| 673 | 
            -
                    len = RSTRING_LEN(tmp);
         | 
| 674 | 
            -
                    state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1);
         | 
| 675 | 
            -
                    state->space_before_len = len;
         | 
| 676 | 
            -
                }
         | 
| 677 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
         | 
| 678 | 
            -
                if (RTEST(tmp)) {
         | 
| 679 | 
            -
                    unsigned long len;
         | 
| 680 | 
            -
                    Check_Type(tmp, T_STRING);
         | 
| 681 | 
            -
                    len = RSTRING_LEN(tmp);
         | 
| 682 | 
            -
                    state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
         | 
| 683 | 
            -
                    state->array_nl_len = len;
         | 
| 684 | 
            -
                }
         | 
| 685 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
         | 
| 686 | 
            -
                if (RTEST(tmp)) {
         | 
| 687 | 
            -
                    unsigned long len;
         | 
| 688 | 
            -
                    Check_Type(tmp, T_STRING);
         | 
| 689 | 
            -
                    len = RSTRING_LEN(tmp);
         | 
| 690 | 
            -
                    state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
         | 
| 691 | 
            -
                    state->object_nl_len = len;
         | 
| 692 | 
            -
                }
         | 
| 693 | 
            -
                tmp = ID2SYM(i_max_nesting);
         | 
| 694 751 | 
             
                state->max_nesting = 100;
         | 
| 695 | 
            -
                 | 
| 696 | 
            -
                    VALUE max_nesting = rb_hash_aref(opts, tmp);
         | 
| 697 | 
            -
                    if (RTEST(max_nesting)) {
         | 
| 698 | 
            -
                        Check_Type(max_nesting, T_FIXNUM);
         | 
| 699 | 
            -
                        state->max_nesting = FIX2LONG(max_nesting);
         | 
| 700 | 
            -
                    } else {
         | 
| 701 | 
            -
                        state->max_nesting = 0;
         | 
| 702 | 
            -
                    }
         | 
| 703 | 
            -
                }
         | 
| 704 | 
            -
                tmp = ID2SYM(i_depth);
         | 
| 705 | 
            -
                state->depth = 0;
         | 
| 706 | 
            -
                if (option_given_p(opts, tmp)) {
         | 
| 707 | 
            -
                    VALUE depth = rb_hash_aref(opts, tmp);
         | 
| 708 | 
            -
                    if (RTEST(depth)) {
         | 
| 709 | 
            -
                        Check_Type(depth, T_FIXNUM);
         | 
| 710 | 
            -
                        state->depth = FIX2LONG(depth);
         | 
| 711 | 
            -
                    } else {
         | 
| 712 | 
            -
                        state->depth = 0;
         | 
| 713 | 
            -
                    }
         | 
| 714 | 
            -
                }
         | 
| 715 | 
            -
                tmp = ID2SYM(i_buffer_initial_length);
         | 
| 716 | 
            -
                if (option_given_p(opts, tmp)) {
         | 
| 717 | 
            -
                    VALUE buffer_initial_length = rb_hash_aref(opts, tmp);
         | 
| 718 | 
            -
                    if (RTEST(buffer_initial_length)) {
         | 
| 719 | 
            -
                        long initial_length;
         | 
| 720 | 
            -
                        Check_Type(buffer_initial_length, T_FIXNUM);
         | 
| 721 | 
            -
                        initial_length = FIX2LONG(buffer_initial_length);
         | 
| 722 | 
            -
                        if (initial_length > 0) state->buffer_initial_length = initial_length;
         | 
| 723 | 
            -
                    }
         | 
| 724 | 
            -
                }
         | 
| 725 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan));
         | 
| 726 | 
            -
                state->allow_nan = RTEST(tmp);
         | 
| 727 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
         | 
| 728 | 
            -
                state->ascii_only = RTEST(tmp);
         | 
| 729 | 
            -
                tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
         | 
| 730 | 
            -
                state->escape_slash = RTEST(tmp);
         | 
| 731 | 
            -
                return self;
         | 
| 752 | 
            +
                state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
         | 
| 732 753 | 
             
            }
         | 
| 733 754 |  | 
| 734 | 
            -
            static  | 
| 755 | 
            +
            static VALUE cState_s_allocate(VALUE klass)
         | 
| 735 756 | 
             
            {
         | 
| 736 | 
            -
                 | 
| 737 | 
            -
                 | 
| 738 | 
            -
                 | 
| 739 | 
            -
             | 
| 740 | 
            -
                    long key_len = RSTRING_LEN(key);
         | 
| 741 | 
            -
                    VALUE value = rb_iv_get(state, StringValueCStr(key));
         | 
| 742 | 
            -
                    rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value);
         | 
| 743 | 
            -
                }
         | 
| 757 | 
            +
                JSON_Generator_State *state;
         | 
| 758 | 
            +
                VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
         | 
| 759 | 
            +
                state_init(state);
         | 
| 760 | 
            +
                return obj;
         | 
| 744 761 | 
             
            }
         | 
| 745 762 |  | 
| 746 | 
            -
             | 
| 747 | 
            -
             * call-seq: to_h
         | 
| 748 | 
            -
             *
         | 
| 749 | 
            -
             * Returns the configuration instance variables as a hash, that can be
         | 
| 750 | 
            -
             * passed to the configure method.
         | 
| 751 | 
            -
             */
         | 
| 752 | 
            -
            static VALUE cState_to_h(VALUE self)
         | 
| 763 | 
            +
            static void vstate_spill(struct generate_json_data *data)
         | 
| 753 764 | 
             
            {
         | 
| 754 | 
            -
                VALUE  | 
| 755 | 
            -
                GET_STATE( | 
| 756 | 
            -
                 | 
| 757 | 
            -
                 | 
| 758 | 
            -
                 | 
| 759 | 
            -
                 | 
| 760 | 
            -
                 | 
| 761 | 
            -
                 | 
| 762 | 
            -
                 | 
| 763 | 
            -
                 | 
| 764 | 
            -
                 | 
| 765 | 
            -
                rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
         | 
| 766 | 
            -
                rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
         | 
| 767 | 
            -
                rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
         | 
| 768 | 
            -
                return result;
         | 
| 765 | 
            +
                VALUE vstate = cState_s_allocate(cState);
         | 
| 766 | 
            +
                GET_STATE(vstate);
         | 
| 767 | 
            +
                MEMCPY(state, data->state, JSON_Generator_State, 1);
         | 
| 768 | 
            +
                data->state = state;
         | 
| 769 | 
            +
                data->vstate = vstate;
         | 
| 770 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
         | 
| 771 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->space);
         | 
| 772 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
         | 
| 773 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
         | 
| 774 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
         | 
| 775 | 
            +
                RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
         | 
| 769 776 | 
             
            }
         | 
| 770 777 |  | 
| 771 | 
            -
             | 
| 772 | 
            -
            * call-seq: [](name)
         | 
| 773 | 
            -
            *
         | 
| 774 | 
            -
            * Returns the value returned by method +name+.
         | 
| 775 | 
            -
            */
         | 
| 776 | 
            -
            static VALUE cState_aref(VALUE self, VALUE name)
         | 
| 778 | 
            +
            static inline VALUE vstate_get(struct generate_json_data *data)
         | 
| 777 779 | 
             
            {
         | 
| 778 | 
            -
                 | 
| 779 | 
            -
             | 
| 780 | 
            -
                    return rb_funcall(self, i_send, 1, name);
         | 
| 781 | 
            -
                } else {
         | 
| 782 | 
            -
                    return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
         | 
| 780 | 
            +
                if (RB_UNLIKELY(!data->vstate)) {
         | 
| 781 | 
            +
                    vstate_spill(data);
         | 
| 783 782 | 
             
                }
         | 
| 784 | 
            -
             | 
| 785 | 
            -
             | 
| 786 | 
            -
            /*
         | 
| 787 | 
            -
            * call-seq: []=(name, value)
         | 
| 788 | 
            -
            *
         | 
| 789 | 
            -
            * Sets the attribute name to value.
         | 
| 790 | 
            -
            */
         | 
| 791 | 
            -
            static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
         | 
| 792 | 
            -
            {
         | 
| 793 | 
            -
                VALUE name_writer;
         | 
| 794 | 
            -
             | 
| 795 | 
            -
                name = rb_funcall(name, i_to_s, 0);
         | 
| 796 | 
            -
                name_writer = rb_str_cat2(rb_str_dup(name), "=");
         | 
| 797 | 
            -
                if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) {
         | 
| 798 | 
            -
                    return rb_funcall(self, i_send, 2, name_writer, value);
         | 
| 799 | 
            -
                } else {
         | 
| 800 | 
            -
                    rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value);
         | 
| 801 | 
            -
                }
         | 
| 802 | 
            -
                return Qnil;
         | 
| 783 | 
            +
                return data->vstate;
         | 
| 803 784 | 
             
            }
         | 
| 804 785 |  | 
| 805 786 | 
             
            struct hash_foreach_arg {
         | 
| 806 | 
            -
                 | 
| 807 | 
            -
                JSON_Generator_State *state;
         | 
| 808 | 
            -
                VALUE Vstate;
         | 
| 787 | 
            +
                struct generate_json_data *data;
         | 
| 809 788 | 
             
                int iter;
         | 
| 810 789 | 
             
            };
         | 
| 811 790 |  | 
| @@ -813,314 +792,421 @@ static int | |
| 813 792 | 
             
            json_object_i(VALUE key, VALUE val, VALUE _arg)
         | 
| 814 793 | 
             
            {
         | 
| 815 794 | 
             
                struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
         | 
| 816 | 
            -
                 | 
| 817 | 
            -
             | 
| 818 | 
            -
                 | 
| 819 | 
            -
             | 
| 820 | 
            -
             | 
| 821 | 
            -
                long object_nl_len = state->object_nl_len;
         | 
| 822 | 
            -
                char *indent = state->indent;
         | 
| 823 | 
            -
                long indent_len = state->indent_len;
         | 
| 824 | 
            -
                char *delim = FBUFFER_PTR(state->object_delim);
         | 
| 825 | 
            -
                long delim_len = FBUFFER_LEN(state->object_delim);
         | 
| 826 | 
            -
                char *delim2 = FBUFFER_PTR(state->object_delim2);
         | 
| 827 | 
            -
                long delim2_len = FBUFFER_LEN(state->object_delim2);
         | 
| 795 | 
            +
                struct generate_json_data *data = arg->data;
         | 
| 796 | 
            +
             | 
| 797 | 
            +
                FBuffer *buffer = data->buffer;
         | 
| 798 | 
            +
                JSON_Generator_State *state = data->state;
         | 
| 799 | 
            +
             | 
| 828 800 | 
             
                long depth = state->depth;
         | 
| 829 801 | 
             
                int j;
         | 
| 830 | 
            -
                VALUE klass, key_to_s;
         | 
| 831 802 |  | 
| 832 | 
            -
                if (arg->iter > 0)  | 
| 833 | 
            -
                if (object_nl) {
         | 
| 834 | 
            -
                     | 
| 803 | 
            +
                if (arg->iter > 0) fbuffer_append_char(buffer, ',');
         | 
| 804 | 
            +
                if (RB_UNLIKELY(state->object_nl)) {
         | 
| 805 | 
            +
                    fbuffer_append_str(buffer, state->object_nl);
         | 
| 835 806 | 
             
                }
         | 
| 836 | 
            -
                if (indent) {
         | 
| 807 | 
            +
                if (RB_UNLIKELY(state->indent)) {
         | 
| 837 808 | 
             
                    for (j = 0; j < depth; j++) {
         | 
| 838 | 
            -
                         | 
| 809 | 
            +
                        fbuffer_append_str(buffer, state->indent);
         | 
| 839 810 | 
             
                    }
         | 
| 840 811 | 
             
                }
         | 
| 841 812 |  | 
| 842 | 
            -
                 | 
| 843 | 
            -
                 | 
| 844 | 
            -
                     | 
| 845 | 
            -
             | 
| 846 | 
            -
             | 
| 813 | 
            +
                VALUE key_to_s;
         | 
| 814 | 
            +
                switch(rb_type(key)) {
         | 
| 815 | 
            +
                    case T_STRING:
         | 
| 816 | 
            +
                        if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
         | 
| 817 | 
            +
                            key_to_s = key;
         | 
| 818 | 
            +
                        } else {
         | 
| 819 | 
            +
                            key_to_s = rb_funcall(key, i_to_s, 0);
         | 
| 820 | 
            +
                        }
         | 
| 821 | 
            +
                        break;
         | 
| 822 | 
            +
                    case T_SYMBOL:
         | 
| 823 | 
            +
                        key_to_s = rb_sym2str(key);
         | 
| 824 | 
            +
                        break;
         | 
| 825 | 
            +
                    default:
         | 
| 826 | 
            +
                        key_to_s = rb_convert_type(key, T_STRING, "String", "to_s");
         | 
| 827 | 
            +
                        break;
         | 
| 828 | 
            +
                }
         | 
| 829 | 
            +
             | 
| 830 | 
            +
                if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
         | 
| 831 | 
            +
                    generate_json_string(buffer, data, state, key_to_s);
         | 
| 847 832 | 
             
                } else {
         | 
| 848 | 
            -
                     | 
| 833 | 
            +
                    generate_json(buffer, data, state, key_to_s);
         | 
| 849 834 | 
             
                }
         | 
| 850 | 
            -
                 | 
| 851 | 
            -
                 | 
| 852 | 
            -
                 | 
| 853 | 
            -
                generate_json(buffer,  | 
| 835 | 
            +
                if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
         | 
| 836 | 
            +
                fbuffer_append_char(buffer, ':');
         | 
| 837 | 
            +
                if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
         | 
| 838 | 
            +
                generate_json(buffer, data, state, val);
         | 
| 854 839 |  | 
| 855 840 | 
             
                arg->iter++;
         | 
| 856 841 | 
             
                return ST_CONTINUE;
         | 
| 857 842 | 
             
            }
         | 
| 858 843 |  | 
| 859 | 
            -
            static  | 
| 844 | 
            +
            static inline long increase_depth(JSON_Generator_State *state)
         | 
| 860 845 | 
             
            {
         | 
| 861 | 
            -
                char *object_nl = state->object_nl;
         | 
| 862 | 
            -
                long object_nl_len = state->object_nl_len;
         | 
| 863 | 
            -
                char *indent = state->indent;
         | 
| 864 | 
            -
                long indent_len = state->indent_len;
         | 
| 865 | 
            -
                long max_nesting = state->max_nesting;
         | 
| 866 846 | 
             
                long depth = ++state->depth;
         | 
| 847 | 
            +
                if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
         | 
| 848 | 
            +
                    rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
         | 
| 849 | 
            +
                }
         | 
| 850 | 
            +
                return depth;
         | 
| 851 | 
            +
            }
         | 
| 852 | 
            +
             | 
| 853 | 
            +
            static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 854 | 
            +
            {
         | 
| 867 855 | 
             
                int j;
         | 
| 868 | 
            -
                 | 
| 856 | 
            +
                long depth = increase_depth(state);
         | 
| 869 857 |  | 
| 870 | 
            -
                if ( | 
| 871 | 
            -
                     | 
| 872 | 
            -
                     | 
| 858 | 
            +
                if (RHASH_SIZE(obj) == 0) {
         | 
| 859 | 
            +
                    fbuffer_append(buffer, "{}", 2);
         | 
| 860 | 
            +
                    --state->depth;
         | 
| 861 | 
            +
                    return;
         | 
| 873 862 | 
             
                }
         | 
| 863 | 
            +
             | 
| 874 864 | 
             
                fbuffer_append_char(buffer, '{');
         | 
| 875 865 |  | 
| 876 | 
            -
                arg | 
| 877 | 
            -
             | 
| 878 | 
            -
             | 
| 879 | 
            -
                 | 
| 866 | 
            +
                struct hash_foreach_arg arg = {
         | 
| 867 | 
            +
                    .data = data,
         | 
| 868 | 
            +
                    .iter = 0,
         | 
| 869 | 
            +
                };
         | 
| 880 870 | 
             
                rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
         | 
| 881 871 |  | 
| 882 872 | 
             
                depth = --state->depth;
         | 
| 883 | 
            -
                if (object_nl) {
         | 
| 884 | 
            -
                     | 
| 885 | 
            -
                    if (indent) {
         | 
| 873 | 
            +
                if (RB_UNLIKELY(state->object_nl)) {
         | 
| 874 | 
            +
                    fbuffer_append_str(buffer, state->object_nl);
         | 
| 875 | 
            +
                    if (RB_UNLIKELY(state->indent)) {
         | 
| 886 876 | 
             
                        for (j = 0; j < depth; j++) {
         | 
| 887 | 
            -
                             | 
| 877 | 
            +
                            fbuffer_append_str(buffer, state->indent);
         | 
| 888 878 | 
             
                        }
         | 
| 889 879 | 
             
                    }
         | 
| 890 880 | 
             
                }
         | 
| 891 881 | 
             
                fbuffer_append_char(buffer, '}');
         | 
| 892 882 | 
             
            }
         | 
| 893 883 |  | 
| 894 | 
            -
            static void generate_json_array(FBuffer *buffer,  | 
| 884 | 
            +
            static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 895 885 | 
             
            {
         | 
| 896 | 
            -
                char *array_nl = state->array_nl;
         | 
| 897 | 
            -
                long array_nl_len = state->array_nl_len;
         | 
| 898 | 
            -
                char *indent = state->indent;
         | 
| 899 | 
            -
                long indent_len = state->indent_len;
         | 
| 900 | 
            -
                long max_nesting = state->max_nesting;
         | 
| 901 | 
            -
                char *delim = FBUFFER_PTR(state->array_delim);
         | 
| 902 | 
            -
                long delim_len = FBUFFER_LEN(state->array_delim);
         | 
| 903 | 
            -
                long depth = ++state->depth;
         | 
| 904 886 | 
             
                int i, j;
         | 
| 905 | 
            -
                 | 
| 906 | 
            -
             | 
| 907 | 
            -
             | 
| 887 | 
            +
                long depth = increase_depth(state);
         | 
| 888 | 
            +
             | 
| 889 | 
            +
                if (RARRAY_LEN(obj) == 0) {
         | 
| 890 | 
            +
                    fbuffer_append(buffer, "[]", 2);
         | 
| 891 | 
            +
                    --state->depth;
         | 
| 892 | 
            +
                    return;
         | 
| 908 893 | 
             
                }
         | 
| 894 | 
            +
             | 
| 909 895 | 
             
                fbuffer_append_char(buffer, '[');
         | 
| 910 | 
            -
                if (array_nl)  | 
| 896 | 
            +
                if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
         | 
| 911 897 | 
             
                for(i = 0; i < RARRAY_LEN(obj); i++) {
         | 
| 912 | 
            -
                    if (i > 0)  | 
| 913 | 
            -
             | 
| 898 | 
            +
                    if (i > 0) {
         | 
| 899 | 
            +
                        fbuffer_append_char(buffer, ',');
         | 
| 900 | 
            +
                        if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
         | 
| 901 | 
            +
                    }
         | 
| 902 | 
            +
                    if (RB_UNLIKELY(state->indent)) {
         | 
| 914 903 | 
             
                        for (j = 0; j < depth; j++) {
         | 
| 915 | 
            -
                             | 
| 904 | 
            +
                            fbuffer_append_str(buffer, state->indent);
         | 
| 916 905 | 
             
                        }
         | 
| 917 906 | 
             
                    }
         | 
| 918 | 
            -
                    generate_json(buffer,  | 
| 907 | 
            +
                    generate_json(buffer, data, state, RARRAY_AREF(obj, i));
         | 
| 919 908 | 
             
                }
         | 
| 920 909 | 
             
                state->depth = --depth;
         | 
| 921 | 
            -
                if (array_nl) {
         | 
| 922 | 
            -
                     | 
| 923 | 
            -
                    if (indent) {
         | 
| 910 | 
            +
                if (RB_UNLIKELY(state->array_nl)) {
         | 
| 911 | 
            +
                    fbuffer_append_str(buffer, state->array_nl);
         | 
| 912 | 
            +
                    if (RB_UNLIKELY(state->indent)) {
         | 
| 924 913 | 
             
                        for (j = 0; j < depth; j++) {
         | 
| 925 | 
            -
                             | 
| 914 | 
            +
                            fbuffer_append_str(buffer, state->indent);
         | 
| 926 915 | 
             
                        }
         | 
| 927 916 | 
             
                    }
         | 
| 928 917 | 
             
                }
         | 
| 929 918 | 
             
                fbuffer_append_char(buffer, ']');
         | 
| 930 919 | 
             
            }
         | 
| 931 920 |  | 
| 932 | 
            -
             | 
| 933 | 
            -
            static int enc_utf8_compatible_p(rb_encoding *enc)
         | 
| 921 | 
            +
            static inline int enc_utf8_compatible_p(int enc_idx)
         | 
| 934 922 | 
             
            {
         | 
| 935 | 
            -
                if ( | 
| 936 | 
            -
                if ( | 
| 923 | 
            +
                if (enc_idx == usascii_encindex) return 1;
         | 
| 924 | 
            +
                if (enc_idx == utf8_encindex) return 1;
         | 
| 937 925 | 
             
                return 0;
         | 
| 938 926 | 
             
            }
         | 
| 939 | 
            -
            #endif
         | 
| 940 927 |  | 
| 941 | 
            -
            static  | 
| 928 | 
            +
            static VALUE encode_json_string_try(VALUE str)
         | 
| 942 929 | 
             
            {
         | 
| 930 | 
            +
                return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
         | 
| 931 | 
            +
            }
         | 
| 932 | 
            +
             | 
| 933 | 
            +
            static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
         | 
| 934 | 
            +
            {
         | 
| 935 | 
            +
                raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
         | 
| 936 | 
            +
                return Qundef;
         | 
| 937 | 
            +
            }
         | 
| 938 | 
            +
             | 
| 939 | 
            +
            static inline VALUE ensure_valid_encoding(VALUE str)
         | 
| 940 | 
            +
            {
         | 
| 941 | 
            +
                int encindex = RB_ENCODING_GET(str);
         | 
| 942 | 
            +
                VALUE utf8_string;
         | 
| 943 | 
            +
                if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
         | 
| 944 | 
            +
                    if (encindex == binary_encindex) {
         | 
| 945 | 
            +
                        utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
         | 
| 946 | 
            +
                        switch (rb_enc_str_coderange(utf8_string)) {
         | 
| 947 | 
            +
                            case ENC_CODERANGE_7BIT:
         | 
| 948 | 
            +
                                return utf8_string;
         | 
| 949 | 
            +
                            case ENC_CODERANGE_VALID:
         | 
| 950 | 
            +
                                // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
         | 
| 951 | 
            +
                                // TODO: Raise in 3.0.0
         | 
| 952 | 
            +
                                rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
         | 
| 953 | 
            +
                                return utf8_string;
         | 
| 954 | 
            +
                                break;
         | 
| 955 | 
            +
                        }
         | 
| 956 | 
            +
                    }
         | 
| 957 | 
            +
             | 
| 958 | 
            +
                    str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
         | 
| 959 | 
            +
                }
         | 
| 960 | 
            +
                return str;
         | 
| 961 | 
            +
            }
         | 
| 962 | 
            +
             | 
| 963 | 
            +
            static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 964 | 
            +
            {
         | 
| 965 | 
            +
                obj = ensure_valid_encoding(obj);
         | 
| 966 | 
            +
             | 
| 943 967 | 
             
                fbuffer_append_char(buffer, '"');
         | 
| 944 | 
            -
             | 
| 945 | 
            -
                 | 
| 946 | 
            -
             | 
| 968 | 
            +
             | 
| 969 | 
            +
                long len;
         | 
| 970 | 
            +
                search_state search;
         | 
| 971 | 
            +
                search.buffer = buffer;
         | 
| 972 | 
            +
                RSTRING_GETMEM(obj, search.ptr, len);
         | 
| 973 | 
            +
                search.cursor = search.ptr;
         | 
| 974 | 
            +
                search.end = search.ptr + len;
         | 
| 975 | 
            +
             | 
| 976 | 
            +
                switch(rb_enc_str_coderange(obj)) {
         | 
| 977 | 
            +
                    case ENC_CODERANGE_7BIT:
         | 
| 978 | 
            +
                    case ENC_CODERANGE_VALID:
         | 
| 979 | 
            +
                        if (RB_UNLIKELY(state->ascii_only)) {
         | 
| 980 | 
            +
                            convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
         | 
| 981 | 
            +
                        } else if (RB_UNLIKELY(state->script_safe)) {
         | 
| 982 | 
            +
                            convert_UTF8_to_script_safe_JSON(&search);
         | 
| 983 | 
            +
                        } else {
         | 
| 984 | 
            +
                            convert_UTF8_to_JSON(&search);
         | 
| 985 | 
            +
                        }
         | 
| 986 | 
            +
                        break;
         | 
| 987 | 
            +
                    default:
         | 
| 988 | 
            +
                        raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
         | 
| 989 | 
            +
                        break;
         | 
| 947 990 | 
             
                }
         | 
| 948 | 
            -
             | 
| 949 | 
            -
             | 
| 950 | 
            -
             | 
| 991 | 
            +
                fbuffer_append_char(buffer, '"');
         | 
| 992 | 
            +
            }
         | 
| 993 | 
            +
             | 
| 994 | 
            +
            static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 995 | 
            +
            {
         | 
| 996 | 
            +
                VALUE tmp;
         | 
| 997 | 
            +
                if (rb_respond_to(obj, i_to_json)) {
         | 
| 998 | 
            +
                    tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
         | 
| 999 | 
            +
                    Check_Type(tmp, T_STRING);
         | 
| 1000 | 
            +
                    fbuffer_append_str(buffer, tmp);
         | 
| 951 1001 | 
             
                } else {
         | 
| 952 | 
            -
                     | 
| 1002 | 
            +
                    tmp = rb_funcall(obj, i_to_s, 0);
         | 
| 1003 | 
            +
                    Check_Type(tmp, T_STRING);
         | 
| 1004 | 
            +
                    generate_json_string(buffer, data, state, tmp);
         | 
| 953 1005 | 
             
                }
         | 
| 954 | 
            -
                fbuffer_append_char(buffer, '"');
         | 
| 955 1006 | 
             
            }
         | 
| 956 1007 |  | 
| 957 | 
            -
            static void  | 
| 1008 | 
            +
            static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 1009 | 
            +
            {
         | 
| 1010 | 
            +
                if (state->strict) {
         | 
| 1011 | 
            +
                    generate_json_string(buffer, data, state, rb_sym2str(obj));
         | 
| 1012 | 
            +
                } else {
         | 
| 1013 | 
            +
                    generate_json_fallback(buffer, data, state, obj);
         | 
| 1014 | 
            +
                }
         | 
| 1015 | 
            +
            }
         | 
| 1016 | 
            +
             | 
| 1017 | 
            +
            static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 958 1018 | 
             
            {
         | 
| 959 1019 | 
             
                fbuffer_append(buffer, "null", 4);
         | 
| 960 1020 | 
             
            }
         | 
| 961 1021 |  | 
| 962 | 
            -
            static void generate_json_false(FBuffer *buffer,  | 
| 1022 | 
            +
            static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 963 1023 | 
             
            {
         | 
| 964 1024 | 
             
                fbuffer_append(buffer, "false", 5);
         | 
| 965 1025 | 
             
            }
         | 
| 966 1026 |  | 
| 967 | 
            -
            static void generate_json_true(FBuffer *buffer,  | 
| 1027 | 
            +
            static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 968 1028 | 
             
            {
         | 
| 969 1029 | 
             
                fbuffer_append(buffer, "true", 4);
         | 
| 970 1030 | 
             
            }
         | 
| 971 1031 |  | 
| 972 | 
            -
            static void generate_json_fixnum(FBuffer *buffer,  | 
| 1032 | 
            +
            static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 973 1033 | 
             
            {
         | 
| 974 1034 | 
             
                fbuffer_append_long(buffer, FIX2LONG(obj));
         | 
| 975 1035 | 
             
            }
         | 
| 976 1036 |  | 
| 977 | 
            -
            static void generate_json_bignum(FBuffer *buffer,  | 
| 1037 | 
            +
            static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 978 1038 | 
             
            {
         | 
| 979 1039 | 
             
                VALUE tmp = rb_funcall(obj, i_to_s, 0);
         | 
| 980 1040 | 
             
                fbuffer_append_str(buffer, tmp);
         | 
| 981 1041 | 
             
            }
         | 
| 982 1042 |  | 
| 983 1043 | 
             
            #ifdef RUBY_INTEGER_UNIFICATION
         | 
| 984 | 
            -
            static void generate_json_integer(FBuffer *buffer,  | 
| 1044 | 
            +
            static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 985 1045 | 
             
            {
         | 
| 986 1046 | 
             
                if (FIXNUM_P(obj))
         | 
| 987 | 
            -
                    generate_json_fixnum(buffer,  | 
| 1047 | 
            +
                    generate_json_fixnum(buffer, data, state, obj);
         | 
| 988 1048 | 
             
                else
         | 
| 989 | 
            -
                    generate_json_bignum(buffer,  | 
| 1049 | 
            +
                    generate_json_bignum(buffer, data, state, obj);
         | 
| 990 1050 | 
             
            }
         | 
| 991 1051 | 
             
            #endif
         | 
| 992 | 
            -
             | 
| 1052 | 
            +
             | 
| 1053 | 
            +
            static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 993 1054 | 
             
            {
         | 
| 994 1055 | 
             
                double value = RFLOAT_VALUE(obj);
         | 
| 995 1056 | 
             
                char allow_nan = state->allow_nan;
         | 
| 996 | 
            -
                VALUE tmp = rb_funcall(obj, i_to_s, 0);
         | 
| 997 1057 | 
             
                if (!allow_nan) {
         | 
| 998 | 
            -
                    if (isinf(value)) {
         | 
| 999 | 
            -
                         | 
| 1000 | 
            -
             | 
| 1001 | 
            -
             | 
| 1002 | 
            -
             | 
| 1003 | 
            -
             | 
| 1058 | 
            +
                    if (isinf(value) || isnan(value)) {
         | 
| 1059 | 
            +
                        if (state->strict && state->as_json) {
         | 
| 1060 | 
            +
                            VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
         | 
| 1061 | 
            +
                            if (casted_obj != obj) {
         | 
| 1062 | 
            +
                                increase_depth(state);
         | 
| 1063 | 
            +
                                generate_json(buffer, data, state, casted_obj);
         | 
| 1064 | 
            +
                                state->depth--;
         | 
| 1065 | 
            +
                                return;
         | 
| 1066 | 
            +
                            }
         | 
| 1067 | 
            +
                        }
         | 
| 1068 | 
            +
                        raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", rb_funcall(obj, i_to_s, 0));
         | 
| 1004 1069 | 
             
                    }
         | 
| 1005 1070 | 
             
                }
         | 
| 1006 | 
            -
                fbuffer_append_str(buffer,  | 
| 1071 | 
            +
                fbuffer_append_str(buffer, rb_funcall(obj, i_to_s, 0));
         | 
| 1007 1072 | 
             
            }
         | 
| 1008 1073 |  | 
| 1009 | 
            -
            static void  | 
| 1074 | 
            +
            static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 1010 1075 | 
             
            {
         | 
| 1011 | 
            -
                VALUE  | 
| 1012 | 
            -
                 | 
| 1013 | 
            -
                 | 
| 1014 | 
            -
             | 
| 1015 | 
            -
             | 
| 1016 | 
            -
             | 
| 1017 | 
            -
             | 
| 1018 | 
            -
             | 
| 1019 | 
            -
             | 
| 1020 | 
            -
             | 
| 1076 | 
            +
                VALUE fragment = RSTRUCT_GET(obj, 0);
         | 
| 1077 | 
            +
                Check_Type(fragment, T_STRING);
         | 
| 1078 | 
            +
                fbuffer_append_str(buffer, fragment);
         | 
| 1079 | 
            +
            }
         | 
| 1080 | 
            +
             | 
| 1081 | 
            +
            static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
         | 
| 1082 | 
            +
            {
         | 
| 1083 | 
            +
                bool as_json_called = false;
         | 
| 1084 | 
            +
            start:
         | 
| 1085 | 
            +
                if (obj == Qnil) {
         | 
| 1086 | 
            +
                    generate_json_null(buffer, data, state, obj);
         | 
| 1021 1087 | 
             
                } else if (obj == Qfalse) {
         | 
| 1022 | 
            -
                    generate_json_false(buffer,  | 
| 1088 | 
            +
                    generate_json_false(buffer, data, state, obj);
         | 
| 1023 1089 | 
             
                } else if (obj == Qtrue) {
         | 
| 1024 | 
            -
                    generate_json_true(buffer,  | 
| 1025 | 
            -
                } else if ( | 
| 1026 | 
            -
                     | 
| 1027 | 
            -
             | 
| 1028 | 
            -
                     | 
| 1029 | 
            -
             | 
| 1030 | 
            -
                     | 
| 1031 | 
            -
             | 
| 1032 | 
            -
                     | 
| 1033 | 
            -
             | 
| 1034 | 
            -
                     | 
| 1090 | 
            +
                    generate_json_true(buffer, data, state, obj);
         | 
| 1091 | 
            +
                } else if (RB_SPECIAL_CONST_P(obj)) {
         | 
| 1092 | 
            +
                    if (RB_FIXNUM_P(obj)) {
         | 
| 1093 | 
            +
                        generate_json_fixnum(buffer, data, state, obj);
         | 
| 1094 | 
            +
                    } else if (RB_FLONUM_P(obj)) {
         | 
| 1095 | 
            +
                        generate_json_float(buffer, data, state, obj);
         | 
| 1096 | 
            +
                    } else if (RB_STATIC_SYM_P(obj)) {
         | 
| 1097 | 
            +
                        generate_json_symbol(buffer, data, state, obj);
         | 
| 1098 | 
            +
                    } else {
         | 
| 1099 | 
            +
                        goto general;
         | 
| 1100 | 
            +
                    }
         | 
| 1035 1101 | 
             
                } else {
         | 
| 1036 | 
            -
                     | 
| 1037 | 
            -
                     | 
| 1038 | 
            -
             | 
| 1102 | 
            +
                    VALUE klass = RBASIC_CLASS(obj);
         | 
| 1103 | 
            +
                    switch (RB_BUILTIN_TYPE(obj)) {
         | 
| 1104 | 
            +
                        case T_BIGNUM:
         | 
| 1105 | 
            +
                            generate_json_bignum(buffer, data, state, obj);
         | 
| 1106 | 
            +
                            break;
         | 
| 1107 | 
            +
                        case T_HASH:
         | 
| 1108 | 
            +
                            if (klass != rb_cHash) goto general;
         | 
| 1109 | 
            +
                            generate_json_object(buffer, data, state, obj);
         | 
| 1110 | 
            +
                            break;
         | 
| 1111 | 
            +
                        case T_ARRAY:
         | 
| 1112 | 
            +
                            if (klass != rb_cArray) goto general;
         | 
| 1113 | 
            +
                            generate_json_array(buffer, data, state, obj);
         | 
| 1114 | 
            +
                            break;
         | 
| 1115 | 
            +
                        case T_STRING:
         | 
| 1116 | 
            +
                            if (klass != rb_cString) goto general;
         | 
| 1117 | 
            +
                            generate_json_string(buffer, data, state, obj);
         | 
| 1118 | 
            +
                            break;
         | 
| 1119 | 
            +
                        case T_SYMBOL:
         | 
| 1120 | 
            +
                            generate_json_symbol(buffer, data, state, obj);
         | 
| 1121 | 
            +
                            break;
         | 
| 1122 | 
            +
                        case T_FLOAT:
         | 
| 1123 | 
            +
                            if (klass != rb_cFloat) goto general;
         | 
| 1124 | 
            +
                            generate_json_float(buffer, data, state, obj);
         | 
| 1125 | 
            +
                            break;
         | 
| 1126 | 
            +
                        case T_STRUCT:
         | 
| 1127 | 
            +
                            if (klass != cFragment) goto general;
         | 
| 1128 | 
            +
                            generate_json_fragment(buffer, data, state, obj);
         | 
| 1129 | 
            +
                            break;
         | 
| 1130 | 
            +
                        default:
         | 
| 1131 | 
            +
                        general:
         | 
| 1132 | 
            +
                            if (state->strict) {
         | 
| 1133 | 
            +
                                if (RTEST(state->as_json) && !as_json_called) {
         | 
| 1134 | 
            +
                                    obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
         | 
| 1135 | 
            +
                                    as_json_called = true;
         | 
| 1136 | 
            +
                                    goto start;
         | 
| 1137 | 
            +
                                } else {
         | 
| 1138 | 
            +
                                    raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
         | 
| 1139 | 
            +
                                }
         | 
| 1140 | 
            +
                            } else {
         | 
| 1141 | 
            +
                                generate_json_fallback(buffer, data, state, obj);
         | 
| 1142 | 
            +
                            }
         | 
| 1143 | 
            +
                    }
         | 
| 1039 1144 | 
             
                }
         | 
| 1040 1145 | 
             
            }
         | 
| 1041 1146 |  | 
| 1042 | 
            -
            static  | 
| 1147 | 
            +
            static VALUE generate_json_try(VALUE d)
         | 
| 1043 1148 | 
             
            {
         | 
| 1044 | 
            -
                 | 
| 1045 | 
            -
                GET_STATE(self);
         | 
| 1046 | 
            -
                buffer = fbuffer_alloc(state->buffer_initial_length);
         | 
| 1149 | 
            +
                struct generate_json_data *data = (struct generate_json_data *)d;
         | 
| 1047 1150 |  | 
| 1048 | 
            -
                 | 
| 1049 | 
            -
                    fbuffer_clear(state->object_delim);
         | 
| 1050 | 
            -
                } else {
         | 
| 1051 | 
            -
                    state->object_delim = fbuffer_alloc(16);
         | 
| 1052 | 
            -
                }
         | 
| 1053 | 
            -
                fbuffer_append_char(state->object_delim, ',');
         | 
| 1054 | 
            -
                if (state->object_delim2) {
         | 
| 1055 | 
            -
                    fbuffer_clear(state->object_delim2);
         | 
| 1056 | 
            -
                } else {
         | 
| 1057 | 
            -
                    state->object_delim2 = fbuffer_alloc(16);
         | 
| 1058 | 
            -
                }
         | 
| 1059 | 
            -
                if (state->space_before) fbuffer_append(state->object_delim2, state->space_before, state->space_before_len);
         | 
| 1060 | 
            -
                fbuffer_append_char(state->object_delim2, ':');
         | 
| 1061 | 
            -
                if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
         | 
| 1151 | 
            +
                data->func(data->buffer, data, data->state, data->obj);
         | 
| 1062 1152 |  | 
| 1063 | 
            -
                 | 
| 1064 | 
            -
                    fbuffer_clear(state->array_delim);
         | 
| 1065 | 
            -
                } else {
         | 
| 1066 | 
            -
                    state->array_delim = fbuffer_alloc(16);
         | 
| 1067 | 
            -
                }
         | 
| 1068 | 
            -
                fbuffer_append_char(state->array_delim, ',');
         | 
| 1069 | 
            -
                if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len);
         | 
| 1070 | 
            -
                return buffer;
         | 
| 1153 | 
            +
                return Qnil;
         | 
| 1071 1154 | 
             
            }
         | 
| 1072 1155 |  | 
| 1073 | 
            -
            static VALUE  | 
| 1156 | 
            +
            static VALUE generate_json_rescue(VALUE d, VALUE exc)
         | 
| 1157 | 
            +
            {
         | 
| 1158 | 
            +
                struct generate_json_data *data = (struct generate_json_data *)d;
         | 
| 1159 | 
            +
                fbuffer_free(data->buffer);
         | 
| 1160 | 
            +
             | 
| 1161 | 
            +
                rb_exc_raise(exc);
         | 
| 1162 | 
            +
             | 
| 1163 | 
            +
                return Qundef;
         | 
| 1164 | 
            +
            }
         | 
| 1165 | 
            +
             | 
| 1166 | 
            +
            static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
         | 
| 1074 1167 | 
             
            {
         | 
| 1075 | 
            -
                FBuffer *buffer = cState_prepare_buffer(self);
         | 
| 1076 1168 | 
             
                GET_STATE(self);
         | 
| 1077 | 
            -
             | 
| 1078 | 
            -
                 | 
| 1169 | 
            +
             | 
| 1170 | 
            +
                char stack_buffer[FBUFFER_STACK_SIZE];
         | 
| 1171 | 
            +
                FBuffer buffer = {
         | 
| 1172 | 
            +
                    .io = RTEST(io) ? io : Qfalse,
         | 
| 1173 | 
            +
                };
         | 
| 1174 | 
            +
                fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
         | 
| 1175 | 
            +
             | 
| 1176 | 
            +
                struct generate_json_data data = {
         | 
| 1177 | 
            +
                    .buffer = &buffer,
         | 
| 1178 | 
            +
                    .vstate = self,
         | 
| 1179 | 
            +
                    .state = state,
         | 
| 1180 | 
            +
                    .obj = obj,
         | 
| 1181 | 
            +
                    .func = func
         | 
| 1182 | 
            +
                };
         | 
| 1183 | 
            +
                rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
         | 
| 1184 | 
            +
             | 
| 1185 | 
            +
                return fbuffer_finalize(&buffer);
         | 
| 1079 1186 | 
             
            }
         | 
| 1080 1187 |  | 
| 1081 | 
            -
            /*
         | 
| 1082 | 
            -
             * | 
| 1188 | 
            +
            /* call-seq:
         | 
| 1189 | 
            +
             *   generate(obj) -> String
         | 
| 1190 | 
            +
             *   generate(obj, anIO) -> anIO
         | 
| 1083 1191 | 
             
             *
         | 
| 1084 1192 | 
             
             * Generates a valid JSON document from object +obj+ and returns the
         | 
| 1085 1193 | 
             
             * result. If no valid JSON document can be created this method raises a
         | 
| 1086 1194 | 
             
             * GeneratorError exception.
         | 
| 1087 1195 | 
             
             */
         | 
| 1088 | 
            -
            static VALUE cState_generate(VALUE  | 
| 1196 | 
            +
            static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
         | 
| 1089 1197 | 
             
            {
         | 
| 1090 | 
            -
                 | 
| 1198 | 
            +
                rb_check_arity(argc, 1, 2);
         | 
| 1199 | 
            +
                VALUE obj = argv[0];
         | 
| 1200 | 
            +
                VALUE io = argc > 1 ? argv[1] : Qnil;
         | 
| 1201 | 
            +
                VALUE result = cState_partial_generate(self, obj, generate_json, io);
         | 
| 1091 1202 | 
             
                GET_STATE(self);
         | 
| 1092 1203 | 
             
                (void)state;
         | 
| 1093 1204 | 
             
                return result;
         | 
| 1094 1205 | 
             
            }
         | 
| 1095 1206 |  | 
| 1096 | 
            -
            /*
         | 
| 1097 | 
            -
             * call-seq: new(opts = {})
         | 
| 1098 | 
            -
             *
         | 
| 1099 | 
            -
             * Instantiates a new State object, configured by _opts_.
         | 
| 1100 | 
            -
             *
         | 
| 1101 | 
            -
             * _opts_ can have the following keys:
         | 
| 1102 | 
            -
             *
         | 
| 1103 | 
            -
             * * *indent*: a string used to indent levels (default: ''),
         | 
| 1104 | 
            -
             * * *space*: a string that is put after, a : or , delimiter (default: ''),
         | 
| 1105 | 
            -
             * * *space_before*: a string that is put before a : pair delimiter (default: ''),
         | 
| 1106 | 
            -
             * * *object_nl*: a string that is put at the end of a JSON object (default: ''),
         | 
| 1107 | 
            -
             * * *array_nl*: a string that is put at the end of a JSON array (default: ''),
         | 
| 1108 | 
            -
             * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
         | 
| 1109 | 
            -
             *   generated, otherwise an exception is thrown, if these values are
         | 
| 1110 | 
            -
             *   encountered. This options defaults to false.
         | 
| 1111 | 
            -
             * * *ascii_only*: true if only ASCII characters should be generated. This
         | 
| 1112 | 
            -
             *   option defaults to false.
         | 
| 1113 | 
            -
             * * *buffer_initial_length*: sets the initial length of the generator's
         | 
| 1114 | 
            -
             *   internal buffer.
         | 
| 1115 | 
            -
             */
         | 
| 1116 1207 | 
             
            static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
         | 
| 1117 1208 | 
             
            {
         | 
| 1118 | 
            -
                 | 
| 1119 | 
            -
                GET_STATE(self);
         | 
| 1120 | 
            -
                state->max_nesting = 100;
         | 
| 1121 | 
            -
                state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
         | 
| 1122 | 
            -
                rb_scan_args(argc, argv, "01", &opts);
         | 
| 1123 | 
            -
                if (!NIL_P(opts)) cState_configure(self, opts);
         | 
| 1209 | 
            +
                rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
         | 
| 1124 1210 | 
             
                return self;
         | 
| 1125 1211 | 
             
            }
         | 
| 1126 1212 |  | 
| @@ -1140,14 +1226,12 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig) | |
| 1140 1226 | 
             
                if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
         | 
| 1141 1227 |  | 
| 1142 1228 | 
             
                MEMCPY(objState, origState, JSON_Generator_State, 1);
         | 
| 1143 | 
            -
                objState->indent =  | 
| 1144 | 
            -
                objState->space =  | 
| 1145 | 
            -
                objState->space_before =  | 
| 1146 | 
            -
                objState->object_nl =  | 
| 1147 | 
            -
                objState->array_nl =  | 
| 1148 | 
            -
                 | 
| 1149 | 
            -
                if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim);
         | 
| 1150 | 
            -
                if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2);
         | 
| 1229 | 
            +
                objState->indent = origState->indent;
         | 
| 1230 | 
            +
                objState->space = origState->space;
         | 
| 1231 | 
            +
                objState->space_before = origState->space_before;
         | 
| 1232 | 
            +
                objState->object_nl = origState->object_nl;
         | 
| 1233 | 
            +
                objState->array_nl = origState->array_nl;
         | 
| 1234 | 
            +
                objState->as_json = origState->as_json;
         | 
| 1151 1235 | 
             
                return obj;
         | 
| 1152 1236 | 
             
            }
         | 
| 1153 1237 |  | 
| @@ -1177,7 +1261,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts) | |
| 1177 1261 | 
             
            static VALUE cState_indent(VALUE self)
         | 
| 1178 1262 | 
             
            {
         | 
| 1179 1263 | 
             
                GET_STATE(self);
         | 
| 1180 | 
            -
                return state->indent ?  | 
| 1264 | 
            +
                return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
         | 
| 1265 | 
            +
            }
         | 
| 1266 | 
            +
             | 
| 1267 | 
            +
            static VALUE string_config(VALUE config)
         | 
| 1268 | 
            +
            {
         | 
| 1269 | 
            +
                if (RTEST(config)) {
         | 
| 1270 | 
            +
                    Check_Type(config, T_STRING);
         | 
| 1271 | 
            +
                    if (RSTRING_LEN(config)) {
         | 
| 1272 | 
            +
                        return rb_str_new_frozen(config);
         | 
| 1273 | 
            +
                    }
         | 
| 1274 | 
            +
                }
         | 
| 1275 | 
            +
                return Qfalse;
         | 
| 1181 1276 | 
             
            }
         | 
| 1182 1277 |  | 
| 1183 1278 | 
             
            /*
         | 
| @@ -1187,21 +1282,8 @@ static VALUE cState_indent(VALUE self) | |
| 1187 1282 | 
             
             */
         | 
| 1188 1283 | 
             
            static VALUE cState_indent_set(VALUE self, VALUE indent)
         | 
| 1189 1284 | 
             
            {
         | 
| 1190 | 
            -
                unsigned long len;
         | 
| 1191 1285 | 
             
                GET_STATE(self);
         | 
| 1192 | 
            -
                 | 
| 1193 | 
            -
                len = RSTRING_LEN(indent);
         | 
| 1194 | 
            -
                if (len == 0) {
         | 
| 1195 | 
            -
                    if (state->indent) {
         | 
| 1196 | 
            -
                        ruby_xfree(state->indent);
         | 
| 1197 | 
            -
                        state->indent = NULL;
         | 
| 1198 | 
            -
                        state->indent_len = 0;
         | 
| 1199 | 
            -
                    }
         | 
| 1200 | 
            -
                } else {
         | 
| 1201 | 
            -
                    if (state->indent) ruby_xfree(state->indent);
         | 
| 1202 | 
            -
                    state->indent = fstrndup(RSTRING_PTR(indent), len);
         | 
| 1203 | 
            -
                    state->indent_len = len;
         | 
| 1204 | 
            -
                }
         | 
| 1286 | 
            +
                RB_OBJ_WRITE(self, &state->indent, string_config(indent));
         | 
| 1205 1287 | 
             
                return Qnil;
         | 
| 1206 1288 | 
             
            }
         | 
| 1207 1289 |  | 
| @@ -1214,7 +1296,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent) | |
| 1214 1296 | 
             
            static VALUE cState_space(VALUE self)
         | 
| 1215 1297 | 
             
            {
         | 
| 1216 1298 | 
             
                GET_STATE(self);
         | 
| 1217 | 
            -
                return state->space ?  | 
| 1299 | 
            +
                return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
         | 
| 1218 1300 | 
             
            }
         | 
| 1219 1301 |  | 
| 1220 1302 | 
             
            /*
         | 
| @@ -1225,21 +1307,8 @@ static VALUE cState_space(VALUE self) | |
| 1225 1307 | 
             
             */
         | 
| 1226 1308 | 
             
            static VALUE cState_space_set(VALUE self, VALUE space)
         | 
| 1227 1309 | 
             
            {
         | 
| 1228 | 
            -
                unsigned long len;
         | 
| 1229 1310 | 
             
                GET_STATE(self);
         | 
| 1230 | 
            -
                 | 
| 1231 | 
            -
                len = RSTRING_LEN(space);
         | 
| 1232 | 
            -
                if (len == 0) {
         | 
| 1233 | 
            -
                    if (state->space) {
         | 
| 1234 | 
            -
                        ruby_xfree(state->space);
         | 
| 1235 | 
            -
                        state->space = NULL;
         | 
| 1236 | 
            -
                        state->space_len = 0;
         | 
| 1237 | 
            -
                    }
         | 
| 1238 | 
            -
                } else {
         | 
| 1239 | 
            -
                    if (state->space) ruby_xfree(state->space);
         | 
| 1240 | 
            -
                    state->space = fstrndup(RSTRING_PTR(space), len);
         | 
| 1241 | 
            -
                    state->space_len = len;
         | 
| 1242 | 
            -
                }
         | 
| 1311 | 
            +
                RB_OBJ_WRITE(self, &state->space, string_config(space));
         | 
| 1243 1312 | 
             
                return Qnil;
         | 
| 1244 1313 | 
             
            }
         | 
| 1245 1314 |  | 
| @@ -1251,7 +1320,7 @@ static VALUE cState_space_set(VALUE self, VALUE space) | |
| 1251 1320 | 
             
            static VALUE cState_space_before(VALUE self)
         | 
| 1252 1321 | 
             
            {
         | 
| 1253 1322 | 
             
                GET_STATE(self);
         | 
| 1254 | 
            -
                return state->space_before ?  | 
| 1323 | 
            +
                return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
         | 
| 1255 1324 | 
             
            }
         | 
| 1256 1325 |  | 
| 1257 1326 | 
             
            /*
         | 
| @@ -1261,21 +1330,8 @@ static VALUE cState_space_before(VALUE self) | |
| 1261 1330 | 
             
             */
         | 
| 1262 1331 | 
             
            static VALUE cState_space_before_set(VALUE self, VALUE space_before)
         | 
| 1263 1332 | 
             
            {
         | 
| 1264 | 
            -
                unsigned long len;
         | 
| 1265 1333 | 
             
                GET_STATE(self);
         | 
| 1266 | 
            -
                 | 
| 1267 | 
            -
                len = RSTRING_LEN(space_before);
         | 
| 1268 | 
            -
                if (len == 0) {
         | 
| 1269 | 
            -
                    if (state->space_before) {
         | 
| 1270 | 
            -
                        ruby_xfree(state->space_before);
         | 
| 1271 | 
            -
                        state->space_before = NULL;
         | 
| 1272 | 
            -
                        state->space_before_len = 0;
         | 
| 1273 | 
            -
                    }
         | 
| 1274 | 
            -
                } else {
         | 
| 1275 | 
            -
                    if (state->space_before) ruby_xfree(state->space_before);
         | 
| 1276 | 
            -
                    state->space_before = fstrndup(RSTRING_PTR(space_before), len);
         | 
| 1277 | 
            -
                    state->space_before_len = len;
         | 
| 1278 | 
            -
                }
         | 
| 1334 | 
            +
                RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
         | 
| 1279 1335 | 
             
                return Qnil;
         | 
| 1280 1336 | 
             
            }
         | 
| 1281 1337 |  | 
| @@ -1288,7 +1344,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before) | |
| 1288 1344 | 
             
            static VALUE cState_object_nl(VALUE self)
         | 
| 1289 1345 | 
             
            {
         | 
| 1290 1346 | 
             
                GET_STATE(self);
         | 
| 1291 | 
            -
                return state->object_nl ?  | 
| 1347 | 
            +
                return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
         | 
| 1292 1348 | 
             
            }
         | 
| 1293 1349 |  | 
| 1294 1350 | 
             
            /*
         | 
| @@ -1299,20 +1355,8 @@ static VALUE cState_object_nl(VALUE self) | |
| 1299 1355 | 
             
             */
         | 
| 1300 1356 | 
             
            static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
         | 
| 1301 1357 | 
             
            {
         | 
| 1302 | 
            -
                unsigned long len;
         | 
| 1303 1358 | 
             
                GET_STATE(self);
         | 
| 1304 | 
            -
                 | 
| 1305 | 
            -
                len = RSTRING_LEN(object_nl);
         | 
| 1306 | 
            -
                if (len == 0) {
         | 
| 1307 | 
            -
                    if (state->object_nl) {
         | 
| 1308 | 
            -
                        ruby_xfree(state->object_nl);
         | 
| 1309 | 
            -
                        state->object_nl = NULL;
         | 
| 1310 | 
            -
                    }
         | 
| 1311 | 
            -
                } else {
         | 
| 1312 | 
            -
                    if (state->object_nl) ruby_xfree(state->object_nl);
         | 
| 1313 | 
            -
                    state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
         | 
| 1314 | 
            -
                    state->object_nl_len = len;
         | 
| 1315 | 
            -
                }
         | 
| 1359 | 
            +
                RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
         | 
| 1316 1360 | 
             
                return Qnil;
         | 
| 1317 1361 | 
             
            }
         | 
| 1318 1362 |  | 
| @@ -1324,7 +1368,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl) | |
| 1324 1368 | 
             
            static VALUE cState_array_nl(VALUE self)
         | 
| 1325 1369 | 
             
            {
         | 
| 1326 1370 | 
             
                GET_STATE(self);
         | 
| 1327 | 
            -
                return state->array_nl ?  | 
| 1371 | 
            +
                return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
         | 
| 1328 1372 | 
             
            }
         | 
| 1329 1373 |  | 
| 1330 1374 | 
             
            /*
         | 
| @@ -1334,23 +1378,33 @@ static VALUE cState_array_nl(VALUE self) | |
| 1334 1378 | 
             
             */
         | 
| 1335 1379 | 
             
            static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
         | 
| 1336 1380 | 
             
            {
         | 
| 1337 | 
            -
                unsigned long len;
         | 
| 1338 1381 | 
             
                GET_STATE(self);
         | 
| 1339 | 
            -
                 | 
| 1340 | 
            -
                len = RSTRING_LEN(array_nl);
         | 
| 1341 | 
            -
                if (len == 0) {
         | 
| 1342 | 
            -
                    if (state->array_nl) {
         | 
| 1343 | 
            -
                        ruby_xfree(state->array_nl);
         | 
| 1344 | 
            -
                        state->array_nl = NULL;
         | 
| 1345 | 
            -
                    }
         | 
| 1346 | 
            -
                } else {
         | 
| 1347 | 
            -
                    if (state->array_nl) ruby_xfree(state->array_nl);
         | 
| 1348 | 
            -
                    state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
         | 
| 1349 | 
            -
                    state->array_nl_len = len;
         | 
| 1350 | 
            -
                }
         | 
| 1382 | 
            +
                RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
         | 
| 1351 1383 | 
             
                return Qnil;
         | 
| 1352 1384 | 
             
            }
         | 
| 1353 1385 |  | 
| 1386 | 
            +
            /*
         | 
| 1387 | 
            +
             * call-seq: as_json()
         | 
| 1388 | 
            +
             *
         | 
| 1389 | 
            +
             * This string is put at the end of a line that holds a JSON array.
         | 
| 1390 | 
            +
             */
         | 
| 1391 | 
            +
            static VALUE cState_as_json(VALUE self)
         | 
| 1392 | 
            +
            {
         | 
| 1393 | 
            +
                GET_STATE(self);
         | 
| 1394 | 
            +
                return state->as_json;
         | 
| 1395 | 
            +
            }
         | 
| 1396 | 
            +
             | 
| 1397 | 
            +
            /*
         | 
| 1398 | 
            +
             * call-seq: as_json=(as_json)
         | 
| 1399 | 
            +
             *
         | 
| 1400 | 
            +
             * This string is put at the end of a line that holds a JSON array.
         | 
| 1401 | 
            +
             */
         | 
| 1402 | 
            +
            static VALUE cState_as_json_set(VALUE self, VALUE as_json)
         | 
| 1403 | 
            +
            {
         | 
| 1404 | 
            +
                GET_STATE(self);
         | 
| 1405 | 
            +
                RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
         | 
| 1406 | 
            +
                return Qnil;
         | 
| 1407 | 
            +
            }
         | 
| 1354 1408 |  | 
| 1355 1409 | 
             
            /*
         | 
| 1356 1410 | 
             
            * call-seq: check_circular?
         | 
| @@ -1376,6 +1430,11 @@ static VALUE cState_max_nesting(VALUE self) | |
| 1376 1430 | 
             
                return LONG2FIX(state->max_nesting);
         | 
| 1377 1431 | 
             
            }
         | 
| 1378 1432 |  | 
| 1433 | 
            +
            static long long_config(VALUE num)
         | 
| 1434 | 
            +
            {
         | 
| 1435 | 
            +
                return RTEST(num) ? FIX2LONG(num) : 0;
         | 
| 1436 | 
            +
            }
         | 
| 1437 | 
            +
             | 
| 1379 1438 | 
             
            /*
         | 
| 1380 1439 | 
             
             * call-seq: max_nesting=(depth)
         | 
| 1381 1440 | 
             
             *
         | 
| @@ -1385,32 +1444,63 @@ static VALUE cState_max_nesting(VALUE self) | |
| 1385 1444 | 
             
            static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
         | 
| 1386 1445 | 
             
            {
         | 
| 1387 1446 | 
             
                GET_STATE(self);
         | 
| 1388 | 
            -
                 | 
| 1389 | 
            -
                return  | 
| 1447 | 
            +
                state->max_nesting = long_config(depth);
         | 
| 1448 | 
            +
                return Qnil;
         | 
| 1390 1449 | 
             
            }
         | 
| 1391 1450 |  | 
| 1392 1451 | 
             
            /*
         | 
| 1393 | 
            -
             * call-seq:  | 
| 1452 | 
            +
             * call-seq: script_safe
         | 
| 1394 1453 | 
             
             *
         | 
| 1395 1454 | 
             
             * If this boolean is true, the forward slashes will be escaped in
         | 
| 1396 1455 | 
             
             * the json output.
         | 
| 1397 1456 | 
             
             */
         | 
| 1398 | 
            -
            static VALUE  | 
| 1457 | 
            +
            static VALUE cState_script_safe(VALUE self)
         | 
| 1399 1458 | 
             
            {
         | 
| 1400 1459 | 
             
                GET_STATE(self);
         | 
| 1401 | 
            -
                return state-> | 
| 1460 | 
            +
                return state->script_safe ? Qtrue : Qfalse;
         | 
| 1402 1461 | 
             
            }
         | 
| 1403 1462 |  | 
| 1404 1463 | 
             
            /*
         | 
| 1405 | 
            -
             * call-seq:  | 
| 1464 | 
            +
             * call-seq: script_safe=(enable)
         | 
| 1406 1465 | 
             
             *
         | 
| 1407 1466 | 
             
             * This sets whether or not the forward slashes will be escaped in
         | 
| 1408 1467 | 
             
             * the json output.
         | 
| 1409 1468 | 
             
             */
         | 
| 1410 | 
            -
            static VALUE  | 
| 1469 | 
            +
            static VALUE cState_script_safe_set(VALUE self, VALUE enable)
         | 
| 1470 | 
            +
            {
         | 
| 1471 | 
            +
                GET_STATE(self);
         | 
| 1472 | 
            +
                state->script_safe = RTEST(enable);
         | 
| 1473 | 
            +
                return Qnil;
         | 
| 1474 | 
            +
            }
         | 
| 1475 | 
            +
             | 
| 1476 | 
            +
            /*
         | 
| 1477 | 
            +
             * call-seq: strict
         | 
| 1478 | 
            +
             *
         | 
| 1479 | 
            +
             * If this boolean is false, types unsupported by the JSON format will
         | 
| 1480 | 
            +
             * be serialized as strings.
         | 
| 1481 | 
            +
             * If this boolean is true, types unsupported by the JSON format will
         | 
| 1482 | 
            +
             * raise a JSON::GeneratorError.
         | 
| 1483 | 
            +
             */
         | 
| 1484 | 
            +
            static VALUE cState_strict(VALUE self)
         | 
| 1411 1485 | 
             
            {
         | 
| 1412 1486 | 
             
                GET_STATE(self);
         | 
| 1413 | 
            -
                state-> | 
| 1487 | 
            +
                return state->strict ? Qtrue : Qfalse;
         | 
| 1488 | 
            +
            }
         | 
| 1489 | 
            +
             | 
| 1490 | 
            +
            /*
         | 
| 1491 | 
            +
             * call-seq: strict=(enable)
         | 
| 1492 | 
            +
             *
         | 
| 1493 | 
            +
             * This sets whether or not to serialize types unsupported by the
         | 
| 1494 | 
            +
             * JSON format as strings.
         | 
| 1495 | 
            +
             * If this boolean is false, types unsupported by the JSON format will
         | 
| 1496 | 
            +
             * be serialized as strings.
         | 
| 1497 | 
            +
             * If this boolean is true, types unsupported by the JSON format will
         | 
| 1498 | 
            +
             * raise a JSON::GeneratorError.
         | 
| 1499 | 
            +
             */
         | 
| 1500 | 
            +
            static VALUE cState_strict_set(VALUE self, VALUE enable)
         | 
| 1501 | 
            +
            {
         | 
| 1502 | 
            +
                GET_STATE(self);
         | 
| 1503 | 
            +
                state->strict = RTEST(enable);
         | 
| 1414 1504 | 
             
                return Qnil;
         | 
| 1415 1505 | 
             
            }
         | 
| 1416 1506 |  | 
| @@ -1426,6 +1516,18 @@ static VALUE cState_allow_nan_p(VALUE self) | |
| 1426 1516 | 
             
                return state->allow_nan ? Qtrue : Qfalse;
         | 
| 1427 1517 | 
             
            }
         | 
| 1428 1518 |  | 
| 1519 | 
            +
            /*
         | 
| 1520 | 
            +
             * call-seq: allow_nan=(enable)
         | 
| 1521 | 
            +
             *
         | 
| 1522 | 
            +
             * This sets whether or not to serialize NaN, Infinity, and -Infinity
         | 
| 1523 | 
            +
             */
         | 
| 1524 | 
            +
            static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
         | 
| 1525 | 
            +
            {
         | 
| 1526 | 
            +
                GET_STATE(self);
         | 
| 1527 | 
            +
                state->allow_nan = RTEST(enable);
         | 
| 1528 | 
            +
                return Qnil;
         | 
| 1529 | 
            +
            }
         | 
| 1530 | 
            +
             | 
| 1429 1531 | 
             
            /*
         | 
| 1430 1532 | 
             
             * call-seq: ascii_only?
         | 
| 1431 1533 | 
             
             *
         | 
| @@ -1438,6 +1540,18 @@ static VALUE cState_ascii_only_p(VALUE self) | |
| 1438 1540 | 
             
                return state->ascii_only ? Qtrue : Qfalse;
         | 
| 1439 1541 | 
             
            }
         | 
| 1440 1542 |  | 
| 1543 | 
            +
            /*
         | 
| 1544 | 
            +
             * call-seq: ascii_only=(enable)
         | 
| 1545 | 
            +
             *
         | 
| 1546 | 
            +
             * This sets whether only ASCII characters should be generated.
         | 
| 1547 | 
            +
             */
         | 
| 1548 | 
            +
            static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
         | 
| 1549 | 
            +
            {
         | 
| 1550 | 
            +
                GET_STATE(self);
         | 
| 1551 | 
            +
                state->ascii_only = RTEST(enable);
         | 
| 1552 | 
            +
                return Qnil;
         | 
| 1553 | 
            +
            }
         | 
| 1554 | 
            +
             | 
| 1441 1555 | 
             
            /*
         | 
| 1442 1556 | 
             
             * call-seq: depth
         | 
| 1443 1557 | 
             
             *
         | 
| @@ -1458,8 +1572,7 @@ static VALUE cState_depth(VALUE self) | |
| 1458 1572 | 
             
            static VALUE cState_depth_set(VALUE self, VALUE depth)
         | 
| 1459 1573 | 
             
            {
         | 
| 1460 1574 | 
             
                GET_STATE(self);
         | 
| 1461 | 
            -
                 | 
| 1462 | 
            -
                state->depth = FIX2LONG(depth);
         | 
| 1575 | 
            +
                state->depth = long_config(depth);
         | 
| 1463 1576 | 
             
                return Qnil;
         | 
| 1464 1577 | 
             
            }
         | 
| 1465 1578 |  | 
| @@ -1474,6 +1587,15 @@ static VALUE cState_buffer_initial_length(VALUE self) | |
| 1474 1587 | 
             
                return LONG2FIX(state->buffer_initial_length);
         | 
| 1475 1588 | 
             
            }
         | 
| 1476 1589 |  | 
| 1590 | 
            +
            static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
         | 
| 1591 | 
            +
            {
         | 
| 1592 | 
            +
                Check_Type(buffer_initial_length, T_FIXNUM);
         | 
| 1593 | 
            +
                long initial_length = FIX2LONG(buffer_initial_length);
         | 
| 1594 | 
            +
                if (initial_length > 0) {
         | 
| 1595 | 
            +
                    state->buffer_initial_length = initial_length;
         | 
| 1596 | 
            +
                }
         | 
| 1597 | 
            +
            }
         | 
| 1598 | 
            +
             | 
| 1477 1599 | 
             
            /*
         | 
| 1478 1600 | 
             
             * call-seq: buffer_initial_length=(length)
         | 
| 1479 1601 | 
             
             *
         | 
| @@ -1482,16 +1604,76 @@ static VALUE cState_buffer_initial_length(VALUE self) | |
| 1482 1604 | 
             
             */
         | 
| 1483 1605 | 
             
            static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
         | 
| 1484 1606 | 
             
            {
         | 
| 1485 | 
            -
                long initial_length;
         | 
| 1486 1607 | 
             
                GET_STATE(self);
         | 
| 1487 | 
            -
                 | 
| 1488 | 
            -
                initial_length = FIX2LONG(buffer_initial_length);
         | 
| 1489 | 
            -
                if (initial_length > 0) {
         | 
| 1490 | 
            -
                    state->buffer_initial_length = initial_length;
         | 
| 1491 | 
            -
                }
         | 
| 1608 | 
            +
                buffer_initial_length_set(state, buffer_initial_length);
         | 
| 1492 1609 | 
             
                return Qnil;
         | 
| 1493 1610 | 
             
            }
         | 
| 1494 1611 |  | 
| 1612 | 
            +
            static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
         | 
| 1613 | 
            +
            {
         | 
| 1614 | 
            +
                JSON_Generator_State *state = (JSON_Generator_State *)_arg;
         | 
| 1615 | 
            +
             | 
| 1616 | 
            +
                     if (key == sym_indent)                { state->indent = string_config(val); }
         | 
| 1617 | 
            +
                else if (key == sym_space)                 { state->space = string_config(val); }
         | 
| 1618 | 
            +
                else if (key == sym_space_before)          { state->space_before = string_config(val); }
         | 
| 1619 | 
            +
                else if (key == sym_object_nl)             { state->object_nl = string_config(val); }
         | 
| 1620 | 
            +
                else if (key == sym_array_nl)              { state->array_nl = string_config(val); }
         | 
| 1621 | 
            +
                else if (key == sym_max_nesting)           { state->max_nesting = long_config(val); }
         | 
| 1622 | 
            +
                else if (key == sym_allow_nan)             { state->allow_nan = RTEST(val); }
         | 
| 1623 | 
            +
                else if (key == sym_ascii_only)            { state->ascii_only = RTEST(val); }
         | 
| 1624 | 
            +
                else if (key == sym_depth)                 { state->depth = long_config(val); }
         | 
| 1625 | 
            +
                else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
         | 
| 1626 | 
            +
                else if (key == sym_script_safe)           { state->script_safe = RTEST(val); }
         | 
| 1627 | 
            +
                else if (key == sym_escape_slash)          { state->script_safe = RTEST(val); }
         | 
| 1628 | 
            +
                else if (key == sym_strict)                { state->strict = RTEST(val); }
         | 
| 1629 | 
            +
                else if (key == sym_as_json)               { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
         | 
| 1630 | 
            +
                return ST_CONTINUE;
         | 
| 1631 | 
            +
            }
         | 
| 1632 | 
            +
             | 
| 1633 | 
            +
            static void configure_state(JSON_Generator_State *state, VALUE config)
         | 
| 1634 | 
            +
            {
         | 
| 1635 | 
            +
                if (!RTEST(config)) return;
         | 
| 1636 | 
            +
             | 
| 1637 | 
            +
                Check_Type(config, T_HASH);
         | 
| 1638 | 
            +
             | 
| 1639 | 
            +
                if (!RHASH_SIZE(config)) return;
         | 
| 1640 | 
            +
             | 
| 1641 | 
            +
                // We assume in most cases few keys are set so it's faster to go over
         | 
| 1642 | 
            +
                // the provided keys than to check all possible keys.
         | 
| 1643 | 
            +
                rb_hash_foreach(config, configure_state_i, (VALUE)state);
         | 
| 1644 | 
            +
            }
         | 
| 1645 | 
            +
             | 
| 1646 | 
            +
            static VALUE cState_configure(VALUE self, VALUE opts)
         | 
| 1647 | 
            +
            {
         | 
| 1648 | 
            +
                GET_STATE(self);
         | 
| 1649 | 
            +
                configure_state(state, opts);
         | 
| 1650 | 
            +
                return self;
         | 
| 1651 | 
            +
            }
         | 
| 1652 | 
            +
             | 
| 1653 | 
            +
            static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
         | 
| 1654 | 
            +
            {
         | 
| 1655 | 
            +
                JSON_Generator_State state = {0};
         | 
| 1656 | 
            +
                state_init(&state);
         | 
| 1657 | 
            +
                configure_state(&state, opts);
         | 
| 1658 | 
            +
             | 
| 1659 | 
            +
                char stack_buffer[FBUFFER_STACK_SIZE];
         | 
| 1660 | 
            +
                FBuffer buffer = {
         | 
| 1661 | 
            +
                    .io = RTEST(io) ? io : Qfalse,
         | 
| 1662 | 
            +
                };
         | 
| 1663 | 
            +
                fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
         | 
| 1664 | 
            +
             | 
| 1665 | 
            +
                struct generate_json_data data = {
         | 
| 1666 | 
            +
                    .buffer = &buffer,
         | 
| 1667 | 
            +
                    .vstate = Qfalse,
         | 
| 1668 | 
            +
                    .state = &state,
         | 
| 1669 | 
            +
                    .obj = obj,
         | 
| 1670 | 
            +
                    .func = generate_json,
         | 
| 1671 | 
            +
                };
         | 
| 1672 | 
            +
                rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
         | 
| 1673 | 
            +
             | 
| 1674 | 
            +
                return fbuffer_finalize(&buffer);
         | 
| 1675 | 
            +
            }
         | 
| 1676 | 
            +
             | 
| 1495 1677 | 
             
            /*
         | 
| 1496 1678 | 
             
             *
         | 
| 1497 1679 | 
             
             */
         | 
| @@ -1505,18 +1687,26 @@ void Init_generator(void) | |
| 1505 1687 | 
             
                rb_require("json/common");
         | 
| 1506 1688 |  | 
| 1507 1689 | 
             
                mJSON = rb_define_module("JSON");
         | 
| 1508 | 
            -
                mExt = rb_define_module_under(mJSON, "Ext");
         | 
| 1509 | 
            -
                mGenerator = rb_define_module_under(mExt, "Generator");
         | 
| 1510 1690 |  | 
| 1691 | 
            +
                rb_global_variable(&cFragment);
         | 
| 1692 | 
            +
                cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
         | 
| 1693 | 
            +
             | 
| 1694 | 
            +
                VALUE mExt = rb_define_module_under(mJSON, "Ext");
         | 
| 1695 | 
            +
                VALUE mGenerator = rb_define_module_under(mExt, "Generator");
         | 
| 1696 | 
            +
             | 
| 1697 | 
            +
                rb_global_variable(&eGeneratorError);
         | 
| 1511 1698 | 
             
                eGeneratorError = rb_path2class("JSON::GeneratorError");
         | 
| 1699 | 
            +
             | 
| 1700 | 
            +
                rb_global_variable(&eNestingError);
         | 
| 1512 1701 | 
             
                eNestingError = rb_path2class("JSON::NestingError");
         | 
| 1513 | 
            -
                rb_gc_register_mark_object(eGeneratorError);
         | 
| 1514 | 
            -
                rb_gc_register_mark_object(eNestingError);
         | 
| 1515 1702 |  | 
| 1516 1703 | 
             
                cState = rb_define_class_under(mGenerator, "State", rb_cObject);
         | 
| 1517 1704 | 
             
                rb_define_alloc_func(cState, cState_s_allocate);
         | 
| 1518 1705 | 
             
                rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
         | 
| 1519 1706 | 
             
                rb_define_method(cState, "initialize", cState_initialize, -1);
         | 
| 1707 | 
            +
                rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
         | 
| 1708 | 
            +
                rb_define_private_method(cState, "_configure", cState_configure, 1);
         | 
| 1709 | 
            +
             | 
| 1520 1710 | 
             
                rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
         | 
| 1521 1711 | 
             
                rb_define_method(cState, "indent", cState_indent, 0);
         | 
| 1522 1712 | 
             
                rb_define_method(cState, "indent=", cState_indent_set, 1);
         | 
| @@ -1528,81 +1718,105 @@ void Init_generator(void) | |
| 1528 1718 | 
             
                rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
         | 
| 1529 1719 | 
             
                rb_define_method(cState, "array_nl", cState_array_nl, 0);
         | 
| 1530 1720 | 
             
                rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
         | 
| 1721 | 
            +
                rb_define_method(cState, "as_json", cState_as_json, 0);
         | 
| 1722 | 
            +
                rb_define_method(cState, "as_json=", cState_as_json_set, 1);
         | 
| 1531 1723 | 
             
                rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
         | 
| 1532 1724 | 
             
                rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
         | 
| 1533 | 
            -
                rb_define_method(cState, " | 
| 1534 | 
            -
                rb_define_method(cState, " | 
| 1535 | 
            -
                rb_define_method(cState, " | 
| 1725 | 
            +
                rb_define_method(cState, "script_safe", cState_script_safe, 0);
         | 
| 1726 | 
            +
                rb_define_method(cState, "script_safe?", cState_script_safe, 0);
         | 
| 1727 | 
            +
                rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
         | 
| 1728 | 
            +
                rb_define_alias(cState, "escape_slash", "script_safe");
         | 
| 1729 | 
            +
                rb_define_alias(cState, "escape_slash?", "script_safe?");
         | 
| 1730 | 
            +
                rb_define_alias(cState, "escape_slash=", "script_safe=");
         | 
| 1731 | 
            +
                rb_define_method(cState, "strict", cState_strict, 0);
         | 
| 1732 | 
            +
                rb_define_method(cState, "strict?", cState_strict, 0);
         | 
| 1733 | 
            +
                rb_define_method(cState, "strict=", cState_strict_set, 1);
         | 
| 1536 1734 | 
             
                rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
         | 
| 1537 1735 | 
             
                rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
         | 
| 1736 | 
            +
                rb_define_method(cState, "allow_nan=", cState_allow_nan_set, 1);
         | 
| 1538 1737 | 
             
                rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
         | 
| 1738 | 
            +
                rb_define_method(cState, "ascii_only=", cState_ascii_only_set, 1);
         | 
| 1539 1739 | 
             
                rb_define_method(cState, "depth", cState_depth, 0);
         | 
| 1540 1740 | 
             
                rb_define_method(cState, "depth=", cState_depth_set, 1);
         | 
| 1541 1741 | 
             
                rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
         | 
| 1542 1742 | 
             
                rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
         | 
| 1543 | 
            -
                rb_define_method(cState, " | 
| 1544 | 
            -
                rb_define_alias(cState, " | 
| 1545 | 
            -
             | 
| 1546 | 
            -
                 | 
| 1547 | 
            -
             | 
| 1548 | 
            -
                 | 
| 1549 | 
            -
             | 
| 1550 | 
            -
             | 
| 1551 | 
            -
                mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
         | 
| 1552 | 
            -
                mObject = rb_define_module_under(mGeneratorMethods, "Object");
         | 
| 1743 | 
            +
                rb_define_method(cState, "generate", cState_generate, -1);
         | 
| 1744 | 
            +
                rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
         | 
| 1745 | 
            +
             | 
| 1746 | 
            +
                rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
         | 
| 1747 | 
            +
             | 
| 1748 | 
            +
                VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
         | 
| 1749 | 
            +
             | 
| 1750 | 
            +
                VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
         | 
| 1553 1751 | 
             
                rb_define_method(mObject, "to_json", mObject_to_json, -1);
         | 
| 1554 | 
            -
             | 
| 1752 | 
            +
             | 
| 1753 | 
            +
                VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
         | 
| 1555 1754 | 
             
                rb_define_method(mHash, "to_json", mHash_to_json, -1);
         | 
| 1556 | 
            -
             | 
| 1755 | 
            +
             | 
| 1756 | 
            +
                VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
         | 
| 1557 1757 | 
             
                rb_define_method(mArray, "to_json", mArray_to_json, -1);
         | 
| 1758 | 
            +
             | 
| 1558 1759 | 
             
            #ifdef RUBY_INTEGER_UNIFICATION
         | 
| 1559 | 
            -
                mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
         | 
| 1760 | 
            +
                VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
         | 
| 1560 1761 | 
             
                rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
         | 
| 1561 1762 | 
             
            #else
         | 
| 1562 | 
            -
                mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
         | 
| 1763 | 
            +
                VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
         | 
| 1563 1764 | 
             
                rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
         | 
| 1564 | 
            -
             | 
| 1765 | 
            +
             | 
| 1766 | 
            +
                VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
         | 
| 1565 1767 | 
             
                rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
         | 
| 1566 1768 | 
             
            #endif
         | 
| 1567 | 
            -
                mFloat = rb_define_module_under(mGeneratorMethods, "Float");
         | 
| 1769 | 
            +
                VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
         | 
| 1568 1770 | 
             
                rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
         | 
| 1569 | 
            -
             | 
| 1771 | 
            +
             | 
| 1772 | 
            +
                VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
         | 
| 1570 1773 | 
             
                rb_define_singleton_method(mString, "included", mString_included_s, 1);
         | 
| 1571 1774 | 
             
                rb_define_method(mString, "to_json", mString_to_json, -1);
         | 
| 1572 1775 | 
             
                rb_define_method(mString, "to_json_raw", mString_to_json_raw, -1);
         | 
| 1573 1776 | 
             
                rb_define_method(mString, "to_json_raw_object", mString_to_json_raw_object, 0);
         | 
| 1777 | 
            +
             | 
| 1574 1778 | 
             
                mString_Extend = rb_define_module_under(mString, "Extend");
         | 
| 1575 1779 | 
             
                rb_define_method(mString_Extend, "json_create", mString_Extend_json_create, 1);
         | 
| 1576 | 
            -
             | 
| 1780 | 
            +
             | 
| 1781 | 
            +
                VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
         | 
| 1577 1782 | 
             
                rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
         | 
| 1578 | 
            -
             | 
| 1783 | 
            +
             | 
| 1784 | 
            +
                VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
         | 
| 1579 1785 | 
             
                rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
         | 
| 1580 | 
            -
             | 
| 1786 | 
            +
             | 
| 1787 | 
            +
                VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
         | 
| 1581 1788 | 
             
                rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
         | 
| 1582 1789 |  | 
| 1790 | 
            +
                rb_global_variable(&Encoding_UTF_8);
         | 
| 1791 | 
            +
                Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
         | 
| 1792 | 
            +
             | 
| 1583 1793 | 
             
                i_to_s = rb_intern("to_s");
         | 
| 1584 1794 | 
             
                i_to_json = rb_intern("to_json");
         | 
| 1585 1795 | 
             
                i_new = rb_intern("new");
         | 
| 1586 | 
            -
                i_indent = rb_intern("indent");
         | 
| 1587 | 
            -
                i_space = rb_intern("space");
         | 
| 1588 | 
            -
                i_space_before = rb_intern("space_before");
         | 
| 1589 | 
            -
                i_object_nl = rb_intern("object_nl");
         | 
| 1590 | 
            -
                i_array_nl = rb_intern("array_nl");
         | 
| 1591 | 
            -
                i_max_nesting = rb_intern("max_nesting");
         | 
| 1592 | 
            -
                i_escape_slash = rb_intern("escape_slash");
         | 
| 1593 | 
            -
                i_allow_nan = rb_intern("allow_nan");
         | 
| 1594 | 
            -
                i_ascii_only = rb_intern("ascii_only");
         | 
| 1595 | 
            -
                i_depth = rb_intern("depth");
         | 
| 1596 | 
            -
                i_buffer_initial_length = rb_intern("buffer_initial_length");
         | 
| 1597 1796 | 
             
                i_pack = rb_intern("pack");
         | 
| 1598 1797 | 
             
                i_unpack = rb_intern("unpack");
         | 
| 1599 1798 | 
             
                i_create_id = rb_intern("create_id");
         | 
| 1600 1799 | 
             
                i_extend = rb_intern("extend");
         | 
| 1601 | 
            -
                 | 
| 1602 | 
            -
             | 
| 1603 | 
            -
                 | 
| 1604 | 
            -
                 | 
| 1605 | 
            -
                 | 
| 1606 | 
            -
                 | 
| 1607 | 
            -
                 | 
| 1800 | 
            +
                i_encode = rb_intern("encode");
         | 
| 1801 | 
            +
             | 
| 1802 | 
            +
                sym_indent = ID2SYM(rb_intern("indent"));
         | 
| 1803 | 
            +
                sym_space = ID2SYM(rb_intern("space"));
         | 
| 1804 | 
            +
                sym_space_before = ID2SYM(rb_intern("space_before"));
         | 
| 1805 | 
            +
                sym_object_nl = ID2SYM(rb_intern("object_nl"));
         | 
| 1806 | 
            +
                sym_array_nl = ID2SYM(rb_intern("array_nl"));
         | 
| 1807 | 
            +
                sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
         | 
| 1808 | 
            +
                sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
         | 
| 1809 | 
            +
                sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
         | 
| 1810 | 
            +
                sym_depth = ID2SYM(rb_intern("depth"));
         | 
| 1811 | 
            +
                sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
         | 
| 1812 | 
            +
                sym_script_safe = ID2SYM(rb_intern("script_safe"));
         | 
| 1813 | 
            +
                sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
         | 
| 1814 | 
            +
                sym_strict = ID2SYM(rb_intern("strict"));
         | 
| 1815 | 
            +
                sym_as_json = ID2SYM(rb_intern("as_json"));
         | 
| 1816 | 
            +
             | 
| 1817 | 
            +
                usascii_encindex = rb_usascii_encindex();
         | 
| 1818 | 
            +
                utf8_encindex = rb_utf8_encindex();
         | 
| 1819 | 
            +
                binary_encindex = rb_ascii8bit_encindex();
         | 
| 1820 | 
            +
             | 
| 1821 | 
            +
                rb_require("json/ext/generator/state");
         | 
| 1608 1822 | 
             
            }
         |