setbyte / ungetbyte allow out-of-range integers
* string.c: String#setbyte to accept arbitrary integers [Bug #15460] * io.c: ditto for IO#ungetbyte * ext/strringio/stringio.c: ditto for StringIO#ungetbyte git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66824 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
5e84537d32
commit
d154bec0d5
@ -805,33 +805,26 @@ strio_ungetbyte(VALUE self, VALUE c)
|
|||||||
struct StringIO *ptr = readable(self);
|
struct StringIO *ptr = readable(self);
|
||||||
|
|
||||||
check_modifiable(ptr);
|
check_modifiable(ptr);
|
||||||
if (NIL_P(c)) return Qnil;
|
switch (TYPE(c)) {
|
||||||
if (FIXNUM_P(c)) {
|
case T_NIL:
|
||||||
int i = FIX2INT(c);
|
return Qnil;
|
||||||
if (0 <= i && i <= UCHAR_MAX) {
|
case T_FIXNUM:
|
||||||
char buf[1];
|
case T_BIGNUM: ;
|
||||||
buf[0] = (char)i;
|
/* rb_int_modulo() not visible from exts */
|
||||||
return strio_unget_bytes(ptr, buf, 1);
|
VALUE v = rb_funcall(c, rb_intern("modulo"), 1, INT2FIX(256));
|
||||||
}
|
unsigned char cc = NUM2INT(v) & 0xFF;
|
||||||
else {
|
c = rb_str_new((const char *)&cc, 1);
|
||||||
rb_raise(rb_eRangeError,
|
break;
|
||||||
"integer %d too big to convert into `unsigned char'", i);
|
default:
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (RB_TYPE_P(c, T_BIGNUM)) {
|
|
||||||
rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char *cp;
|
|
||||||
long cl;
|
|
||||||
SafeStringValue(c);
|
SafeStringValue(c);
|
||||||
cp = RSTRING_PTR(c);
|
}
|
||||||
cl = RSTRING_LEN(c);
|
|
||||||
|
const char *cp = RSTRING_PTR(c);
|
||||||
|
long cl = RSTRING_LEN(c);
|
||||||
if (cl == 0) return Qnil;
|
if (cl == 0) return Qnil;
|
||||||
strio_unget_bytes(ptr, cp, cl);
|
strio_unget_bytes(ptr, cp, cl);
|
||||||
RB_GC_GUARD(c);
|
RB_GC_GUARD(c);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
26
io.c
26
io.c
@ -4258,22 +4258,16 @@ rb_io_ungetbyte(VALUE io, VALUE b)
|
|||||||
|
|
||||||
GetOpenFile(io, fptr);
|
GetOpenFile(io, fptr);
|
||||||
rb_io_check_byte_readable(fptr);
|
rb_io_check_byte_readable(fptr);
|
||||||
if (NIL_P(b)) return Qnil;
|
switch (TYPE(b)) {
|
||||||
if (FIXNUM_P(b)) {
|
case T_NIL:
|
||||||
int i = FIX2INT(b);
|
return Qnil;
|
||||||
if (0 <= i && i <= UCHAR_MAX) {
|
case T_FIXNUM:
|
||||||
unsigned char cc = i & 0xFF;
|
case T_BIGNUM: ;
|
||||||
b = rb_str_new((const char *)&cc, 1);
|
VALUE v = rb_int_modulo(b, INT2FIX(256));
|
||||||
}
|
unsigned char c = NUM2INT(v) & 0xFF;
|
||||||
else {
|
b = rb_str_new((const char *)&c, 1);
|
||||||
rb_raise(rb_eRangeError,
|
break;
|
||||||
"integer %d too big to convert into `unsigned char'", i);
|
default:
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (RB_TYPE_P(b, T_BIGNUM)) {
|
|
||||||
rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SafeStringValue(b);
|
SafeStringValue(b);
|
||||||
}
|
}
|
||||||
io_ungetbyte(b, fptr);
|
io_ungetbyte(b, fptr);
|
||||||
|
@ -49,7 +49,7 @@ describe "IO#ungetbyte" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ruby_version_is '2.6' do
|
ruby_version_is '2.6'...'2.7' do
|
||||||
it "is an RangeError if the integer is not in 8bit" do
|
it "is an RangeError if the integer is not in 8bit" do
|
||||||
for i in [4095, 0x4f7574206f6620636861722072616e6765] do
|
for i in [4095, 0x4f7574206f6620636861722072616e6765] do
|
||||||
lambda { @io.ungetbyte(i) }.should raise_error(RangeError)
|
lambda { @io.ungetbyte(i) }.should raise_error(RangeError)
|
||||||
@ -57,6 +57,14 @@ describe "IO#ungetbyte" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.7' do
|
||||||
|
it "never raises RangeError" do
|
||||||
|
for i in [4095, 0x4f7574206f6620636861722072616e6765] do
|
||||||
|
lambda { @io.ungetbyte(i) }.should_not raise_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "raises an IOError if the IO is closed" do
|
it "raises an IOError if the IO is closed" do
|
||||||
@io.close
|
@io.close
|
||||||
lambda { @io.ungetbyte(42) }.should raise_error(IOError)
|
lambda { @io.ungetbyte(42) }.should raise_error(IOError)
|
||||||
|
9
string.c
9
string.c
@ -5409,7 +5409,6 @@ static VALUE
|
|||||||
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
|
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
|
||||||
{
|
{
|
||||||
long pos = NUM2LONG(index);
|
long pos = NUM2LONG(index);
|
||||||
int byte = NUM2INT(value);
|
|
||||||
long len = RSTRING_LEN(str);
|
long len = RSTRING_LEN(str);
|
||||||
char *head, *left = 0;
|
char *head, *left = 0;
|
||||||
unsigned char *ptr;
|
unsigned char *ptr;
|
||||||
@ -5420,10 +5419,10 @@ rb_str_setbyte(VALUE str, VALUE index, VALUE value)
|
|||||||
rb_raise(rb_eIndexError, "index %ld out of string", pos);
|
rb_raise(rb_eIndexError, "index %ld out of string", pos);
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
pos += len;
|
pos += len;
|
||||||
if (byte < 0)
|
|
||||||
rb_raise(rb_eRangeError, "integer %d too small to convert into `unsigned char'", byte);
|
VALUE v = rb_to_int(value);
|
||||||
if (UCHAR_MAX < byte)
|
VALUE w = rb_int_modulo(v, INT2FIX(256));
|
||||||
rb_raise(rb_eRangeError, "integer %d too big to convert into `unsigned char'", byte);
|
unsigned char byte = NUM2INT(w) & 0xFF;
|
||||||
|
|
||||||
if (!str_independent(str))
|
if (!str_independent(str))
|
||||||
str_make_independent(str);
|
str_make_independent(str);
|
||||||
|
@ -1526,13 +1526,13 @@ class TestM17N < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_setbyte_range
|
def test_setbyte_range
|
||||||
s = u("\xE3\x81\x82\xE3\x81\x84")
|
s = u("\xE3\x81\x82\xE3\x81\x84")
|
||||||
assert_raise(RangeError) { s.setbyte(0, -1) }
|
assert_nothing_raised { s.setbyte(0, -1) }
|
||||||
assert_nothing_raised { s.setbyte(0, 0x00) }
|
assert_nothing_raised { s.setbyte(0, 0x00) }
|
||||||
assert_nothing_raised { s.setbyte(0, 0x7F) }
|
assert_nothing_raised { s.setbyte(0, 0x7F) }
|
||||||
assert_nothing_raised { s.setbyte(0, 0x80) }
|
assert_nothing_raised { s.setbyte(0, 0x80) }
|
||||||
assert_nothing_raised { s.setbyte(0, 0xff) }
|
assert_nothing_raised { s.setbyte(0, 0xff) }
|
||||||
assert_raise(RangeError) { s.setbyte(0, 0x100) }
|
assert_nothing_raised { s.setbyte(0, 0x100) }
|
||||||
assert_raise(RangeError) { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
|
assert_nothing_raised { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compatible
|
def test_compatible
|
||||||
|
@ -453,9 +453,9 @@ class TestStringIO < Test::Unit::TestCase
|
|||||||
assert_equal(0, t.pos)
|
assert_equal(0, t.pos)
|
||||||
assert_equal("\u{30eb 30d3 30fc}\u7d05\u7389bar\n", s)
|
assert_equal("\u{30eb 30d3 30fc}\u7d05\u7389bar\n", s)
|
||||||
|
|
||||||
assert_raise(RangeError) {t.ungetbyte(-1)}
|
assert_nothing_raised {t.ungetbyte(-1)}
|
||||||
assert_raise(RangeError) {t.ungetbyte(256)}
|
assert_nothing_raised {t.ungetbyte(256)}
|
||||||
assert_raise(RangeError) {t.ungetbyte(1<<64)}
|
assert_nothing_raised {t.ungetbyte(1<<64)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ungetc
|
def test_ungetc
|
||||||
|
Loading…
x
Reference in New Issue
Block a user