summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTomoyuki Sahara <[email protected]>2015-08-07 11:48:45 +0900
committerTomoyuki Sahara <[email protected]>2015-08-07 11:48:45 +0900
commit359d2ae6fd60cff9593d145d4e7c881cf031fbd5 (patch)
tree0a2e7b4abb8e1bffbcdea9b924de26161d5f3ad4
parentd34db58797427ddc55ade11bcdcefbc614b20eba (diff)
downloadmruby-359d2ae6fd60cff9593d145d4e7c881cf031fbd5.tar.gz
mruby-359d2ae6fd60cff9593d145d4e7c881cf031fbd5.zip
support "q" and "Q". closes #7.
-rw-r--r--README.md2
-rw-r--r--packtest.rb8
-rw-r--r--src/pack.c89
3 files changed, 96 insertions, 3 deletions
diff --git a/README.md b/README.md
index d253f7e72..e82458f06 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,8 @@ rake ENABLE_GEMS="true"
- m : base64 encoded string (see RFC 2045, count is width)
- N : 32-bit unsigned, network (big-endian) byte order
- n : 16-bit unsigned, network (big-endian) byte order
+ - Q : 64-bit unsigned, native endian (`uint64_t`)
+ - q : 64-bit signed, native endian (`int64_t`)
- S : 16-bit unsigned, native endian (`uint16_t`)
- s : 16-bit signed, native endian (`int16_t`)
- V : 32-bit unsigned, VAX (little-endian) byte order
diff --git a/packtest.rb b/packtest.rb
index 003131236..feaed31f9 100644
--- a/packtest.rb
+++ b/packtest.rb
@@ -60,6 +60,14 @@ pptest [16909060], "\x01\x02\x03\x04", "L>"
packtest [-1], "\xff\xff\xff\xff", "L<"
+pptest [1000000000], "\x00\x00\x00\x00\x3b\x9a\xca\x00", "q>"
+pptest [-1000000000], "\xff\xff\xff\xff\xc4\x65\x36\x00", "q>"
+
+if (2**33).is_a? Fixnum
+ pptest [81985529216486895], "\x01\x23\x45\x67\x89\xab\xcd\xef", "q>"
+ pptest [-1167088121787636991], "\x01\x23\x45\x67\x89\xab\xcd\xef", "q<"
+end
+
pptest [16909060], "\x01\x02\x03\x04", "N"
pptest [258], "\x01\x02", "n"
pptest [32769], "\x80\x01", "n"
diff --git a/src/pack.c b/src/pack.c
index 276944e4b..3a750eb69 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -25,7 +25,7 @@ enum {
PACK_DIR_CHAR, /* C */
PACK_DIR_SHORT, /* S */
PACK_DIR_LONG, /* L */
- //PACK_DIR_QUAD, /* Q */
+ PACK_DIR_QUAD, /* Q */
//PACK_DIR_INT, /* i */
//PACK_DIR_VAX,
//PACK_DIR_UTF8, /* U */
@@ -232,6 +232,72 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un
}
static int
+pack_q(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+ unsigned long long n;
+ str = str_len_ensure(mrb, str, sidx + 8);
+ n = mrb_fixnum(o);
+ if (flags & PACK_FLAG_LITTLEENDIAN) {
+ RSTRING_PTR(str)[sidx+0] = n & 0xff;
+ RSTRING_PTR(str)[sidx+1] = n >> 8;
+ RSTRING_PTR(str)[sidx+2] = n >> 16;
+ RSTRING_PTR(str)[sidx+3] = n >> 24;
+ RSTRING_PTR(str)[sidx+4] = n >> 32;
+ RSTRING_PTR(str)[sidx+5] = n >> 40;
+ RSTRING_PTR(str)[sidx+6] = n >> 48;
+ RSTRING_PTR(str)[sidx+7] = n >> 56;
+ } else {
+ RSTRING_PTR(str)[sidx+0] = n >> 56;
+ RSTRING_PTR(str)[sidx+1] = n >> 48;
+ RSTRING_PTR(str)[sidx+2] = n >> 40;
+ RSTRING_PTR(str)[sidx+3] = n >> 32;
+ RSTRING_PTR(str)[sidx+4] = n >> 24;
+ RSTRING_PTR(str)[sidx+5] = n >> 16;
+ RSTRING_PTR(str)[sidx+6] = n >> 8;
+ RSTRING_PTR(str)[sidx+7] = n & 0xff;
+ }
+ return 8;
+}
+
+static int
+unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+ char msg[60];
+ uint64_t ull;
+ int i, pos, step;
+ mrb_int n;
+
+ if (flags & PACK_FLAG_LITTLEENDIAN) {
+ pos = 7;
+ step = -1;
+ } else {
+ pos = 0;
+ step = 1;
+ }
+ ull = 0;
+ for (i = 0; i < 8; i++) {
+ ull = ull * 256 + (uint64_t)src[pos];
+ pos += step;
+ }
+ if (flags & PACK_FLAG_SIGNED) {
+ int64_t sll = ull;
+ if (!FIXABLE(sll)) {
+ snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lld", (long long)sll);
+ mrb_raise(mrb, E_RANGE_ERROR, msg);
+ }
+ n = sll;
+ } else {
+ if (!POSFIXABLE(ull)) {
+ snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %llu", (unsigned long long)ull);
+ mrb_raise(mrb, E_RANGE_ERROR, msg);
+ }
+ n = ull;
+ }
+ mrb_ary_push(mrb, ary, mrb_fixnum_value(n));
+ return 8;
+}
+
+static int
pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
{
int i;
@@ -775,6 +841,17 @@ alias:
size = 2;
flags |= PACK_FLAG_GT;
break;
+ case 'Q':
+ dir = PACK_DIR_QUAD;
+ type = PACK_TYPE_INTEGER;
+ size = 8;
+ break;
+ case 'q':
+ dir = PACK_DIR_QUAD;
+ type = PACK_TYPE_INTEGER;
+ size = 8;
+ flags |= PACK_FLAG_SIGNED;
+ break;
case 'S':
dir = PACK_DIR_SHORT;
type = PACK_TYPE_INTEGER;
@@ -821,9 +898,9 @@ alias:
} else if (ch == '*') {
count = -1;
} else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
- if (strchr("sSiIlL", t) == NULL) {
+ if (strchr("sSiIlLqQ", t) == NULL) {
char ch_str = ch;
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlL", mrb_str_new(mrb, &ch_str, 1));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlLqQ", mrb_str_new(mrb, &ch_str, 1));
}
if (ch == '_' || ch == '!') {
flags |= PACK_FLAG_s;
@@ -901,6 +978,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
case PACK_DIR_LONG:
ridx += pack_l(mrb, o, result, ridx, flags);
break;
+ case PACK_DIR_QUAD:
+ ridx += pack_q(mrb, o, result, ridx, flags);
+ break;
case PACK_DIR_BASE64:
ridx += pack_m(mrb, o, result, ridx, count, flags);
break;
@@ -987,6 +1067,9 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str)
case PACK_DIR_LONG:
srcidx += unpack_l(mrb, sptr, srclen - srcidx, result, flags);
break;
+ case PACK_DIR_QUAD:
+ srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags);
+ break;
case PACK_DIR_BASE64:
srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags);
break;