Skip to content

Commit 3aeaa4f

Browse files
author
Francois Chagnon
committed
java stuff
1 parent ff4fbcc commit 3aeaa4f

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

java/src/json/ext/Generator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public RuntimeInfo getInfo() {
136136

137137
public StringEncoder getStringEncoder() {
138138
if (stringEncoder == null) {
139-
stringEncoder = new StringEncoder(context, getState().asciiOnly());
139+
stringEncoder = new StringEncoder(context, getState().asciiOnly(), getState().escapeSlash());
140140
}
141141
return stringEncoder;
142142
}

java/src/json/ext/GeneratorState.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ public class GeneratorState extends RubyObject {
8383
*/
8484
private boolean quirksMode = DEFAULT_QUIRKS_MODE;
8585
static final boolean DEFAULT_QUIRKS_MODE = false;
86+
/**
87+
* If set to <code>true</code> the forward slash will be escaped in
88+
* json output.
89+
*/
90+
private boolean escapeSlash = DEFAULT_ESCAPE_SLASH;
91+
static final boolean DEFAULT_ESCAPE_SLASH = false;
8692
/**
8793
* The initial buffer length of this state. (This isn't really used on all
8894
* non-C implementations.)
@@ -172,6 +178,9 @@ static GeneratorState fromState(ThreadContext context, RuntimeInfo info,
172178
* <code>-Infinity</code> should be generated, otherwise an exception is
173179
* thrown if these values are encountered.
174180
* This options defaults to <code>false</code>.
181+
* <dt><code>:escape_slash</code>
182+
* <dd>set to <code>true</code> if the forward slashes should be escaped
183+
* in the json output (default: <code>false</code>)
175184
*/
176185
@JRubyMethod(optional=1, visibility=Visibility.PRIVATE)
177186
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
@@ -195,6 +204,7 @@ public IRubyObject initialize_copy(ThreadContext context, IRubyObject vOrig) {
195204
this.allowNaN = orig.allowNaN;
196205
this.asciiOnly = orig.asciiOnly;
197206
this.quirksMode = orig.quirksMode;
207+
this.escapeSlash = orig.escapeSlash;
198208
this.bufferInitialLength = orig.bufferInitialLength;
199209
this.depth = orig.depth;
200210
return this;
@@ -381,6 +391,24 @@ public IRubyObject max_nesting_set(IRubyObject max_nesting) {
381391
return max_nesting;
382392
}
383393

394+
/**
395+
* Returns true if forward slashes are escaped in the json output.
396+
*/
397+
public int getEscapeSlash() {
398+
return escapeSlash;
399+
}
400+
401+
@JRubyMethod(name="escape_slash")
402+
public RubyBoolean escape_slash_get(ThreadContext context) {
403+
return context.getRuntime().newBoolean(escapeSlash);
404+
}
405+
406+
@JRubyMethod(name="escape_slash=")
407+
public IRubyObject escape_slash_set(IRubyObject escape_slash) {
408+
escapeSlash = escape_slash.isTrue();
409+
return escape_slash.getRuntime().newBoolean(escapeSlash);
410+
}
411+
384412
public boolean allowNaN() {
385413
return allowNaN;
386414
}
@@ -482,6 +510,7 @@ public IRubyObject configure(ThreadContext context, IRubyObject vOpts) {
482510
allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
483511
asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
484512
quirksMode = opts.getBool("quirks_mode", DEFAULT_QUIRKS_MODE);
513+
escapeSlash = opts.getBool("escape_slash", DEFAULT_ESCAPE_SLASH);
485514
bufferInitialLength = opts.getInt("buffer_initial_length", DEFAULT_BUFFER_INITIAL_LENGTH);
486515

487516
depth = opts.getInt("depth", 0);
@@ -510,6 +539,7 @@ public RubyHash to_h(ThreadContext context) {
510539
result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
511540
result.op_aset(context, runtime.newSymbol("quirks_mode"), quirks_mode_p(context));
512541
result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
542+
result.op_aset(context, runtime.newSymbol("escape_slash"), escape_slash_get(context));
513543
result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
514544
result.op_aset(context, runtime.newSymbol("buffer_initial_length"), buffer_initial_length_get(context));
515545
for (String name: getInstanceVariableNameList()) {

java/src/json/ext/StringEncoder.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* and throws a GeneratorError if any problem is found.
1111
*/
1212
final class StringEncoder extends ByteListTranscoder {
13-
private final boolean asciiOnly;
13+
private final boolean asciiOnly, escapeSlash;
1414

1515
// Escaped characters will reuse this array, to avoid new allocations
1616
// or appending them byte-by-byte
@@ -32,9 +32,10 @@ final class StringEncoder extends ByteListTranscoder {
3232
new byte[] {'0', '1', '2', '3', '4', '5', '6', '7',
3333
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
3434

35-
StringEncoder(ThreadContext context, boolean asciiOnly) {
35+
StringEncoder(ThreadContext context, boolean asciiOnly, boolean escapeSlash) {
3636
super(context);
3737
this.asciiOnly = asciiOnly;
38+
this.escapeSlash = escapeSlash;
3839
}
3940

4041
void encode(ByteList src, ByteList out) {
@@ -50,7 +51,6 @@ void encode(ByteList src, ByteList out) {
5051
private void handleChar(int c) {
5152
switch (c) {
5253
case '"':
53-
case '/':
5454
case '\\':
5555
escapeChar((char)c);
5656
break;
@@ -69,6 +69,11 @@ private void handleChar(int c) {
6969
case '\b':
7070
escapeChar('b');
7171
break;
72+
case '/':
73+
if(escapeSlash) {
74+
escapeChar((char)c);
75+
break;
76+
}
7277
default:
7378
if (c >= 0x20 && c <= 0x7f ||
7479
(c >= 0x80 && !asciiOnly)) {

0 commit comments

Comments
 (0)