* pack.c (pack_pack): support endian modifiers: < and >.
[ruby-dev:42376] Feature #3491 * pack.c (pack_unpack): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29496 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b1085abaeb
commit
5825359dd8
|
@ -1,3 +1,10 @@
|
||||||
|
Thu Oct 14 20:41:27 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
|
* pack.c (pack_pack): support endian modifiers: < and >.
|
||||||
|
[ruby-dev:42376] Feature #3491
|
||||||
|
|
||||||
|
* pack.c (pack_unpack): ditto.
|
||||||
|
|
||||||
Thu Oct 14 20:50:51 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
|
Thu Oct 14 20:50:51 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
|
||||||
|
|
||||||
* ext/win32ole/win32ole.c (reg_get_val): expand environment in
|
* ext/win32ole/win32ole.c (reg_get_val): expand environment in
|
||||||
|
|
6
NEWS
6
NEWS
|
@ -31,6 +31,8 @@ with all sufficient information, see the ChangeLog file.
|
||||||
* new constants:
|
* new constants:
|
||||||
* File::NULL
|
* File::NULL
|
||||||
name of NULL device.
|
name of NULL device.
|
||||||
|
* extended methods:
|
||||||
|
* String#unpack supports endian modifiers
|
||||||
|
|
||||||
* String
|
* String
|
||||||
* new methods:
|
* new methods:
|
||||||
|
@ -44,6 +46,10 @@ with all sufficient information, see the ChangeLog file.
|
||||||
* extended methods:
|
* extended methods:
|
||||||
* IO#putc supports multibyte characters
|
* IO#putc supports multibyte characters
|
||||||
|
|
||||||
|
* Array
|
||||||
|
* extended methods:
|
||||||
|
* Array#pack supports endian modifiers
|
||||||
|
|
||||||
* io/console
|
* io/console
|
||||||
* new methods:
|
* new methods:
|
||||||
* IO#noecho {|io| }
|
* IO#noecho {|io| }
|
||||||
|
|
101
pack.c
101
pack.c
|
@ -330,14 +330,6 @@ static unsigned long utf8_to_uv(const char*,long*);
|
||||||
* l | Integer | 32-bit signed, native endian (int32_t)
|
* l | Integer | 32-bit signed, native endian (int32_t)
|
||||||
* q | Integer | 64-bit signed, native endian (int64_t)
|
* q | Integer | 64-bit signed, native endian (int64_t)
|
||||||
* | |
|
* | |
|
||||||
* S_, S! | Integer | unsigned short, native endian
|
|
||||||
* I, I_, I! | Integer | unsigned int, native endian
|
|
||||||
* L_, L! | Integer | unsigned long, native endian
|
|
||||||
* | |
|
|
||||||
* s_, s! | Integer | signed short, native endian
|
|
||||||
* i, i_, i! | Integer | signed int, native endian
|
|
||||||
* l_, l! | Integer | signed long, native endian
|
|
||||||
* | |
|
|
||||||
* n | Integer | 16-bit unsigned, network (big-endian) byte order
|
* n | Integer | 16-bit unsigned, network (big-endian) byte order
|
||||||
* N | Integer | 32-bit unsigned, network (big-endian) byte order
|
* N | Integer | 32-bit unsigned, network (big-endian) byte order
|
||||||
* v | Integer | 16-bit unsigned, VAX (little-endian) byte order
|
* v | Integer | 16-bit unsigned, VAX (little-endian) byte order
|
||||||
|
@ -379,6 +371,14 @@ static unsigned long utf8_to_uv(const char*,long*);
|
||||||
* @ | --- | moves to absolute position
|
* @ | --- | moves to absolute position
|
||||||
* X | --- | back up a byte
|
* X | --- | back up a byte
|
||||||
* x | --- | null byte
|
* x | --- | null byte
|
||||||
|
*
|
||||||
|
* | Target |
|
||||||
|
* Modifier | Directive | Meaning
|
||||||
|
* ---------------------------------------------------------------------------
|
||||||
|
* _, ! | sSiIlL | Force native size of the related type:
|
||||||
|
* | | short, int, long, and long long
|
||||||
|
* > | sSiIlLqQ | Force big-endian byte order
|
||||||
|
* < | sSiIlLqQ | Force little-endian byte order
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -396,6 +396,7 @@ pack_pack(VALUE ary, VALUE fmt)
|
||||||
int natint; /* native integer */
|
int natint; /* native integer */
|
||||||
#endif
|
#endif
|
||||||
int signed_p, integer_size, bigendian_p;
|
int signed_p, integer_size, bigendian_p;
|
||||||
|
int explicit_endian = 0;
|
||||||
|
|
||||||
StringValue(fmt);
|
StringValue(fmt);
|
||||||
p = RSTRING_PTR(fmt);
|
p = RSTRING_PTR(fmt);
|
||||||
|
@ -425,19 +426,39 @@ pack_pack(VALUE ary, VALUE fmt)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*p == '_' || *p == '!') {
|
|
||||||
static const char natstr[] = "sSiIlL";
|
|
||||||
|
|
||||||
if (strchr(natstr, type)) {
|
{
|
||||||
|
static const char natstr[] = "sSiIlL";
|
||||||
|
static const char endstr[] = "sSiIlLqQ";
|
||||||
|
|
||||||
|
modifiers:
|
||||||
|
switch (*p) {
|
||||||
|
case '_':
|
||||||
|
case '!':
|
||||||
|
if (strchr(natstr, type)) {
|
||||||
#ifdef NATINT_PACK
|
#ifdef NATINT_PACK
|
||||||
natint = 1;
|
natint = 1;
|
||||||
#endif
|
#endif
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
|
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
|
||||||
|
}
|
||||||
|
goto modifiers;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
if (!strchr(endstr, type)) {
|
||||||
|
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
|
||||||
|
}
|
||||||
|
if (explicit_endian) {
|
||||||
|
rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
|
||||||
|
}
|
||||||
|
explicit_endian = *p++;
|
||||||
|
goto modifiers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '*') { /* set data length */
|
if (*p == '*') { /* set data length */
|
||||||
len = strchr("@Xxu", type) ? 0
|
len = strchr("@Xxu", type) ? 0
|
||||||
: strchr("PMm", type) ? 1
|
: strchr("PMm", type) ? 1
|
||||||
|
@ -716,6 +737,10 @@ pack_pack(VALUE ary, VALUE fmt)
|
||||||
goto pack_integer;
|
goto pack_integer;
|
||||||
|
|
||||||
pack_integer:
|
pack_integer:
|
||||||
|
if (explicit_endian) {
|
||||||
|
bigendian_p = ((explicit_endian - '<') != 0);
|
||||||
|
}
|
||||||
|
|
||||||
switch (integer_size) {
|
switch (integer_size) {
|
||||||
#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
|
#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
|
||||||
case SIZEOF_INT16_T:
|
case SIZEOF_INT16_T:
|
||||||
|
@ -1309,6 +1334,7 @@ pack_unpack(VALUE str, VALUE fmt)
|
||||||
#endif
|
#endif
|
||||||
int block_p = rb_block_given_p();
|
int block_p = rb_block_given_p();
|
||||||
int signed_p, integer_size, bigendian_p;
|
int signed_p, integer_size, bigendian_p;
|
||||||
|
int explicit_endian = 0;
|
||||||
#define UNPACK_PUSH(item) do {\
|
#define UNPACK_PUSH(item) do {\
|
||||||
VALUE item_val = (item);\
|
VALUE item_val = (item);\
|
||||||
if (block_p) {\
|
if (block_p) {\
|
||||||
|
@ -1340,20 +1366,41 @@ pack_unpack(VALUE str, VALUE fmt)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
star = 0;
|
|
||||||
if (*p == '_' || *p == '!') {
|
|
||||||
static const char natstr[] = "sSiIlL";
|
|
||||||
|
|
||||||
if (strchr(natstr, type)) {
|
star = 0;
|
||||||
|
{
|
||||||
|
static const char natstr[] = "sSiIlL";
|
||||||
|
static const char endstr[] = "sSiIlLqQ";
|
||||||
|
|
||||||
|
modifiers:
|
||||||
|
switch (*p) {
|
||||||
|
case '_':
|
||||||
|
case '!':
|
||||||
|
|
||||||
|
if (strchr(natstr, type)) {
|
||||||
#ifdef NATINT_PACK
|
#ifdef NATINT_PACK
|
||||||
natint = 1;
|
natint = 1;
|
||||||
#endif
|
#endif
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
|
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
|
||||||
|
}
|
||||||
|
goto modifiers;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
if (!strchr(endstr, type)) {
|
||||||
|
rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
|
||||||
|
}
|
||||||
|
if (explicit_endian) {
|
||||||
|
rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
|
||||||
|
}
|
||||||
|
explicit_endian = *p++;
|
||||||
|
goto modifiers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p >= pend)
|
if (p >= pend)
|
||||||
len = 1;
|
len = 1;
|
||||||
else if (*p == '*') {
|
else if (*p == '*') {
|
||||||
|
@ -1586,6 +1633,10 @@ pack_unpack(VALUE str, VALUE fmt)
|
||||||
goto unpack_integer;
|
goto unpack_integer;
|
||||||
|
|
||||||
unpack_integer:
|
unpack_integer:
|
||||||
|
if (explicit_endian) {
|
||||||
|
bigendian_p = ((explicit_endian - '<') != 0);
|
||||||
|
}
|
||||||
|
|
||||||
switch (integer_size) {
|
switch (integer_size) {
|
||||||
#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
|
#if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
|
||||||
case SIZEOF_INT16_T:
|
case SIZEOF_INT16_T:
|
||||||
|
|
|
@ -70,75 +70,88 @@ class TestPack < Test::Unit::TestCase
|
||||||
assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*')
|
assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _integer_big_endian(mod='')
|
||||||
|
assert_equal("\x01\x02", [0x0102].pack("s"+mod))
|
||||||
|
assert_equal("\x01\x02", [0x0102].pack("S"+mod))
|
||||||
|
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l"+mod))
|
||||||
|
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"+mod))
|
||||||
|
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"+mod))
|
||||||
|
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"+mod))
|
||||||
|
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"+mod))
|
||||||
|
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
|
||||||
|
fmt += mod
|
||||||
|
nuls = [0].pack(fmt)
|
||||||
|
v = 0
|
||||||
|
s = "".force_encoding("ascii-8bit")
|
||||||
|
nuls.bytesize.times {|i|
|
||||||
|
j = i + 40
|
||||||
|
v = v * 256 + j
|
||||||
|
s << [j].pack("C")
|
||||||
|
}
|
||||||
|
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
|
||||||
|
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
|
||||||
|
s2 = s+s
|
||||||
|
fmt2 = fmt+"*"
|
||||||
|
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def _integer_little_endian(mod='')
|
||||||
|
assert_equal("\x02\x01", [0x0102].pack("s"+mod))
|
||||||
|
assert_equal("\x02\x01", [0x0102].pack("S"+mod))
|
||||||
|
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l"+mod))
|
||||||
|
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"+mod))
|
||||||
|
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"+mod))
|
||||||
|
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"+mod))
|
||||||
|
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"+mod))
|
||||||
|
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"+mod))
|
||||||
|
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"+mod))
|
||||||
|
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
|
||||||
|
fmt += mod
|
||||||
|
nuls = [0].pack(fmt)
|
||||||
|
v = 0
|
||||||
|
s = "".force_encoding("ascii-8bit")
|
||||||
|
nuls.bytesize.times {|i|
|
||||||
|
j = i+40
|
||||||
|
v = v * 256 + j
|
||||||
|
s << [j].pack("C")
|
||||||
|
}
|
||||||
|
s.reverse!
|
||||||
|
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
|
||||||
|
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
|
||||||
|
s2 = s+s
|
||||||
|
fmt2 = fmt+"*"
|
||||||
|
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def test_integer_endian
|
def test_integer_endian
|
||||||
s = [1].pack("s")
|
s = [1].pack("s")
|
||||||
assert_includes(["\0\1", "\1\0"], s)
|
assert_includes(["\0\1", "\1\0"], s)
|
||||||
if s == "\0\1"
|
if s == "\0\1"
|
||||||
# big endian
|
_integer_big_endian()
|
||||||
assert_equal("\x01\x02", [0x0102].pack("s"))
|
|
||||||
assert_equal("\x01\x02", [0x0102].pack("S"))
|
|
||||||
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l"))
|
|
||||||
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"))
|
|
||||||
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"))
|
|
||||||
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"))
|
|
||||||
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"))
|
|
||||||
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
|
|
||||||
nuls = [0].pack(fmt)
|
|
||||||
v = 0
|
|
||||||
s = "".force_encoding("ascii-8bit")
|
|
||||||
nuls.bytesize.times {|i|
|
|
||||||
j = i + 40
|
|
||||||
v = v * 256 + j
|
|
||||||
s << [j].pack("C")
|
|
||||||
}
|
|
||||||
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
|
|
||||||
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
|
|
||||||
s2 = s+s
|
|
||||||
fmt2 = fmt+"*"
|
|
||||||
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
# little endian
|
_integer_little_endian()
|
||||||
assert_equal("\x02\x01", [0x0102].pack("s"))
|
|
||||||
assert_equal("\x02\x01", [0x0102].pack("S"))
|
|
||||||
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l"))
|
|
||||||
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"))
|
|
||||||
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"))
|
|
||||||
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"))
|
|
||||||
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"))
|
|
||||||
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"))
|
|
||||||
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"))
|
|
||||||
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
|
|
||||||
nuls = [0].pack(fmt)
|
|
||||||
v = 0
|
|
||||||
s = "".force_encoding("ascii-8bit")
|
|
||||||
nuls.bytesize.times {|i|
|
|
||||||
j = i+40
|
|
||||||
v = v * 256 + j
|
|
||||||
s << [j].pack("C")
|
|
||||||
}
|
|
||||||
s.reverse!
|
|
||||||
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
|
|
||||||
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
|
|
||||||
s2 = s+s
|
|
||||||
fmt2 = fmt+"*"
|
|
||||||
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_integer_endian_explicit
|
||||||
|
_integer_big_endian('>')
|
||||||
|
_integer_little_endian('<')
|
||||||
|
end
|
||||||
|
|
||||||
def test_pack_U
|
def test_pack_U
|
||||||
assert_raise(RangeError) { [-0x40000001].pack("U") }
|
assert_raise(RangeError) { [-0x40000001].pack("U") }
|
||||||
assert_raise(RangeError) { [-0x40000000].pack("U") }
|
assert_raise(RangeError) { [-0x40000000].pack("U") }
|
||||||
|
|
Loading…
Reference in New Issue