Skip to content

Commit 247173b

Browse files
committed
Add rb_enc_check that ignores empty str1
The version of this method in JRuby does not support passing an encoding for the first argument, which means downstream code in enc_compatible_latter will not reject cases StringIO is expected to reject. This patch hacks a version of rb_enc_check that works with current JRuby versions and exhibits the behavior required. A future JRuby update will improve this API and this hack should become a fallback at that point (for older JRuby versions).
1 parent 18c7d46 commit 247173b

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

ext/java/org/jruby/ext/stringio/StringIO.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.jruby.runtime.marshal.DataType;
5656
import org.jruby.util.ArraySupport;
5757
import org.jruby.util.ByteList;
58+
import org.jruby.util.CodeRangeable;
5859
import org.jruby.util.StringSupport;
5960
import org.jruby.util.TypeConverter;
6061
import org.jruby.util.func.ObjectObjectIntFunction;
@@ -1655,7 +1656,7 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
16551656
if (enc != encStr && enc != ASCIIEncoding.INSTANCE && enc != USASCIIEncoding.INSTANCE) {
16561657
RubyString converted = EncodingUtils.strConvEnc(context, str, encStr, enc);
16571658
if (converted == str && encStr != ASCIIEncoding.INSTANCE && encStr != USASCIIEncoding.INSTANCE) { /* conversion failed */
1658-
ptr.string.checkEncoding(str);
1659+
rb_enc_check_hack(context, enc, str);
16591660
}
16601661
str = converted;
16611662
}
@@ -1689,6 +1690,50 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
16891690
return len;
16901691
}
16911692

1693+
/*
1694+
This hack inlines the JRuby version of rb_enc_check (RubString.checkEncoding) because it only supports str1 being
1695+
a true string. This breaks an expectation in StringIO test "test_write_encoding_conversion".
1696+
1697+
If the StringIO string is blank, logic downstream from "rb_enc_check" in "encoding_compatible_latter" will simply
1698+
choose the second encoding rather than fail as the test expects.
1699+
1700+
See discussion in https://github.com/ruby/stringio/pull/116.
1701+
*/
1702+
private static void rb_enc_check_hack(ThreadContext context, Encoding enc, CodeRangeable str) {
1703+
CodeRangeable fakeCodeRangeable = new EncodingOnlyCodeRangeable(enc);
1704+
Encoding enc1 = StringSupport.areCompatible(fakeCodeRangeable, str);
1705+
if (enc1 == null) throw context.runtime.newEncodingCompatibilityError("incompatible character encodings: " +
1706+
enc1 + " and " + str.getByteList().getEncoding());
1707+
}
1708+
1709+
private static class EncodingOnlyCodeRangeable implements CodeRangeable {
1710+
private final Encoding enc;
1711+
1712+
public EncodingOnlyCodeRangeable(Encoding enc) {this.enc = enc;}
1713+
@Override
1714+
public int getCodeRange() {return 0;}
1715+
@Override
1716+
public int scanForCodeRange() {return 0;}
1717+
@Override
1718+
public boolean isCodeRangeValid() {return false;}
1719+
@Override
1720+
public void setCodeRange(int codeRange) {}
1721+
@Override
1722+
public void clearCodeRange() {}
1723+
@Override
1724+
public void keepCodeRange() {}
1725+
@Override
1726+
public void modifyAndKeepCodeRange() {}
1727+
@Override
1728+
public Encoding checkEncoding(CodeRangeable other) {return null;}
1729+
@Override
1730+
public ByteList getByteList() {return new ByteList(0, enc);}
1731+
@Override
1732+
public void modify() {}
1733+
@Override
1734+
public void modify(int length) {}
1735+
}
1736+
16921737
@JRubyMethod
16931738
public IRubyObject set_encoding(ThreadContext context, IRubyObject ext_enc) {
16941739
Encoding enc;

0 commit comments

Comments
 (0)