@@ -16,7 +16,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
1616 i_object_nl , i_array_nl , i_max_nesting , i_allow_nan , i_ascii_only ,
1717 i_pack , i_unpack , i_create_id , i_extend , i_key_p ,
1818 i_aref , i_send , i_respond_to_p , i_match , i_keys , i_depth ,
19- i_buffer_initial_length , i_dup , i_escape_slash ;
19+ i_buffer_initial_length , i_dup , i_script_safe , i_escape_slash ;
2020
2121/*
2222 * Copyright 2001-2004 Unicode, Inc.
@@ -124,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
124124
125125/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
126126 * and control characters are JSON escaped. */
127- static void convert_UTF8_to_JSON_ASCII (FBuffer * buffer , VALUE string , char escape_slash )
127+ static void convert_UTF8_to_JSON_ASCII (FBuffer * buffer , VALUE string , char script_safe )
128128{
129129 const UTF8 * source = (UTF8 * ) RSTRING_PTR (string );
130130 const UTF8 * sourceEnd = source + RSTRING_LEN (string );
@@ -175,7 +175,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escap
175175 fbuffer_append (buffer , "\\\"" , 2 );
176176 break ;
177177 case '/' :
178- if (escape_slash ) {
178+ if (script_safe ) {
179179 fbuffer_append (buffer , "\\/" , 2 );
180180 break ;
181181 }
@@ -228,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escap
228228 * characters required by the JSON standard are JSON escaped. The remaining
229229 * characters (should be UTF8) are just passed through and appended to the
230230 * result. */
231- static void convert_UTF8_to_JSON (FBuffer * buffer , VALUE string , char escape_slash )
231+ static void convert_UTF8_to_JSON (FBuffer * buffer , VALUE string , char script_safe )
232232{
233233 const char * ptr = RSTRING_PTR (string ), * p ;
234234 unsigned long len = RSTRING_LEN (string ), start = 0 , end = 0 ;
@@ -280,7 +280,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slas
280280 escape_len = 2 ;
281281 break ;
282282 case '/' :
283- if (escape_slash ) {
283+ if (script_safe ) {
284284 escape = "\\/" ;
285285 escape_len = 2 ;
286286 break ;
@@ -294,6 +294,22 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slas
294294 rb_raise (rb_path2class ("JSON::GeneratorError" ),
295295 "partial character in source, but hit end" );
296296 }
297+
298+ if (script_safe && c == 0xE2 ) {
299+ unsigned char c2 = (unsigned char ) * (p + 1 );
300+ unsigned char c3 = (unsigned char ) * (p + 2 );
301+ if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9 )) {
302+ fbuffer_append (buffer , ptr + start , end - start );
303+ start = end = (end + clen );
304+ if (c3 == 0xA8 ) {
305+ fbuffer_append (buffer , "\\u2028" , 6 );
306+ } else {
307+ fbuffer_append (buffer , "\\u2029" , 6 );
308+ }
309+ continue ;
310+ }
311+ }
312+
297313 if (!isLegalUTF8 ((UTF8 * ) p , clen )) {
298314 rb_raise (rb_path2class ("JSON::GeneratorError" ),
299315 "source sequence is illegal/malformed utf-8" );
@@ -726,8 +742,12 @@ static VALUE cState_configure(VALUE self, VALUE opts)
726742 state -> allow_nan = RTEST (tmp );
727743 tmp = rb_hash_aref (opts , ID2SYM (i_ascii_only ));
728744 state -> ascii_only = RTEST (tmp );
729- tmp = rb_hash_aref (opts , ID2SYM (i_escape_slash ));
730- state -> escape_slash = RTEST (tmp );
745+ tmp = rb_hash_aref (opts , ID2SYM (i_script_safe ));
746+ state -> script_safe = RTEST (tmp );
747+ if (!state -> script_safe ) {
748+ tmp = rb_hash_aref (opts , ID2SYM (i_escape_slash ));
749+ state -> script_safe = RTEST (tmp );
750+ }
731751 return self ;
732752}
733753
@@ -762,7 +782,7 @@ static VALUE cState_to_h(VALUE self)
762782 rb_hash_aset (result , ID2SYM (i_allow_nan ), state -> allow_nan ? Qtrue : Qfalse );
763783 rb_hash_aset (result , ID2SYM (i_ascii_only ), state -> ascii_only ? Qtrue : Qfalse );
764784 rb_hash_aset (result , ID2SYM (i_max_nesting ), LONG2FIX (state -> max_nesting ));
765- rb_hash_aset (result , ID2SYM (i_escape_slash ), state -> escape_slash ? Qtrue : Qfalse );
785+ rb_hash_aset (result , ID2SYM (i_script_safe ), state -> script_safe ? Qtrue : Qfalse );
766786 rb_hash_aset (result , ID2SYM (i_depth ), LONG2FIX (state -> depth ));
767787 rb_hash_aset (result , ID2SYM (i_buffer_initial_length ), LONG2FIX (state -> buffer_initial_length ));
768788 return result ;
@@ -947,9 +967,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
947967 }
948968#endif
949969 if (state -> ascii_only ) {
950- convert_UTF8_to_JSON_ASCII (buffer , obj , state -> escape_slash );
970+ convert_UTF8_to_JSON_ASCII (buffer , obj , state -> script_safe );
951971 } else {
952- convert_UTF8_to_JSON (buffer , obj , state -> escape_slash );
972+ convert_UTF8_to_JSON (buffer , obj , state -> script_safe );
953973 }
954974 fbuffer_append_char (buffer , '"' );
955975}
@@ -1390,27 +1410,27 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
13901410}
13911411
13921412/*
1393- * call-seq: escape_slash
1413+ * call-seq: script_safe
13941414 *
13951415 * If this boolean is true, the forward slashes will be escaped in
13961416 * the json output.
13971417 */
1398- static VALUE cState_escape_slash (VALUE self )
1418+ static VALUE cState_script_safe (VALUE self )
13991419{
14001420 GET_STATE (self );
1401- return state -> escape_slash ? Qtrue : Qfalse ;
1421+ return state -> script_safe ? Qtrue : Qfalse ;
14021422}
14031423
14041424/*
1405- * call-seq: escape_slash =(depth)
1425+ * call-seq: script_safe =(depth)
14061426 *
14071427 * This sets whether or not the forward slashes will be escaped in
14081428 * the json output.
14091429 */
1410- static VALUE cState_escape_slash_set (VALUE self , VALUE enable )
1430+ static VALUE cState_script_safe_set (VALUE self , VALUE enable )
14111431{
14121432 GET_STATE (self );
1413- state -> escape_slash = RTEST (enable );
1433+ state -> script_safe = RTEST (enable );
14141434 return Qnil ;
14151435}
14161436
@@ -1530,9 +1550,12 @@ void Init_generator(void)
15301550 rb_define_method (cState , "array_nl=" , cState_array_nl_set , 1 );
15311551 rb_define_method (cState , "max_nesting" , cState_max_nesting , 0 );
15321552 rb_define_method (cState , "max_nesting=" , cState_max_nesting_set , 1 );
1533- rb_define_method (cState , "escape_slash" , cState_escape_slash , 0 );
1534- rb_define_method (cState , "escape_slash?" , cState_escape_slash , 0 );
1535- rb_define_method (cState , "escape_slash=" , cState_escape_slash_set , 1 );
1553+ rb_define_method (cState , "script_safe" , cState_script_safe , 0 );
1554+ rb_define_method (cState , "script_safe?" , cState_script_safe , 0 );
1555+ rb_define_method (cState , "script_safe=" , cState_script_safe_set , 1 );
1556+ rb_define_alias (cState , "escape_slash" , "script_safe" );
1557+ rb_define_alias (cState , "escape_slash?" , "script_safe?" );
1558+ rb_define_alias (cState , "escape_slash=" , "script_safe=" );
15361559 rb_define_method (cState , "check_circular?" , cState_check_circular_p , 0 );
15371560 rb_define_method (cState , "allow_nan?" , cState_allow_nan_p , 0 );
15381561 rb_define_method (cState , "ascii_only?" , cState_ascii_only_p , 0 );
@@ -1589,6 +1612,7 @@ void Init_generator(void)
15891612 i_object_nl = rb_intern ("object_nl" );
15901613 i_array_nl = rb_intern ("array_nl" );
15911614 i_max_nesting = rb_intern ("max_nesting" );
1615+ i_script_safe = rb_intern ("script_safe" );
15921616 i_escape_slash = rb_intern ("escape_slash" );
15931617 i_allow_nan = rb_intern ("allow_nan" );
15941618 i_ascii_only = rb_intern ("ascii_only" );
0 commit comments