pack.c: support `w' directive (BER integer compression).

parent 1ed01a8d
......@@ -30,6 +30,7 @@ enum pack_dir {
PACK_DIR_QUAD, /* Q */
//PACK_DIR_INT, /* i */
//PACK_DIR_VAX,
PACK_DIR_BER, /* w */
PACK_DIR_UTF8, /* U */
//PACK_DIR_BER,
PACK_DIR_DOUBLE, /* E */
......@@ -378,6 +379,46 @@ unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un
return 8;
}
static int
pack_w(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
{
mrb_int n = mrb_integer(o);
mrb_int i;
char *p;
if (n < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "can't compress negative numbers");
}
for (i=1; i<sizeof(mrb_int)+1; i++) {
mrb_int mask = ~((1L<<(7*i))-1);
if ((n & mask) == 0) break;
}
str = str_len_ensure(mrb, str, sidx + i);
p = RSTRING_PTR(str);
for (mrb_int j=i; j>0; p++,j--) {
mrb_int x = (n>>(7*(j-1)))&0x7f;
*p = (char)x;
if (j > 1) *p |= 0x80;
}
return i;
}
static int
unpack_w(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
{
mrb_int i, n = 0;
const unsigned char *p = src;
const unsigned char *e = p + srclen;
for (i=1; p<e; p++,i++) {
n <<= 7;
n |= *p & 0x7f;
if ((*p & 0x80) == 0) break;
}
mrb_ary_push(mrb, ary, mrb_int_value(mrb, n));
return i;
}
#ifndef MRB_NO_FLOAT
static int
pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
......@@ -788,7 +829,6 @@ unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, un
return (int)(sptr - sptr0);
}
static int
pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count)
{
......@@ -1151,6 +1191,11 @@ alias:
size = 4;
flags |= PACK_FLAG_SIGNED;
break;
case 'w':
dir = PACK_DIR_BER;
type = PACK_TYPE_INTEGER;
flags |= PACK_FLAG_SIGNED;
break;
case 'm':
dir = PACK_DIR_BASE64;
type = PACK_TYPE_STRING;
......@@ -1228,7 +1273,7 @@ alias:
type = PACK_TYPE_STRING;
flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z;
break;
case 'p': case 'P': case 'w':
case 'p': case 'P':
case '%':
mrb_raisef(mrb, E_ARGUMENT_ERROR, "%c is not supported", (char)t);
break;
......@@ -1364,6 +1409,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
case PACK_DIR_QUAD:
ridx += pack_q(mrb, o, result, ridx, flags);
break;
case PACK_DIR_BER:
ridx += pack_w(mrb, o, result, ridx, flags);
break;
case PACK_DIR_BASE64:
ridx += pack_m(mrb, o, result, ridx, count);
break;
......@@ -1492,6 +1540,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
case PACK_DIR_QUAD:
srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags);
break;
case PACK_DIR_BER:
srcidx += unpack_w(mrb, sptr, srclen - srcidx, result, flags);
break;
#ifndef MRB_NO_FLOAT
case PACK_DIR_FLOAT:
srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags);
......
......@@ -124,6 +124,12 @@ assert 'pack/unpack "I"' do
assert_pack 'I', str, [12345]
end
assert 'pack/unpack "w"' do
for x in [0,1,127,128,16383,16384,65535,65536]
assert_equal [x], [x].pack("w").unpack("w")
end
end
assert 'pack/unpack "U"' do
assert_equal [], "".unpack("U")
assert_equal [], "".unpack("U*")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment