@@ -22,7 +22,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
2222 i_object_nl , i_array_nl , i_max_nesting , i_allow_nan , i_ascii_only ,
2323 i_pack , i_unpack , i_create_id , i_extend , i_key_p ,
2424 i_aref , i_send , i_respond_to_p , i_match , i_keys , i_depth ,
25- i_buffer_initial_length , i_dup ;
25+ i_buffer_initial_length , i_dup , i_escape_slash ;
2626
2727/*
2828 * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +130,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130130
131131/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132132 * and control characters are JSON escaped. */
133- static void convert_UTF8_to_JSON_ASCII (FBuffer * buffer , VALUE string )
133+ static void convert_UTF8_to_JSON_ASCII (FBuffer * buffer , VALUE string , char escape_slash )
134134{
135135 const UTF8 * source = (UTF8 * ) RSTRING_PTR (string );
136136 const UTF8 * sourceEnd = source + RSTRING_LEN (string );
@@ -180,6 +180,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180180 case '"' :
181181 fbuffer_append (buffer , "\\\"" , 2 );
182182 break ;
183+ case '/' :
184+ if (escape_slash ) {
185+ fbuffer_append (buffer , "\\/" , 2 );
186+ break ;
187+ }
183188 default :
184189 fbuffer_append_char (buffer , (char )ch );
185190 break ;
@@ -229,7 +234,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
229234 * characters required by the JSON standard are JSON escaped. The remaining
230235 * characters (should be UTF8) are just passed through and appended to the
231236 * result. */
232- static void convert_UTF8_to_JSON (FBuffer * buffer , VALUE string )
237+ static void convert_UTF8_to_JSON (FBuffer * buffer , VALUE string , char escape_slash )
233238{
234239 const char * ptr = RSTRING_PTR (string ), * p ;
235240 unsigned long len = RSTRING_LEN (string ), start = 0 , end = 0 ;
@@ -280,6 +285,12 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
280285 escape = "\\\"" ;
281286 escape_len = 2 ;
282287 break ;
288+ case '/' :
289+ if (escape_slash ) {
290+ escape = "\\/" ;
291+ escape_len = 2 ;
292+ break ;
293+ }
283294 default :
284295 {
285296 unsigned short clen = 1 ;
@@ -716,6 +727,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
716727 state -> allow_nan = RTEST (tmp );
717728 tmp = rb_hash_aref (opts , ID2SYM (i_ascii_only ));
718729 state -> ascii_only = RTEST (tmp );
730+ tmp = rb_hash_aref (opts , ID2SYM (i_escape_slash ));
731+ state -> escape_slash = RTEST (tmp );
719732 return self ;
720733}
721734
@@ -750,6 +763,7 @@ static VALUE cState_to_h(VALUE self)
750763 rb_hash_aset (result , ID2SYM (i_allow_nan ), state -> allow_nan ? Qtrue : Qfalse );
751764 rb_hash_aset (result , ID2SYM (i_ascii_only ), state -> ascii_only ? Qtrue : Qfalse );
752765 rb_hash_aset (result , ID2SYM (i_max_nesting ), LONG2FIX (state -> max_nesting ));
766+ rb_hash_aset (result , ID2SYM (i_escape_slash ), state -> escape_slash ? Qtrue : Qfalse );
753767 rb_hash_aset (result , ID2SYM (i_depth ), LONG2FIX (state -> depth ));
754768 rb_hash_aset (result , ID2SYM (i_buffer_initial_length ), LONG2FIX (state -> buffer_initial_length ));
755769 return result ;
@@ -934,9 +948,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
934948 }
935949#endif
936950 if (state -> ascii_only ) {
937- convert_UTF8_to_JSON_ASCII (buffer , obj );
951+ convert_UTF8_to_JSON_ASCII (buffer , obj , state -> escape_slash );
938952 } else {
939- convert_UTF8_to_JSON (buffer , obj );
953+ convert_UTF8_to_JSON (buffer , obj , state -> escape_slash );
940954 }
941955 fbuffer_append_char (buffer , '"' );
942956}
@@ -1377,6 +1391,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
13771391 return state -> max_nesting = FIX2LONG (depth );
13781392}
13791393
1394+ /*
1395+ * call-seq: escape_slash
1396+ *
1397+ * If this boolean is true, the forward slashes will be escaped in
1398+ * the json output.
1399+ */
1400+ static VALUE cState_escape_slash (VALUE self )
1401+ {
1402+ GET_STATE (self );
1403+ return state -> escape_slash ? Qtrue : Qfalse ;
1404+ }
1405+
1406+ /*
1407+ * call-seq: escape_slash=(depth)
1408+ *
1409+ * This sets whether or not the forward slashes will be escaped in
1410+ * the json output.
1411+ */
1412+ static VALUE cState_escape_slash_set (VALUE self , VALUE enable )
1413+ {
1414+ GET_STATE (self );
1415+ state -> escape_slash = RTEST (enable );
1416+ return Qnil ;
1417+ }
1418+
13801419/*
13811420 * call-seq: allow_nan?
13821421 *
@@ -1489,6 +1528,9 @@ void Init_generator(void)
14891528 rb_define_method (cState , "array_nl=" , cState_array_nl_set , 1 );
14901529 rb_define_method (cState , "max_nesting" , cState_max_nesting , 0 );
14911530 rb_define_method (cState , "max_nesting=" , cState_max_nesting_set , 1 );
1531+ rb_define_method (cState , "escape_slash" , cState_escape_slash , 0 );
1532+ rb_define_method (cState , "escape_slash?" , cState_escape_slash , 0 );
1533+ rb_define_method (cState , "escape_slash=" , cState_escape_slash_set , 1 );
14921534 rb_define_method (cState , "check_circular?" , cState_check_circular_p , 0 );
14931535 rb_define_method (cState , "allow_nan?" , cState_allow_nan_p , 0 );
14941536 rb_define_method (cState , "ascii_only?" , cState_ascii_only_p , 0 );
@@ -1545,6 +1587,7 @@ void Init_generator(void)
15451587 i_object_nl = rb_intern ("object_nl" );
15461588 i_array_nl = rb_intern ("array_nl" );
15471589 i_max_nesting = rb_intern ("max_nesting" );
1590+ i_escape_slash = rb_intern ("escape_slash" );
15481591 i_allow_nan = rb_intern ("allow_nan" );
15491592 i_ascii_only = rb_intern ("ascii_only" );
15501593 i_depth = rb_intern ("depth" );
0 commit comments