ext/json/generator/generator.c

Go to the documentation of this file.
00001 #include "../fbuffer/fbuffer.h"
00002 #include "generator.h"
00003 
00004 #ifdef HAVE_RUBY_ENCODING_H
00005 static VALUE CEncoding_UTF_8;
00006 static ID i_encoding, i_encode;
00007 #endif
00008 
00009 static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
00010              mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,
00011              mTrueClass, mFalseClass, mNilClass, eGeneratorError,
00012              eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
00013              i_SAFE_STATE_PROTOTYPE;
00014 
00015 static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
00016           i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
00017           i_quirks_mode, i_pack, i_unpack, i_create_id, i_extend, i_key_p,
00018           i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
00019           i_buffer_initial_length, i_dup;
00020 
00021 /*
00022  * Copyright 2001-2004 Unicode, Inc.
00023  *
00024  * Disclaimer
00025  *
00026  * This source code is provided as is by Unicode, Inc. No claims are
00027  * made as to fitness for any particular purpose. No warranties of any
00028  * kind are expressed or implied. The recipient agrees to determine
00029  * applicability of information provided. If this file has been
00030  * purchased on magnetic or optical media from Unicode, Inc., the
00031  * sole remedy for any claim will be exchange of defective media
00032  * within 90 days of receipt.
00033  *
00034  * Limitations on Rights to Redistribute This Code
00035  *
00036  * Unicode, Inc. hereby grants the right to freely use the information
00037  * supplied in this file in the creation of products supporting the
00038  * Unicode Standard, and to make copies of this file in any form
00039  * for internal or external distribution as long as this notice
00040  * remains attached.
00041  */
00042 
00043 /*
00044  * Index into the table below with the first byte of a UTF-8 sequence to
00045  * get the number of trailing bytes that are supposed to follow it.
00046  * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
00047  * left as-is for anyone who may want to do such conversion, which was
00048  * allowed in earlier algorithms.
00049  */
00050 static const char trailingBytesForUTF8[256] = {
00051     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00052     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00053     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00054     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00055     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00056     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00057     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00058     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
00059 };
00060 
00061 /*
00062  * Magic values subtracted from a buffer value during UTF8 conversion.
00063  * This table contains as many values as there might be trailing bytes
00064  * in a UTF-8 sequence.
00065  */
00066 static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
00067     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
00068 
00069 /*
00070  * Utility routine to tell whether a sequence of bytes is legal UTF-8.
00071  * This must be called with the length pre-determined by the first byte.
00072  * If not calling this from ConvertUTF8to*, then the length can be set by:
00073  *  length = trailingBytesForUTF8[*source]+1;
00074  * and the sequence is illegal right away if there aren't that many bytes
00075  * available.
00076  * If presented with a length > 4, this returns 0.  The Unicode
00077  * definition of UTF-8 goes up to 4-byte sequences.
00078  */
00079 static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length)
00080 {
00081     UTF8 a;
00082     const UTF8 *srcptr = source+length;
00083     switch (length) {
00084         default: return 0;
00085                  /* Everything else falls through when "1"... */
00086         case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
00087         case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
00088         case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
00089 
00090                     switch (*source) {
00091                         /* no fall-through in this inner switch */
00092                         case 0xE0: if (a < 0xA0) return 0; break;
00093                         case 0xED: if (a > 0x9F) return 0; break;
00094                         case 0xF0: if (a < 0x90) return 0; break;
00095                         case 0xF4: if (a > 0x8F) return 0; break;
00096                         default:   if (a < 0x80) return 0;
00097                     }
00098 
00099         case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
00100     }
00101     if (*source > 0xF4) return 0;
00102     return 1;
00103 }
00104 
00105 /* Escapes the UTF16 character and stores the result in the buffer buf. */
00106 static void unicode_escape(char *buf, UTF16 character)
00107 {
00108     const char *digits = "0123456789abcdef";
00109 
00110     buf[2] = digits[character >> 12];
00111     buf[3] = digits[(character >> 8) & 0xf];
00112     buf[4] = digits[(character >> 4) & 0xf];
00113     buf[5] = digits[character & 0xf];
00114 }
00115 
00116 /* Escapes the UTF16 character and stores the result in the buffer buf, then
00117  * the buffer buf is appended to the FBuffer buffer. */
00118 static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
00119         character)
00120 {
00121     unicode_escape(buf, character);
00122     fbuffer_append(buffer, buf, 6);
00123 }
00124 
00125 /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
00126  * and control characters are JSON escaped. */
00127 static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
00128 {
00129     const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
00130     const UTF8 *sourceEnd = source + RSTRING_LEN(string);
00131     char buf[6] = { '\\', 'u' };
00132 
00133     while (source < sourceEnd) {
00134         UTF32 ch = 0;
00135         unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
00136         if (source + extraBytesToRead >= sourceEnd) {
00137             rb_raise(rb_path2class("JSON::GeneratorError"),
00138                     "partial character in source, but hit end");
00139         }
00140         if (!isLegalUTF8(source, extraBytesToRead+1)) {
00141             rb_raise(rb_path2class("JSON::GeneratorError"),
00142                     "source sequence is illegal/malformed utf-8");
00143         }
00144         /*
00145          * The cases all fall through. See "Note A" below.
00146          */
00147         switch (extraBytesToRead) {
00148             case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
00149             case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
00150             case 3: ch += *source++; ch <<= 6;
00151             case 2: ch += *source++; ch <<= 6;
00152             case 1: ch += *source++; ch <<= 6;
00153             case 0: ch += *source++;
00154         }
00155         ch -= offsetsFromUTF8[extraBytesToRead];
00156 
00157         if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
00158             /* UTF-16 surrogate values are illegal in UTF-32 */
00159             if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
00160 #if UNI_STRICT_CONVERSION
00161                 source -= (extraBytesToRead+1); /* return to the illegal value itself */
00162                 rb_raise(rb_path2class("JSON::GeneratorError"),
00163                         "source sequence is illegal/malformed utf-8");
00164 #else
00165                 unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
00166 #endif
00167             } else {
00168                 /* normal case */
00169                 if (ch >= 0x20 && ch <= 0x7f) {
00170                     switch (ch) {
00171                         case '\\':
00172                             fbuffer_append(buffer, "\\\\", 2);
00173                             break;
00174                         case '"':
00175                             fbuffer_append(buffer, "\\\"", 2);
00176                             break;
00177                         default:
00178                             fbuffer_append_char(buffer, (char)ch);
00179                             break;
00180                     }
00181                 } else {
00182                     switch (ch) {
00183                         case '\n':
00184                             fbuffer_append(buffer, "\\n", 2);
00185                             break;
00186                         case '\r':
00187                             fbuffer_append(buffer, "\\r", 2);
00188                             break;
00189                         case '\t':
00190                             fbuffer_append(buffer, "\\t", 2);
00191                             break;
00192                         case '\f':
00193                             fbuffer_append(buffer, "\\f", 2);
00194                             break;
00195                         case '\b':
00196                             fbuffer_append(buffer, "\\b", 2);
00197                             break;
00198                         default:
00199                             unicode_escape_to_buffer(buffer, buf, (UTF16) ch);
00200                             break;
00201                     }
00202                 }
00203             }
00204         } else if (ch > UNI_MAX_UTF16) {
00205 #if UNI_STRICT_CONVERSION
00206             source -= (extraBytesToRead+1); /* return to the start */
00207             rb_raise(rb_path2class("JSON::GeneratorError"),
00208                     "source sequence is illegal/malformed utf8");
00209 #else
00210             unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
00211 #endif
00212         } else {
00213             /* target is a character in range 0xFFFF - 0x10FFFF. */
00214             ch -= halfBase;
00215             unicode_escape_to_buffer(buffer, buf, (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START));
00216             unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
00217         }
00218     }
00219 }
00220 
00221 /* Converts string to a JSON string in FBuffer buffer, where only the
00222  * characters required by the JSON standard are JSON escaped. The remaining
00223  * characters (should be UTF8) are just passed through and appended to the
00224  * result. */
00225 static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
00226 {
00227     const char *ptr = RSTRING_PTR(string), *p;
00228     unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
00229     const char *escape = NULL;
00230     int escape_len;
00231     unsigned char c;
00232     char buf[6] = { '\\', 'u' };
00233 
00234     for (start = 0, end = 0; end < len;) {
00235         p = ptr + end;
00236         c = (unsigned char) *p;
00237         if (c < 0x20) {
00238             switch (c) {
00239                 case '\n':
00240                     escape = "\\n";
00241                     escape_len = 2;
00242                     break;
00243                 case '\r':
00244                     escape = "\\r";
00245                     escape_len = 2;
00246                     break;
00247                 case '\t':
00248                     escape = "\\t";
00249                     escape_len = 2;
00250                     break;
00251                 case '\f':
00252                     escape = "\\f";
00253                     escape_len = 2;
00254                     break;
00255                 case '\b':
00256                     escape = "\\b";
00257                     escape_len = 2;
00258                     break;
00259                 default:
00260                     unicode_escape(buf, (UTF16) *p);
00261                     escape = buf;
00262                     escape_len = 6;
00263                     break;
00264             }
00265         } else {
00266             switch (c) {
00267                 case '\\':
00268                     escape = "\\\\";
00269                     escape_len = 2;
00270                     break;
00271                 case '"':
00272                     escape =  "\\\"";
00273                     escape_len = 2;
00274                     break;
00275                 default:
00276                     {
00277                         unsigned short clen = trailingBytesForUTF8[c] + 1;
00278                         if (end + clen > len) {
00279                             rb_raise(rb_path2class("JSON::GeneratorError"),
00280                                     "partial character in source, but hit end");
00281                         }
00282                         if (!isLegalUTF8((UTF8 *) p, clen)) {
00283                             rb_raise(rb_path2class("JSON::GeneratorError"),
00284                                     "source sequence is illegal/malformed utf-8");
00285                         }
00286                         end += clen;
00287                     }
00288                     continue;
00289                     break;
00290             }
00291         }
00292         fbuffer_append(buffer, ptr + start, end - start);
00293         fbuffer_append(buffer, escape, escape_len);
00294         start = ++end;
00295         escape = NULL;
00296     }
00297     fbuffer_append(buffer, ptr + start, end - start);
00298 }
00299 
00300 static char *fstrndup(const char *ptr, unsigned long len) {
00301   char *result;
00302   if (len <= 0) return NULL;
00303   result = ALLOC_N(char, len);
00304   memccpy(result, ptr, 0, len);
00305   return result;
00306 }
00307 
00308 /*
00309  * Document-module: JSON::Ext::Generator
00310  *
00311  * This is the JSON generator implemented as a C extension. It can be
00312  * configured to be used by setting
00313  *
00314  *  JSON.generator = JSON::Ext::Generator
00315  *
00316  * with the method generator= in JSON.
00317  *
00318  */
00319 
00320 /*
00321  * call-seq: to_json(state = nil)
00322  *
00323  * Returns a JSON string containing a JSON object, that is generated from
00324  * this Hash instance.
00325  * _state_ is a JSON::State object, that can also be used to configure the
00326  * produced JSON string output further.
00327  */
00328 static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
00329 {
00330     GENERATE_JSON(object);
00331 }
00332 
00333 /*
00334  * call-seq: to_json(state = nil)
00335  *
00336  * Returns a JSON string containing a JSON array, that is generated from
00337  * this Array instance.
00338  * _state_ is a JSON::State object, that can also be used to configure the
00339  * produced JSON string output further.
00340  */
00341 static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
00342     GENERATE_JSON(array);
00343 }
00344 
00345 /*
00346  * call-seq: to_json(*)
00347  *
00348  * Returns a JSON string representation for this Integer number.
00349  */
00350 static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
00351 {
00352     GENERATE_JSON(fixnum);
00353 }
00354 
00355 /*
00356  * call-seq: to_json(*)
00357  *
00358  * Returns a JSON string representation for this Integer number.
00359  */
00360 static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
00361 {
00362     GENERATE_JSON(bignum);
00363 }
00364 
00365 /*
00366  * call-seq: to_json(*)
00367  *
00368  * Returns a JSON string representation for this Float number.
00369  */
00370 static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
00371 {
00372     GENERATE_JSON(float);
00373 }
00374 
00375 /*
00376  * call-seq: String.included(modul)
00377  *
00378  * Extends _modul_ with the String::Extend module.
00379  */
00380 static VALUE mString_included_s(VALUE self, VALUE modul) {
00381     VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
00382     return result;
00383 }
00384 
00385 /*
00386  * call-seq: to_json(*)
00387  *
00388  * This string should be encoded with UTF-8 A call to this method
00389  * returns a JSON string encoded with UTF16 big endian characters as
00390  * \u????.
00391  */
00392 static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
00393 {
00394     GENERATE_JSON(string);
00395 }
00396 
00397 /*
00398  * call-seq: to_json_raw_object()
00399  *
00400  * This method creates a raw object hash, that can be nested into
00401  * other data structures and will be generated as a raw string. This
00402  * method should be used, if you want to convert raw strings to JSON
00403  * instead of UTF-8 strings, e. g. binary data.
00404  */
00405 static VALUE mString_to_json_raw_object(VALUE self)
00406 {
00407     VALUE ary;
00408     VALUE result = rb_hash_new();
00409     rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
00410     ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
00411     rb_hash_aset(result, rb_str_new2("raw"), ary);
00412     return result;
00413 }
00414 
00415 /*
00416  * call-seq: to_json_raw(*args)
00417  *
00418  * This method creates a JSON text from the result of a call to
00419  * to_json_raw_object of this String.
00420  */
00421 static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
00422 {
00423     VALUE obj = mString_to_json_raw_object(self);
00424     Check_Type(obj, T_HASH);
00425     return mHash_to_json(argc, argv, obj);
00426 }
00427 
00428 /*
00429  * call-seq: json_create(o)
00430  *
00431  * Raw Strings are JSON Objects (the raw bytes are stored in an array for the
00432  * key "raw"). The Ruby String can be created by this module method.
00433  */
00434 static VALUE mString_Extend_json_create(VALUE self, VALUE o)
00435 {
00436     VALUE ary;
00437     Check_Type(o, T_HASH);
00438     ary = rb_hash_aref(o, rb_str_new2("raw"));
00439     return rb_funcall(ary, i_pack, 1, rb_str_new2("C*"));
00440 }
00441 
00442 /*
00443  * call-seq: to_json(*)
00444  *
00445  * Returns a JSON string for true: 'true'.
00446  */
00447 static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
00448 {
00449     GENERATE_JSON(true);
00450 }
00451 
00452 /*
00453  * call-seq: to_json(*)
00454  *
00455  * Returns a JSON string for false: 'false'.
00456  */
00457 static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
00458 {
00459     GENERATE_JSON(false);
00460 }
00461 
00462 /*
00463  * call-seq: to_json(*)
00464  *
00465  * Returns a JSON string for nil: 'null'.
00466  */
00467 static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
00468 {
00469     GENERATE_JSON(null);
00470 }
00471 
00472 /*
00473  * call-seq: to_json(*)
00474  *
00475  * Converts this object to a string (calling #to_s), converts
00476  * it to a JSON string, and returns the result. This is a fallback, if no
00477  * special method #to_json was defined for some object.
00478  */
00479 static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
00480 {
00481     VALUE state;
00482     VALUE string = rb_funcall(self, i_to_s, 0);
00483     rb_scan_args(argc, argv, "01", &state);
00484     Check_Type(string, T_STRING);
00485     state = cState_from_state_s(cState, state);
00486     return cState_partial_generate(state, string);
00487 }
00488 
00489 static void State_free(JSON_Generator_State *state)
00490 {
00491     if (state->indent) ruby_xfree(state->indent);
00492     if (state->space) ruby_xfree(state->space);
00493     if (state->space_before) ruby_xfree(state->space_before);
00494     if (state->object_nl) ruby_xfree(state->object_nl);
00495     if (state->array_nl) ruby_xfree(state->array_nl);
00496     if (state->array_delim) fbuffer_free(state->array_delim);
00497     if (state->object_delim) fbuffer_free(state->object_delim);
00498     if (state->object_delim2) fbuffer_free(state->object_delim2);
00499     ruby_xfree(state);
00500 }
00501 
00502 static JSON_Generator_State *State_allocate()
00503 {
00504     JSON_Generator_State *state = ALLOC(JSON_Generator_State);
00505     MEMZERO(state, JSON_Generator_State, 1);
00506     return state;
00507 }
00508 
00509 static VALUE cState_s_allocate(VALUE klass)
00510 {
00511     JSON_Generator_State *state = State_allocate();
00512     return Data_Wrap_Struct(klass, NULL, State_free, state);
00513 }
00514 
00515 /*
00516  * call-seq: configure(opts)
00517  *
00518  * Configure this State instance with the Hash _opts_, and return
00519  * itself.
00520  */
00521 static VALUE cState_configure(VALUE self, VALUE opts)
00522 {
00523     VALUE tmp;
00524     GET_STATE(self);
00525     tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash");
00526     if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
00527     opts = tmp;
00528     tmp = rb_hash_aref(opts, ID2SYM(i_indent));
00529     if (RTEST(tmp)) {
00530         unsigned long len;
00531         Check_Type(tmp, T_STRING);
00532         len = RSTRING_LEN(tmp);
00533         state->indent = fstrndup(RSTRING_PTR(tmp), len + 1);
00534         state->indent_len = len;
00535     }
00536     tmp = rb_hash_aref(opts, ID2SYM(i_space));
00537     if (RTEST(tmp)) {
00538         unsigned long len;
00539         Check_Type(tmp, T_STRING);
00540         len = RSTRING_LEN(tmp);
00541         state->space = fstrndup(RSTRING_PTR(tmp), len + 1);
00542         state->space_len = len;
00543     }
00544     tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
00545     if (RTEST(tmp)) {
00546         unsigned long len;
00547         Check_Type(tmp, T_STRING);
00548         len = RSTRING_LEN(tmp);
00549         state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1);
00550         state->space_before_len = len;
00551     }
00552     tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
00553     if (RTEST(tmp)) {
00554         unsigned long len;
00555         Check_Type(tmp, T_STRING);
00556         len = RSTRING_LEN(tmp);
00557         state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
00558         state->array_nl_len = len;
00559     }
00560     tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
00561     if (RTEST(tmp)) {
00562         unsigned long len;
00563         Check_Type(tmp, T_STRING);
00564         len = RSTRING_LEN(tmp);
00565         state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
00566         state->object_nl_len = len;
00567     }
00568     tmp = ID2SYM(i_max_nesting);
00569     state->max_nesting = 100;
00570     if (option_given_p(opts, tmp)) {
00571         VALUE max_nesting = rb_hash_aref(opts, tmp);
00572         if (RTEST(max_nesting)) {
00573             Check_Type(max_nesting, T_FIXNUM);
00574             state->max_nesting = FIX2LONG(max_nesting);
00575         } else {
00576             state->max_nesting = 0;
00577         }
00578     }
00579     tmp = ID2SYM(i_depth);
00580     state->depth = 0;
00581     if (option_given_p(opts, tmp)) {
00582         VALUE depth = rb_hash_aref(opts, tmp);
00583         if (RTEST(depth)) {
00584             Check_Type(depth, T_FIXNUM);
00585             state->depth = FIX2LONG(depth);
00586         } else {
00587             state->depth = 0;
00588         }
00589     }
00590     tmp = ID2SYM(i_buffer_initial_length);
00591     if (option_given_p(opts, tmp)) {
00592         VALUE buffer_initial_length = rb_hash_aref(opts, tmp);
00593         if (RTEST(buffer_initial_length)) {
00594             long initial_length;
00595             Check_Type(buffer_initial_length, T_FIXNUM);
00596             initial_length = FIX2LONG(buffer_initial_length);
00597             if (initial_length > 0) state->buffer_initial_length = initial_length;
00598         }
00599     }
00600     tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan));
00601     state->allow_nan = RTEST(tmp);
00602     tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
00603     state->ascii_only = RTEST(tmp);
00604     tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
00605     state->quirks_mode = RTEST(tmp);
00606     return self;
00607 }
00608 
00609 static void set_state_ivars(VALUE hash, VALUE state)
00610 {
00611     VALUE ivars = rb_obj_instance_variables(state);
00612     int i = 0;
00613     for (i = 0; i < RARRAY_LEN(ivars); i++) {
00614         VALUE key = rb_funcall(rb_ary_entry(ivars, i), i_to_s, 0);
00615         long key_len = RSTRING_LEN(key);
00616         VALUE value = rb_iv_get(state, StringValueCStr(key));
00617         rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value);
00618     }
00619 }
00620 
00621 /*
00622  * call-seq: to_h
00623  *
00624  * Returns the configuration instance variables as a hash, that can be
00625  * passed to the configure method.
00626  */
00627 static VALUE cState_to_h(VALUE self)
00628 {
00629     VALUE result = rb_hash_new();
00630     GET_STATE(self);
00631     set_state_ivars(result, self);
00632     rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len));
00633     rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len));
00634     rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len));
00635     rb_hash_aset(result, ID2SYM(i_object_nl), rb_str_new(state->object_nl, state->object_nl_len));
00636     rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
00637     rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
00638     rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
00639     rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
00640     rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
00641     rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
00642     rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
00643     return result;
00644 }
00645 
00646 /*
00647 * call-seq: [](name)
00648 *
00649 * Return the value returned by method +name+.
00650 */
00651 static VALUE cState_aref(VALUE self, VALUE name)
00652 {
00653     name = rb_funcall(name, i_to_s, 0);
00654     if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
00655         return rb_funcall(self, i_send, 1, name);
00656     } else {
00657         return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
00658     }
00659 }
00660 
00661 /*
00662 * call-seq: []=(name, value)
00663 *
00664 * Set the attribute name to value.
00665 */
00666 static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
00667 {
00668     VALUE name_writer;
00669 
00670     name = rb_funcall(name, i_to_s, 0);
00671     name_writer = rb_str_cat2(rb_str_dup(name), "=");
00672     if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) {
00673         return rb_funcall(self, i_send, 2, name_writer, value);
00674     } else {
00675         rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value);
00676     }
00677     return Qnil;
00678 }
00679 
00680 static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00681 {
00682     char *object_nl = state->object_nl;
00683     long object_nl_len = state->object_nl_len;
00684     char *indent = state->indent;
00685     long indent_len = state->indent_len;
00686     long max_nesting = state->max_nesting;
00687     char *delim = FBUFFER_PTR(state->object_delim);
00688     long delim_len = FBUFFER_LEN(state->object_delim);
00689     char *delim2 = FBUFFER_PTR(state->object_delim2);
00690     long delim2_len = FBUFFER_LEN(state->object_delim2);
00691     long depth = ++state->depth;
00692     int i, j;
00693     VALUE key, key_to_s, keys;
00694     if (max_nesting != 0 && depth > max_nesting) {
00695         fbuffer_free(buffer);
00696         rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
00697     }
00698     fbuffer_append_char(buffer, '{');
00699     keys = rb_funcall(obj, i_keys, 0);
00700     for(i = 0; i < RARRAY_LEN(keys); i++) {
00701         if (i > 0) fbuffer_append(buffer, delim, delim_len);
00702         if (object_nl) {
00703             fbuffer_append(buffer, object_nl, object_nl_len);
00704         }
00705         if (indent) {
00706             for (j = 0; j < depth; j++) {
00707                 fbuffer_append(buffer, indent, indent_len);
00708             }
00709         }
00710         key = rb_ary_entry(keys, i);
00711         key_to_s = rb_funcall(key, i_to_s, 0);
00712         Check_Type(key_to_s, T_STRING);
00713         generate_json(buffer, Vstate, state, key_to_s);
00714         fbuffer_append(buffer, delim2, delim2_len);
00715         generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
00716     }
00717     depth = --state->depth;
00718     if (object_nl) {
00719         fbuffer_append(buffer, object_nl, object_nl_len);
00720         if (indent) {
00721             for (j = 0; j < depth; j++) {
00722                 fbuffer_append(buffer, indent, indent_len);
00723             }
00724         }
00725     }
00726     fbuffer_append_char(buffer, '}');
00727 }
00728 
00729 static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00730 {
00731     char *array_nl = state->array_nl;
00732     long array_nl_len = state->array_nl_len;
00733     char *indent = state->indent;
00734     long indent_len = state->indent_len;
00735     long max_nesting = state->max_nesting;
00736     char *delim = FBUFFER_PTR(state->array_delim);
00737     long delim_len = FBUFFER_LEN(state->array_delim);
00738     long depth = ++state->depth;
00739     int i, j;
00740     if (max_nesting != 0 && depth > max_nesting) {
00741         fbuffer_free(buffer);
00742         rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
00743     }
00744     fbuffer_append_char(buffer, '[');
00745     if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len);
00746     for(i = 0; i < RARRAY_LEN(obj); i++) {
00747         if (i > 0) fbuffer_append(buffer, delim, delim_len);
00748         if (indent) {
00749             for (j = 0; j < depth; j++) {
00750                 fbuffer_append(buffer, indent, indent_len);
00751             }
00752         }
00753         generate_json(buffer, Vstate, state, rb_ary_entry(obj, i));
00754     }
00755     state->depth = --depth;
00756     if (array_nl) {
00757         fbuffer_append(buffer, array_nl, array_nl_len);
00758         if (indent) {
00759             for (j = 0; j < depth; j++) {
00760                 fbuffer_append(buffer, indent, indent_len);
00761             }
00762         }
00763     }
00764     fbuffer_append_char(buffer, ']');
00765 }
00766 
00767 static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00768 {
00769     fbuffer_append_char(buffer, '"');
00770 #ifdef HAVE_RUBY_ENCODING_H
00771     obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
00772 #endif
00773     if (state->ascii_only) {
00774         convert_UTF8_to_JSON_ASCII(buffer, obj);
00775     } else {
00776         convert_UTF8_to_JSON(buffer, obj);
00777     }
00778     fbuffer_append_char(buffer, '"');
00779 }
00780 
00781 static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00782 {
00783     fbuffer_append(buffer, "null", 4);
00784 }
00785 
00786 static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00787 {
00788     fbuffer_append(buffer, "false", 5);
00789 }
00790 
00791 static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00792 {
00793     fbuffer_append(buffer, "true", 4);
00794 }
00795 
00796 static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00797 {
00798     fbuffer_append_long(buffer, FIX2LONG(obj));
00799 }
00800 
00801 static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00802 {
00803     VALUE tmp = rb_funcall(obj, i_to_s, 0);
00804     fbuffer_append_str(buffer, tmp);
00805 }
00806 
00807 static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00808 {
00809     double value = RFLOAT_VALUE(obj);
00810     char allow_nan = state->allow_nan;
00811     VALUE tmp = rb_funcall(obj, i_to_s, 0);
00812     if (!allow_nan) {
00813         if (isinf(value)) {
00814             fbuffer_free(buffer);
00815             rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
00816         } else if (isnan(value)) {
00817             fbuffer_free(buffer);
00818             rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
00819         }
00820     }
00821     fbuffer_append_str(buffer, tmp);
00822 }
00823 
00824 static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
00825 {
00826     VALUE tmp;
00827     VALUE klass = CLASS_OF(obj);
00828     if (klass == rb_cHash) {
00829         generate_json_object(buffer, Vstate, state, obj);
00830     } else if (klass == rb_cArray) {
00831         generate_json_array(buffer, Vstate, state, obj);
00832     } else if (klass == rb_cString) {
00833         generate_json_string(buffer, Vstate, state, obj);
00834     } else if (obj == Qnil) {
00835         generate_json_null(buffer, Vstate, state, obj);
00836     } else if (obj == Qfalse) {
00837         generate_json_false(buffer, Vstate, state, obj);
00838     } else if (obj == Qtrue) {
00839         generate_json_true(buffer, Vstate, state, obj);
00840     } else if (klass == rb_cFixnum) {
00841         generate_json_fixnum(buffer, Vstate, state, obj);
00842     } else if (klass == rb_cBignum) {
00843         generate_json_bignum(buffer, Vstate, state, obj);
00844     } else if (klass == rb_cFloat) {
00845         generate_json_float(buffer, Vstate, state, obj);
00846     } else if (rb_respond_to(obj, i_to_json)) {
00847         tmp = rb_funcall(obj, i_to_json, 1, Vstate);
00848         Check_Type(tmp, T_STRING);
00849         fbuffer_append_str(buffer, tmp);
00850     } else {
00851         tmp = rb_funcall(obj, i_to_s, 0);
00852         Check_Type(tmp, T_STRING);
00853         generate_json(buffer, Vstate, state, tmp);
00854     }
00855 }
00856 
00857 static FBuffer *cState_prepare_buffer(VALUE self)
00858 {
00859     FBuffer *buffer;
00860     GET_STATE(self);
00861     buffer = fbuffer_alloc(state->buffer_initial_length);
00862 
00863     if (state->object_delim) {
00864         fbuffer_clear(state->object_delim);
00865     } else {
00866         state->object_delim = fbuffer_alloc(16);
00867     }
00868     fbuffer_append_char(state->object_delim, ',');
00869     if (state->object_delim2) {
00870         fbuffer_clear(state->object_delim2);
00871     } else {
00872         state->object_delim2 = fbuffer_alloc(16);
00873     }
00874     fbuffer_append_char(state->object_delim2, ':');
00875     if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
00876 
00877     if (state->array_delim) {
00878         fbuffer_clear(state->array_delim);
00879     } else {
00880         state->array_delim = fbuffer_alloc(16);
00881     }
00882     fbuffer_append_char(state->array_delim, ',');
00883     if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len);
00884     return buffer;
00885 }
00886 
00887 static VALUE cState_partial_generate(VALUE self, VALUE obj)
00888 {
00889     FBuffer *buffer = cState_prepare_buffer(self);
00890     GET_STATE(self);
00891     generate_json(buffer, self, state, obj);
00892     return fbuffer_to_s(buffer);
00893 }
00894 
00895 /*
00896  * This function returns true if string is either a JSON array or JSON object.
00897  * It might suffer from false positives, e. g. syntactically incorrect JSON in
00898  * the string or certain UTF-8 characters on the right hand side.
00899  */
00900 static int isArrayOrObject(VALUE string)
00901 {
00902     long string_len = RSTRING_LEN(string);
00903     char *p = RSTRING_PTR(string), *q = p + string_len - 1;
00904     if (string_len < 2) return 0;
00905     for (; p < q && isspace((unsigned char)*p); p++);
00906     for (; q > p && isspace((unsigned char)*q); q--);
00907     return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
00908 }
00909 
00910 /*
00911  * call-seq: generate(obj)
00912  *
00913  * Generates a valid JSON document from object +obj+ and returns the
00914  * result. If no valid JSON document can be created this method raises a
00915  * GeneratorError exception.
00916  */
00917 static VALUE cState_generate(VALUE self, VALUE obj)
00918 {
00919     VALUE result = cState_partial_generate(self, obj);
00920     GET_STATE(self);
00921     if (!state->quirks_mode && !isArrayOrObject(result)) {
00922         rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
00923     }
00924     return result;
00925 }
00926 
00927 /*
00928  * call-seq: new(opts = {})
00929  *
00930  * Instantiates a new State object, configured by _opts_.
00931  *
00932  * _opts_ can have the following keys:
00933  *
00934  * * *indent*: a string used to indent levels (default: ''),
00935  * * *space*: a string that is put after, a : or , delimiter (default: ''),
00936  * * *space_before*: a string that is put before a : pair delimiter (default: ''),
00937  * * *object_nl*: a string that is put at the end of a JSON object (default: ''),
00938  * * *array_nl*: a string that is put at the end of a JSON array (default: ''),
00939  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
00940  *   generated, otherwise an exception is thrown, if these values are
00941  *   encountered. This options defaults to false.
00942  * * *quirks_mode*: Enables quirks_mode for parser, that is for example
00943  *   generating single JSON values instead of documents is possible.
00944  * * *buffer_initial_length*: sets the initial length of the generator's
00945  *   internal buffer.
00946  */
00947 static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
00948 {
00949     VALUE opts;
00950     GET_STATE(self);
00951     state->max_nesting = 100;
00952     state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
00953     rb_scan_args(argc, argv, "01", &opts);
00954     if (!NIL_P(opts)) cState_configure(self, opts);
00955     return self;
00956 }
00957 
00958 /*
00959  * call-seq: initialize_copy(orig)
00960  *
00961  * Initializes this object from orig if it to be duplicated/cloned and returns
00962  * it.
00963 */
00964 static VALUE cState_init_copy(VALUE obj, VALUE orig)
00965 {
00966     JSON_Generator_State *objState, *origState;
00967 
00968     if (obj == orig) return obj;
00969     Data_Get_Struct(obj, JSON_Generator_State, objState);
00970     Data_Get_Struct(orig, JSON_Generator_State, origState);
00971     if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
00972 
00973     MEMCPY(objState, origState, JSON_Generator_State, 1);
00974     objState->indent = fstrndup(origState->indent, origState->indent_len);
00975     objState->space = fstrndup(origState->space, origState->space_len);
00976     objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
00977     objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
00978     objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
00979     if (origState->array_delim) objState->array_delim = fbuffer_dup(origState->array_delim);
00980     if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim);
00981     if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2);
00982     return obj;
00983 }
00984 
00985 /*
00986  * call-seq: from_state(opts)
00987  *
00988  * Creates a State object from _opts_, which ought to be Hash to create a
00989  * new State instance configured by _opts_, something else to create an
00990  * unconfigured instance. If _opts_ is a State object, it is just returned.
00991  */
00992 static VALUE cState_from_state_s(VALUE self, VALUE opts)
00993 {
00994     if (rb_obj_is_kind_of(opts, self)) {
00995         return opts;
00996     } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
00997         return rb_funcall(self, i_new, 1, opts);
00998     } else {
00999         if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
01000             CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
01001         }
01002         return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
01003     }
01004 }
01005 
01006 /*
01007  * call-seq: indent()
01008  *
01009  * This string is used to indent levels in the JSON text.
01010  */
01011 static VALUE cState_indent(VALUE self)
01012 {
01013     GET_STATE(self);
01014     return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
01015 }
01016 
01017 /*
01018  * call-seq: indent=(indent)
01019  *
01020  * This string is used to indent levels in the JSON text.
01021  */
01022 static VALUE cState_indent_set(VALUE self, VALUE indent)
01023 {
01024     unsigned long len;
01025     GET_STATE(self);
01026     Check_Type(indent, T_STRING);
01027     len = RSTRING_LEN(indent);
01028     if (len == 0) {
01029         if (state->indent) {
01030             ruby_xfree(state->indent);
01031             state->indent = NULL;
01032             state->indent_len = 0;
01033         }
01034     } else {
01035         if (state->indent) ruby_xfree(state->indent);
01036         state->indent = strdup(RSTRING_PTR(indent));
01037         state->indent_len = len;
01038     }
01039     return Qnil;
01040 }
01041 
01042 /*
01043  * call-seq: space()
01044  *
01045  * This string is used to insert a space between the tokens in a JSON
01046  * string.
01047  */
01048 static VALUE cState_space(VALUE self)
01049 {
01050     GET_STATE(self);
01051     return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
01052 }
01053 
01054 /*
01055  * call-seq: space=(space)
01056  *
01057  * This string is used to insert a space between the tokens in a JSON
01058  * string.
01059  */
01060 static VALUE cState_space_set(VALUE self, VALUE space)
01061 {
01062     unsigned long len;
01063     GET_STATE(self);
01064     Check_Type(space, T_STRING);
01065     len = RSTRING_LEN(space);
01066     if (len == 0) {
01067         if (state->space) {
01068             ruby_xfree(state->space);
01069             state->space = NULL;
01070             state->space_len = 0;
01071         }
01072     } else {
01073         if (state->space) ruby_xfree(state->space);
01074         state->space = strdup(RSTRING_PTR(space));
01075         state->space_len = len;
01076     }
01077     return Qnil;
01078 }
01079 
01080 /*
01081  * call-seq: space_before()
01082  *
01083  * This string is used to insert a space before the ':' in JSON objects.
01084  */
01085 static VALUE cState_space_before(VALUE self)
01086 {
01087     GET_STATE(self);
01088     return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
01089 }
01090 
01091 /*
01092  * call-seq: space_before=(space_before)
01093  *
01094  * This string is used to insert a space before the ':' in JSON objects.
01095  */
01096 static VALUE cState_space_before_set(VALUE self, VALUE space_before)
01097 {
01098     unsigned long len;
01099     GET_STATE(self);
01100     Check_Type(space_before, T_STRING);
01101     len = RSTRING_LEN(space_before);
01102     if (len == 0) {
01103         if (state->space_before) {
01104             ruby_xfree(state->space_before);
01105             state->space_before = NULL;
01106             state->space_before_len = 0;
01107         }
01108     } else {
01109         if (state->space_before) ruby_xfree(state->space_before);
01110         state->space_before = strdup(RSTRING_PTR(space_before));
01111         state->space_before_len = len;
01112     }
01113     return Qnil;
01114 }
01115 
01116 /*
01117  * call-seq: object_nl()
01118  *
01119  * This string is put at the end of a line that holds a JSON object (or
01120  * Hash).
01121  */
01122 static VALUE cState_object_nl(VALUE self)
01123 {
01124     GET_STATE(self);
01125     return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
01126 }
01127 
01128 /*
01129  * call-seq: object_nl=(object_nl)
01130  *
01131  * This string is put at the end of a line that holds a JSON object (or
01132  * Hash).
01133  */
01134 static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
01135 {
01136     unsigned long len;
01137     GET_STATE(self);
01138     Check_Type(object_nl, T_STRING);
01139     len = RSTRING_LEN(object_nl);
01140     if (len == 0) {
01141         if (state->object_nl) {
01142             ruby_xfree(state->object_nl);
01143             state->object_nl = NULL;
01144         }
01145     } else {
01146         if (state->object_nl) ruby_xfree(state->object_nl);
01147         state->object_nl = strdup(RSTRING_PTR(object_nl));
01148         state->object_nl_len = len;
01149     }
01150     return Qnil;
01151 }
01152 
01153 /*
01154  * call-seq: array_nl()
01155  *
01156  * This string is put at the end of a line that holds a JSON array.
01157  */
01158 static VALUE cState_array_nl(VALUE self)
01159 {
01160     GET_STATE(self);
01161     return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
01162 }
01163 
01164 /*
01165  * call-seq: array_nl=(array_nl)
01166  *
01167  * This string is put at the end of a line that holds a JSON array.
01168  */
01169 static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
01170 {
01171     unsigned long len;
01172     GET_STATE(self);
01173     Check_Type(array_nl, T_STRING);
01174     len = RSTRING_LEN(array_nl);
01175     if (len == 0) {
01176         if (state->array_nl) {
01177             ruby_xfree(state->array_nl);
01178             state->array_nl = NULL;
01179         }
01180     } else {
01181         if (state->array_nl) ruby_xfree(state->array_nl);
01182         state->array_nl = strdup(RSTRING_PTR(array_nl));
01183         state->array_nl_len = len;
01184     }
01185     return Qnil;
01186 }
01187 
01188 
01189 /*
01190 * call-seq: check_circular?
01191 *
01192 * Returns true, if circular data structures should be checked,
01193 * otherwise returns false.
01194 */
01195 static VALUE cState_check_circular_p(VALUE self)
01196 {
01197     GET_STATE(self);
01198     return state->max_nesting ? Qtrue : Qfalse;
01199 }
01200 
01201 /*
01202  * call-seq: max_nesting
01203  *
01204  * This integer returns the maximum level of data structure nesting in
01205  * the generated JSON, max_nesting = 0 if no maximum is checked.
01206  */
01207 static VALUE cState_max_nesting(VALUE self)
01208 {
01209     GET_STATE(self);
01210     return LONG2FIX(state->max_nesting);
01211 }
01212 
01213 /*
01214  * call-seq: max_nesting=(depth)
01215  *
01216  * This sets the maximum level of data structure nesting in the generated JSON
01217  * to the integer depth, max_nesting = 0 if no maximum should be checked.
01218  */
01219 static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
01220 {
01221     GET_STATE(self);
01222     Check_Type(depth, T_FIXNUM);
01223     return state->max_nesting = FIX2LONG(depth);
01224 }
01225 
01226 /*
01227  * call-seq: allow_nan?
01228  *
01229  * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
01230  * returns false.
01231  */
01232 static VALUE cState_allow_nan_p(VALUE self)
01233 {
01234     GET_STATE(self);
01235     return state->allow_nan ? Qtrue : Qfalse;
01236 }
01237 
01238 /*
01239  * call-seq: ascii_only?
01240  *
01241  * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
01242  * returns false.
01243  */
01244 static VALUE cState_ascii_only_p(VALUE self)
01245 {
01246     GET_STATE(self);
01247     return state->ascii_only ? Qtrue : Qfalse;
01248 }
01249 
01250 /*
01251  * call-seq: quirks_mode?
01252  *
01253  * Returns true, if quirks mode is enabled. Otherwise returns false.
01254  */
01255 static VALUE cState_quirks_mode_p(VALUE self)
01256 {
01257     GET_STATE(self);
01258     return state->quirks_mode ? Qtrue : Qfalse;
01259 }
01260 
01261 /*
01262  * call-seq: quirks_mode=(enable)
01263  *
01264  * If set to true, enables the quirks_mode mode.
01265  */
01266 static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
01267 {
01268     GET_STATE(self);
01269     state->quirks_mode = RTEST(enable);
01270     return Qnil;
01271 }
01272 
01273 /*
01274  * call-seq: depth
01275  *
01276  * This integer returns the current depth of data structure nesting.
01277  */
01278 static VALUE cState_depth(VALUE self)
01279 {
01280     GET_STATE(self);
01281     return LONG2FIX(state->depth);
01282 }
01283 
01284 /*
01285  * call-seq: depth=(depth)
01286  *
01287  * This sets the maximum level of data structure nesting in the generated JSON
01288  * to the integer depth, max_nesting = 0 if no maximum should be checked.
01289  */
01290 static VALUE cState_depth_set(VALUE self, VALUE depth)
01291 {
01292     GET_STATE(self);
01293     Check_Type(depth, T_FIXNUM);
01294     state->depth = FIX2LONG(depth);
01295     return Qnil;
01296 }
01297 
01298 /*
01299  * call-seq: buffer_initial_length
01300  *
01301  * This integer returns the current inital length of the buffer.
01302  */
01303 static VALUE cState_buffer_initial_length(VALUE self)
01304 {
01305     GET_STATE(self);
01306     return LONG2FIX(state->buffer_initial_length);
01307 }
01308 
01309 /*
01310  * call-seq: buffer_initial_length=(length)
01311  *
01312  * This sets the initial length of the buffer to +length+, if +length+ > 0,
01313  * otherwise its value isn't changed.
01314  */
01315 static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
01316 {
01317     long initial_length;
01318     GET_STATE(self);
01319     Check_Type(buffer_initial_length, T_FIXNUM);
01320     initial_length = FIX2LONG(buffer_initial_length);
01321     if (initial_length > 0) {
01322         state->buffer_initial_length = initial_length;
01323     }
01324     return Qnil;
01325 }
01326 
01327 /*
01328  *
01329  */
01330 void Init_generator()
01331 {
01332     rb_require("json/common");
01333 
01334     mJSON = rb_define_module("JSON");
01335     mExt = rb_define_module_under(mJSON, "Ext");
01336     mGenerator = rb_define_module_under(mExt, "Generator");
01337 
01338     eGeneratorError = rb_path2class("JSON::GeneratorError");
01339     eNestingError = rb_path2class("JSON::NestingError");
01340 
01341     cState = rb_define_class_under(mGenerator, "State", rb_cObject);
01342     rb_define_alloc_func(cState, cState_s_allocate);
01343     rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
01344     rb_define_method(cState, "initialize", cState_initialize, -1);
01345     rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
01346     rb_define_method(cState, "indent", cState_indent, 0);
01347     rb_define_method(cState, "indent=", cState_indent_set, 1);
01348     rb_define_method(cState, "space", cState_space, 0);
01349     rb_define_method(cState, "space=", cState_space_set, 1);
01350     rb_define_method(cState, "space_before", cState_space_before, 0);
01351     rb_define_method(cState, "space_before=", cState_space_before_set, 1);
01352     rb_define_method(cState, "object_nl", cState_object_nl, 0);
01353     rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
01354     rb_define_method(cState, "array_nl", cState_array_nl, 0);
01355     rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
01356     rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
01357     rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
01358     rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
01359     rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
01360     rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
01361     rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
01362     rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
01363     rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
01364     rb_define_method(cState, "depth", cState_depth, 0);
01365     rb_define_method(cState, "depth=", cState_depth_set, 1);
01366     rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
01367     rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
01368     rb_define_method(cState, "configure", cState_configure, 1);
01369     rb_define_alias(cState, "merge", "configure");
01370     rb_define_method(cState, "to_h", cState_to_h, 0);
01371     rb_define_alias(cState, "to_hash", "to_h");
01372     rb_define_method(cState, "[]", cState_aref, 1);
01373     rb_define_method(cState, "[]=", cState_aset, 2);
01374     rb_define_method(cState, "generate", cState_generate, 1);
01375 
01376     mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
01377     mObject = rb_define_module_under(mGeneratorMethods, "Object");
01378     rb_define_method(mObject, "to_json", mObject_to_json, -1);
01379     mHash = rb_define_module_under(mGeneratorMethods, "Hash");
01380     rb_define_method(mHash, "to_json", mHash_to_json, -1);
01381     mArray = rb_define_module_under(mGeneratorMethods, "Array");
01382     rb_define_method(mArray, "to_json", mArray_to_json, -1);
01383     mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
01384     rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
01385     mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
01386     rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
01387     mFloat = rb_define_module_under(mGeneratorMethods, "Float");
01388     rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
01389     mString = rb_define_module_under(mGeneratorMethods, "String");
01390     rb_define_singleton_method(mString, "included", mString_included_s, 1);
01391     rb_define_method(mString, "to_json", mString_to_json, -1);
01392     rb_define_method(mString, "to_json_raw", mString_to_json_raw, -1);
01393     rb_define_method(mString, "to_json_raw_object", mString_to_json_raw_object, 0);
01394     mString_Extend = rb_define_module_under(mString, "Extend");
01395     rb_define_method(mString_Extend, "json_create", mString_Extend_json_create, 1);
01396     mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
01397     rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
01398     mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
01399     rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
01400     mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
01401     rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
01402 
01403     CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
01404     i_to_s = rb_intern("to_s");
01405     i_to_json = rb_intern("to_json");
01406     i_new = rb_intern("new");
01407     i_indent = rb_intern("indent");
01408     i_space = rb_intern("space");
01409     i_space_before = rb_intern("space_before");
01410     i_object_nl = rb_intern("object_nl");
01411     i_array_nl = rb_intern("array_nl");
01412     i_max_nesting = rb_intern("max_nesting");
01413     i_allow_nan = rb_intern("allow_nan");
01414     i_ascii_only = rb_intern("ascii_only");
01415     i_quirks_mode = rb_intern("quirks_mode");
01416     i_depth = rb_intern("depth");
01417     i_buffer_initial_length = rb_intern("buffer_initial_length");
01418     i_pack = rb_intern("pack");
01419     i_unpack = rb_intern("unpack");
01420     i_create_id = rb_intern("create_id");
01421     i_extend = rb_intern("extend");
01422     i_key_p = rb_intern("key?");
01423     i_aref = rb_intern("[]");
01424     i_send = rb_intern("__send__");
01425     i_respond_to_p = rb_intern("respond_to?");
01426     i_match = rb_intern("match");
01427     i_keys = rb_intern("keys");
01428     i_dup = rb_intern("dup");
01429 #ifdef HAVE_RUBY_ENCODING_H
01430     CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
01431     i_encoding = rb_intern("encoding");
01432     i_encode = rb_intern("encode");
01433 #endif
01434     i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
01435     CJSON_SAFE_STATE_PROTOTYPE = Qnil;
01436 }
01437 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7