| 
55 | 55 | import org.jruby.runtime.marshal.DataType;  | 
56 | 56 | import org.jruby.util.ArraySupport;  | 
57 | 57 | import org.jruby.util.ByteList;  | 
 | 58 | +import org.jruby.util.CodeRangeable;  | 
58 | 59 | import org.jruby.util.StringSupport;  | 
59 | 60 | import org.jruby.util.TypeConverter;  | 
60 | 61 | import org.jruby.util.func.ObjectObjectIntFunction;  | 
@@ -1655,7 +1656,7 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)  | 
1655 | 1656 |             if (enc != encStr && enc != ASCIIEncoding.INSTANCE && enc != USASCIIEncoding.INSTANCE) {  | 
1656 | 1657 |                 RubyString converted = EncodingUtils.strConvEnc(context, str, encStr, enc);  | 
1657 | 1658 |                 if (converted == str && encStr != ASCIIEncoding.INSTANCE && encStr != USASCIIEncoding.INSTANCE) { /* conversion failed */  | 
1658 |  | -                    ptr.string.checkEncoding(str);  | 
 | 1659 | +                    rb_enc_check_hack(context, enc, str);  | 
1659 | 1660 |                 }  | 
1660 | 1661 |                 str = converted;  | 
1661 | 1662 |             }  | 
@@ -1689,6 +1690,50 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)  | 
1689 | 1690 |         return len;  | 
1690 | 1691 |     }  | 
1691 | 1692 | 
 
  | 
 | 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 | + | 
1692 | 1737 |     @JRubyMethod  | 
1693 | 1738 |     public IRubyObject set_encoding(ThreadContext context, IRubyObject ext_enc) {  | 
1694 | 1739 |         Encoding enc;  | 
 | 
0 commit comments