pack.c: support `w' directive (BER integer compression).
MODIFY
mrbgems/mruby-pack/src/pack.c
mrbgems/mruby-pack/src/pack.c
@@ -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);

MODIFY
mrbgems/mruby-pack/test/pack.rb
mrbgems/mruby-pack/test/pack.rb
@@ -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*")

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