From e205905d022b661a1dd279f8a8e6ecac19d1e979 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Mon, 31 Dec 2012 11:31:51 +0900 Subject: mruby-pack --- .gitignore | 4 + Makefile | 12 + src/pack.c | 794 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/pack.rb | 85 +++++++ 4 files changed, 895 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/pack.c create mode 100644 test/pack.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f28a84016 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +gem_* +gem-* +mrb-*.a +src/*.o diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..4539ba01a --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +GEM := mruby-pack + +include $(MAKEFILE_4_GEM) + +GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) +GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) + +gem-all : $(GEM_OBJECTS) gem-c-files + +gem-clean : gem-clean-c-files + +gem-test : gem-test-c-files diff --git a/src/pack.c b/src/pack.c new file mode 100644 index 000000000..c38a2c06c --- /dev/null +++ b/src/pack.c @@ -0,0 +1,794 @@ +/* + ** pack.c - Array#pack, String#unpack + ** + ** See Copyright Notice in mruby.h + */ + +#include "mruby.h" +#include "error.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "mruby/variable.h" + +#include +#include +#include +#include +#include + +struct tmpl { + mrb_value str; + int idx; +}; + +enum { + PACK_DIR_CHAR, /* C */ + PACK_DIR_SHORT, /* S */ + PACK_DIR_LONG, /* L */ + //PACK_DIR_QUAD, /* Q */ + //PACK_DIR_INT, /* i */ + //PACK_DIR_VAX, + //PACK_DIR_UTF8, /* U */ + //PACK_DIR_BER, + //PACK_DIR_DOUBLE, /* d */ + //PACK_DIR_FLOAT, /* f */ + PACK_DIR_STR, /* A */ + PACK_DIR_HEX, /* h */ + PACK_DIR_BASE64, /* m */ + PACK_DIR_INVALID +}; + +enum { + PACK_TYPE_INTEGER, + PACK_TYPE_FLOAT, + PACK_TYPE_STRING, + PACK_TYPE_NONE +}; + +#define PACK_FLAG_s 0x00000001 /* native size ("_" "!") */ +#define PACK_FLAG_a 0x00000002 /* null padding ("a") */ +#define PACK_FLAG_Z 0x00000004 /* append nul char ("z") */ +#define PACK_FLAG_SIGNED 0x00000008 /* native size ("_" "!") */ +#define PACK_FLAG_GT 0x00000010 /* big endian (">") */ +#define PACK_FLAG_LT 0x00000020 /* little endian ("<") */ +#define PACK_FLAG_WIDTH 0x00000040 /* */ +#define PACK_FLAG_LSB 0x00000080 /* LSB / low nibble first */ +#define PACK_FLAG_COUNT2 0x00000100 /* "count" is special... */ +#define PACK_FLAG_LITTLEENDIAN 0x00000200 /* little endian actually */ + +#define PACK_BASE64_IGNORE 0xff +#define PACK_BASE64_PADDING 0xfe + +static int littleendian = 0; + +const static unsigned char base64chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static signed char base64_dec_tab[128]; + + +static int +check_little_endian(void) +{ + unsigned int n = 1; + return (*(unsigned char *)&n == 1); +} + +static unsigned int +hex2int(unsigned char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return 10 + (ch - 'A'); + else if (ch >= 'a' && ch <= 'f') + return 10 + (ch - 'a'); + else + return 0; +} + +static void +make_base64_dec_tab(void) +{ + int i; + memset(base64_dec_tab, PACK_BASE64_IGNORE, sizeof(base64_dec_tab)); + for (i = 0; i < 26; i++) + base64_dec_tab['A' + i] = i; + for (i = 0; i < 26; i++) + base64_dec_tab['a' + i] = i + 26; + for (i = 0; i < 10; i++) + base64_dec_tab['0' + i] = i + 52; + base64_dec_tab['+'] = 62; + base64_dec_tab['/'] = 63; + base64_dec_tab['='] = PACK_BASE64_PADDING; +} + +static mrb_value +str_len_ensure(mrb_state *mrb, mrb_value str, int len) +{ + int n = RSTRING_LEN(str); + if (len > n) { + do { + n *= 2; + } while (len > n); + str = mrb_str_resize(mrb, str, n); + } + return str; +} + + +static int +pack_c(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + str = str_len_ensure(mrb, str, sidx + 1); + RSTRING_PTR(str)[sidx] = mrb_fixnum(o); + return 1; +} + +static int +unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned int flags) +{ + if (flags & PACK_FLAG_SIGNED) + mrb_ary_push(mrb, ary, mrb_fixnum_value(*(signed char *)src)); + else + mrb_ary_push(mrb, ary, mrb_fixnum_value(*(unsigned char *)src)); + return 1; +} + +static int +pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + short n; + str = str_len_ensure(mrb, str, sidx + 2); + n = mrb_fixnum(o); + if (flags & PACK_FLAG_LITTLEENDIAN) { + RSTRING_PTR(str)[sidx+0] = n % 256; + RSTRING_PTR(str)[sidx+1] = n / 256; + } else { + RSTRING_PTR(str)[sidx+0] = n / 256; + RSTRING_PTR(str)[sidx+1] = n % 256; + } + return 2; +} + +static int +unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) +{ + int n; + + if (flags & PACK_FLAG_LITTLEENDIAN) { + n = src[1] * 256 + src[0]; + } else { + n = src[0] * 256 + src[1]; + } + if ((flags & PACK_FLAG_SIGNED) && (n >= 0x8000)) { + n -= 0x10000; + } + mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); + return 2; +} + +static int +pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + long n; + str = str_len_ensure(mrb, str, sidx + 4); + 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; + } else { + RSTRING_PTR(str)[sidx+0] = n >> 24; + RSTRING_PTR(str)[sidx+1] = n >> 16; + RSTRING_PTR(str)[sidx+2] = n >> 8; + RSTRING_PTR(str)[sidx+3] = n & 0xff; + } + return 4; +} + +static int +unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) +{ + long n; + + if (flags & PACK_FLAG_LITTLEENDIAN) { + n = (src[3] << 24) + (src[2] << 16) + (src[1] << 8) + src[0]; + } else { + n = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; + } + if (flags & PACK_FLAG_SIGNED) { + if (sizeof(long) > sizeof(int)) + n = 0L - n; + if (!FIXABLE(n)) + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", n); + } else { + if (!POSFIXABLE(n)) + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %ld", n); + } + mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); + return 4; +} + +static int +pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + int copylen, dlen, slen, padlen; + char *dptr, *dptr0, pad, *sptr; + + sptr = RSTRING_PTR(src); + slen = RSTRING_LEN(src); + + if ((flags & PACK_FLAG_a) || (flags & PACK_FLAG_Z)) + pad = '\0'; + else + pad = ' '; + + if (count == -1) { + copylen = slen; + padlen = (flags & PACK_FLAG_Z) ? 1 : 0; + } else if (count < slen) { + copylen = count; + padlen = 0; + } else { + copylen = slen; + padlen = count - slen; + } + + dst = str_len_ensure(mrb, dst, didx + copylen + padlen); + dptr0 = dptr = RSTRING_PTR(dst) + didx; + memcpy(dptr, sptr, copylen); + dptr += copylen; + while (padlen-- > 0) { + *dptr++ = pad; + } + + return dptr - dptr0; +} + +static int +unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags) +{ + mrb_value dst; + const char *sptr, *sptr0; + char *dptr, *dptr0; + + sptr = src; + + if (count == -1 || count > slen) + count = slen; + + dst = mrb_str_new(mrb, NULL, count); + dptr0 = dptr = RSTRING_PTR(dst); + + memcpy(dptr, sptr, count); + if (flags & PACK_FLAG_Z) { + if (count > 0 && dptr[count - 1] == '\0') + count--; + } else if (!(flags & PACK_FLAG_a)) { + while (count > 0 && (dptr[count - 1] == '\0' || isspace(dptr[count - 1]))) + count--; + } + + dst = mrb_str_resize(mrb, dst, count); + mrb_ary_push(mrb, ary, dst); + return count; +} + + +static int +pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + unsigned int a, ashift, b, bshift, x; + int slen; + char *dptr, *dptr0, *sptr; + + sptr = RSTRING_PTR(src); + slen = RSTRING_LEN(src); + + if (flags & PACK_FLAG_LSB) { + ashift = 0; + bshift = 4; + } else { + ashift = 4; + bshift = 0; + } + + if (count == -1) { + count = slen; + } else if (slen > count) { + slen = count; + } + + dst = str_len_ensure(mrb, dst, didx + count); + dptr = RSTRING_PTR(dst) + didx; + + dptr0 = dptr; + for (; count > 0; count -= 2) { + a = b = 0; + if (slen > 0) { + a = hex2int(*sptr++); + slen--; + } + if (slen > 0) { + b = hex2int(*sptr++); + slen--; + } + *dptr++ = (a << ashift) + (b << bshift); + } + + return dptr - dptr0; +} + +static int +unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags) +{ + mrb_value dst; + unsigned long l; + int a, ashift, b, bshift, i, padding; + unsigned char c, ch[4]; + const char *sptr, *sptr0; + char *dptr, *dptr0; + const char hexadecimal[] = "0123456789abcdef"; + + if (flags & PACK_FLAG_LSB) { + ashift = 0; + bshift = 4; + } else { + ashift = 4; + bshift = 0; + } + + sptr = src; + + if (count == -1) + count = slen * 2; + + dst = mrb_str_new(mrb, NULL, count); + dptr = RSTRING_PTR(dst); + + sptr0 = sptr; + dptr0 = dptr; + padding = 0; + while (slen > 0 && count > 0) { + a = (*sptr >> ashift) & 0x0f; + b = (*sptr >> bshift) & 0x0f; + sptr++; + slen--; + + *dptr++ = hexadecimal[a]; + count--; + + if (count > 0) { + *dptr++ = hexadecimal[b]; + count--; + } + } + + dst = mrb_str_resize(mrb, dst, dptr - dptr0); + mrb_ary_push(mrb, ary, dst); + return sptr - sptr0; +} + + +static int +pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + mrb_int dstlen; + unsigned long l; + int column, srclen; + char *srcptr, *dstptr, *dstptr0; + + srcptr = RSTRING_PTR(src); + srclen = RSTRING_LEN(src); + + if (srclen == 0) /* easy case */ + return 0; + + if (count != 0 && count < 3) { /* -1, 1 or 2 */ + count = 45; + } else if (count >= 3) { + count -= count % 3; + } + + dstlen = srclen / 3 * 4; + if (count > 0) { + dstlen += (srclen / count) + ((srclen % count) == 0 ? 0 : 1); + } + dst = str_len_ensure(mrb, dst, didx + dstlen); + dstptr = RSTRING_PTR(dst) + didx; + + dstptr0 = dstptr; + for (column = 3; srclen >= 3; srclen -= 3, column += 3) { + l = (unsigned char)*srcptr++ << 16; + l += (unsigned char)*srcptr++ << 8; + l += (unsigned char)*srcptr++; + + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = base64chars[(l >> 6) & 0x3f]; + *dstptr++ = base64chars[ l & 0x3f]; + + if (column == count) { + *dstptr++ = '\n'; + column = 0; + } + } + if (srclen == 1) { + l = (unsigned char)*srcptr++ << 16; + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = '='; + *dstptr++ = '='; + column += 3; + } else if (srclen == 2) { + l = (unsigned char)*srcptr++ << 16; + l += (unsigned char)*srcptr++ << 8; + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = base64chars[(l >> 6) & 0x3f]; + *dstptr++ = '='; + column += 3; + } + if (column > 0 && count > 0) { + *dstptr++ = '\n'; + } + + return dstptr - dstptr0; +} + +static int +unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int flags) +{ + mrb_value dst; + int dlen; + unsigned long l; + int i, padding; + unsigned char c, ch[4]; + const char *sptr, *sptr0; + char *dptr, *dptr0; + + sptr0 = sptr = src; + + dlen = slen / 4 * 3; /* an estimated value - may be shorter */ + dst = mrb_str_new(mrb, NULL, dlen); + dptr0 = dptr = RSTRING_PTR(dst); + + padding = 0; + while (slen >= 4) { + for (i = 0; i < 4; i++) { + do { + if (slen-- == 0) + goto done; + c = *sptr++; + if (c >= sizeof(base64_dec_tab)) + continue; + ch[i] = base64_dec_tab[c]; + if (ch[i] == PACK_BASE64_PADDING) { + ch[i] = 0; + padding++; + } + } while (ch[i] == PACK_BASE64_IGNORE); + } + + l = (ch[0] << 18) + (ch[1] << 12) + (ch[2] << 6) + ch[3]; + + if (padding == 0) { + *dptr++ = (l >> 16) & 0xff; + *dptr++ = (l >> 8) & 0xff; + *dptr++ = l & 0xff; + } else if (padding == 1) { + *dptr++ = (l >> 16) & 0xff; + *dptr++ = (l >> 8) & 0xff; + break; + } else { + *dptr++ = (l >> 16) & 0xff; + break; + } + } + +done: + dst = mrb_str_resize(mrb, dst, dptr - dptr0); + mrb_ary_push(mrb, ary, dst); + return sptr - sptr0; +} + + +static void +prepare_tmpl(mrb_state *mrb, struct tmpl *tmpl) +{ + mrb_get_args(mrb, "S", &tmpl->str); + tmpl->idx = 0; +} + +static int +has_tmpl(const struct tmpl *tmpl) +{ + return (tmpl->idx < RSTRING_LEN(tmpl->str)); +} + +static void +read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, long *countp, unsigned int *flagsp) +{ + int ch, dir, t, tlen, type; + int size = 0; + long count = 1; + unsigned int flags = 0; + const char *tptr; + + tptr = RSTRING_PTR(tmpl->str); + tlen = RSTRING_LEN(tmpl->str); + + t = tptr[tmpl->idx++]; + switch (t) { + case 'A': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2; + break; + case 'a': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_a; + break; + case 'C': + dir = PACK_DIR_CHAR; + type = PACK_TYPE_INTEGER; + size = 1; + break; + case 'c': + dir = PACK_DIR_CHAR; + type = PACK_TYPE_INTEGER; + size = 1; + flags |= PACK_FLAG_SIGNED; + break; + case 'H': + dir = PACK_DIR_HEX; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_COUNT2; + break; + case 'h': + dir = PACK_DIR_HEX; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB; + break; + case 'L': + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + break; + case 'l': + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_SIGNED; + break; + case 'N': /* = "L>" */ + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_GT; + break; + case 'n': /* = "S>" */ + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_GT; + break; + case 'S': + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + break; + case 's': + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_SIGNED; + break; + case 'm': + dir = PACK_DIR_BASE64; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH; + break; + case 'Z': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z; + break; + default: + dir = PACK_DIR_INVALID; + break; + } + + /* read suffix [0-9*_!<>] */ + while (tmpl->idx < tlen) { + ch = tptr[tmpl->idx++]; + if (isdigit(ch)) { + count = ch - '0'; + while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { + count = count * 10 + (tptr[tmpl->idx++] - '0'); + } + continue; /* special case */ + } else if (ch == '*') { + count = -1; + } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') { + if (strchr("sSiIlL", t) == NULL) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlL", ch); + } + if (ch == '_' || ch == '!') { + flags |= PACK_FLAG_s; + } else if (ch == '<') { + flags |= PACK_FLAG_LT; + } else if (ch == '>') { + flags |= PACK_FLAG_GT; + } + } else { + tmpl->idx--; + break; + } + } + + if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) { + flags |= PACK_FLAG_LITTLEENDIAN; + } + + *dirp = dir; + *typep = type; + *sizep = size; + *countp = count; + *flagsp = flags; +} + +static mrb_value +mrb_pack_pack(mrb_state *mrb, mrb_value ary) +{ + mrb_value o, result; + mrb_int aidx; + struct tmpl tmpl; + long count; + unsigned int flags; + int dir, ridx, size, type; + + prepare_tmpl(mrb, &tmpl); + + result = mrb_str_new(mrb, NULL, 128); /* allocate initial buffer */ + ridx = 0; + while (has_tmpl(&tmpl)) { + read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags); + + if (dir == PACK_DIR_INVALID) + continue; + + for (aidx = 0; aidx < RARRAY_LEN(ary); aidx++) { + if (count == 0 && !(flags & PACK_FLAG_WIDTH)) + break; + + o = mrb_ary_ref(mrb, ary, aidx); + if (type == PACK_TYPE_INTEGER) { + if (mrb_float_p(o)) { + o = mrb_funcall(mrb, o, "to_i", 0); + } else if (!mrb_fixnum_p(o)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into Integer", mrb_obj_classname(mrb, o)); + } + } else if (type == PACK_TYPE_STRING) { + if (!mrb_string_p(o)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, o)); + } + } + + switch (dir) { + case PACK_DIR_CHAR: + ridx += pack_c(mrb, o, result, ridx, flags); + break; + case PACK_DIR_SHORT: + ridx += pack_s(mrb, o, result, ridx, flags); + break; + case PACK_DIR_LONG: + ridx += pack_l(mrb, o, result, ridx, flags); + break; + case PACK_DIR_BASE64: + ridx += pack_m(mrb, o, result, ridx, count, flags); + break; + case PACK_DIR_HEX: + ridx += pack_h(mrb, o, result, ridx, count, flags); + break; + case PACK_DIR_STR: + ridx += pack_a(mrb, o, result, ridx, count, flags); + break; + default: + break; + } + if (count > 0) { + count--; + } + } + } + + mrb_str_resize(mrb, result, ridx); + return result; +} + +static mrb_value +mrb_pack_unpack(mrb_state *mrb, mrb_value str) +{ + mrb_value result; + struct tmpl tmpl; + long count; + unsigned int flags; + int dir, sidx, size, srclen, type; + const char *sptr; + + prepare_tmpl(mrb, &tmpl); + + sidx = 0; + srclen = RSTRING_LEN(str); + + result = mrb_ary_new(mrb); + while (has_tmpl(&tmpl)) { + read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags); + + if (dir == PACK_DIR_INVALID) + continue; + + if (flags & PACK_FLAG_COUNT2) { + sptr = RSTRING_PTR(str) + sidx; + switch (dir) { + case PACK_DIR_HEX: + sidx += unpack_h(mrb, sptr, srclen - sidx, result, count, flags); + break; + case PACK_DIR_STR: + sidx += unpack_a(mrb, sptr, srclen - sidx, result, count, flags); + break; + } + continue; + } + + while (count != 0) { + if (srclen - sidx < size) { + while (count-- > 0) { + mrb_ary_push(mrb, result, mrb_nil_value()); + } + break; + } + + sptr = RSTRING_PTR(str) + sidx; + switch (dir) { + case PACK_DIR_CHAR: + sidx += unpack_c(mrb, sptr, srclen - sidx, result, flags); + break; + case PACK_DIR_SHORT: + sidx += unpack_s(mrb, sptr, srclen - sidx, result, flags); + break; + case PACK_DIR_LONG: + sidx += unpack_l(mrb, sptr, srclen - sidx, result, flags); + break; + case PACK_DIR_BASE64: + sidx += unpack_m(mrb, sptr, srclen - sidx, result, flags); + break; + } + if (count > 0) { + count--; + } + } + } + + return result; +} + +void +mrb_mruby_pack_gem_init(mrb_state *mrb) +{ + struct RClass *cArray, *cString; + + littleendian = check_little_endian(); + make_base64_dec_tab(); + + cArray = mrb->array_class; + cString = mrb->string_class; + + mrb_define_method(mrb, cArray, "pack", mrb_pack_pack, ARGS_REQ(1)); + mrb_define_method(mrb, cString, "unpack", mrb_pack_unpack, ARGS_REQ(1)); +} diff --git a/test/pack.rb b/test/pack.rb new file mode 100644 index 000000000..7339bbdee --- /dev/null +++ b/test/pack.rb @@ -0,0 +1,85 @@ +# pack & unpack 'm' (base64) +assert('[""].pack("m")') do + ary = "" + str = "" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0"].pack("m")') do + ary = "\0" + str = "AA==\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0\0"].pack("m")') do + ary = "\0\0" + str = "AAA=\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0\0\0"].pack("m")') do + ary = "\0\0\0" + str = "AAAA\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["abc..xyzABC..XYZ"].pack("m")') do + ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m") == "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n" +end + +assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do + str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") == [str] and + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") == [str] +end + +# pack & unpack 'H' +assert('["3031"].pack("H*")') do + ary = "3031" + str = "01" + [ary].pack("H*") == str and + str.unpack("H*") == [ary] +end + +assert('["10"].pack("H*")') do + ary = "10" + str = "\020" + [ary].pack("H*") == str and + str.unpack("H*") == [ary] +end + +assert('[0,1,127,128,255].pack("C*")') do + ary = [ 0, 1, 127, 128, 255 ] + str = "\x00\x01\x7F\x80\xFF" + ary.pack("C*") == str and str.unpack("C*") == ary +end + +# pack "a" +assert('["abc"].pack("a")') do + ["abc"].pack("a") == "a" and + ["abc"].pack("a*") == "abc" and + ["abc"].pack("a4") == "abc\0" +end + +# upack "a" +assert('["abc"].pack("a")') do + "abc\0".unpack("a4") == ["abc\0"] and + "abc ".unpack("a4") == ["abc "] +end + +# pack "A" +assert('["abc"].pack("A")') do + ["abc"].pack("A") == "a" and + ["abc"].pack("A*") == "abc" and + ["abc"].pack("A4") == "abc " +end + +# upack "A" +assert('["abc"].pack("A")') do + "abc\0".unpack("A4") == ["abc"] and + "abc ".unpack("A4") == ["abc"] +end -- cgit v1.2.3 From fb79282a5b62449e7a53025fd8503380a2024357 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Mon, 31 Dec 2012 13:15:30 +0900 Subject: add README.md --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..fff53d4b9 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +mruby-pack (pack / unpack) +========= + +## install by mrbgems +```bash +git clone git://github.com/iij/mruby-pack.git +cp -pr mruby-pack ${MRUBY_ROOT}/mrbgems/g/. +echo mruby-pack >> ${MRUBY_ROOT}/mrbgems/GEMS.active +cd ${MRUBY_ROOT} +rake ENABLE_GEMS="true" +./bin/mruby ${MRUBY_ROOT}/mrbgems/g/mruby-pack/example/sample.rb +``` + +## support template string + - C : 8-bit unsigned (unsigned char) + - c : 8-bit signed (signed char) + - S : 16-bit unsigned, native endian (uint16_t) + - s : 16-bit signed, native endian (int16_t) + - L : 32-bit unsigned, native endian (uint32_t) + - l : 32-bit signed, native endian (int32_t) + - n : 16-bit unsigned, network (big-endian) byte order + - N : 32-bit unsigned, network (big-endian) byte order + - A : arbitrary binary string (space padded, count is width) + - a : arbitrary binary string (null padded, count is width) + - Z : same as "a", except that null is added with * + - H : hex string (high nibble first) + - h : hex string (low nibble first) + - m : base64 encoded string (see RFC 2045, count is width) + +## License +This software is licensed under the same license terms of the original mruby. + -- cgit v1.2.3 From 209ad3171dcf7f3f6c8ecc8566ed0011d0af1c48 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Jan 2013 00:04:02 +0900 Subject: add mrbgem.rake --- mrbgem.rake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mrbgem.rake diff --git a/mrbgem.rake b/mrbgem.rake new file mode 100644 index 000000000..6f6da3e78 --- /dev/null +++ b/mrbgem.rake @@ -0,0 +1,17 @@ +MRuby::Gem::Specification.new('mruby-pack') do |spec| + spec.license = 'MIT' + spec.authors = 'mruby developers' + + # spec.cflags = '' + + # spec.mruby_cflags = '' + # spec.mruby_ldflags = '' + # spec.mruby_libs = '' + spec.mruby_includes = ["#{build.root}/src"] + + # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_preload = 'test/assert.rb' +end -- cgit v1.2.3 From e734ab3f95bff60d2b2095e0b76717f121bd23ba Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 09:00:40 +0900 Subject: add mrb_mruby_pack_gem_final --- src/pack.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pack.c b/src/pack.c index c38a2c06c..0913a9389 100644 --- a/src/pack.c +++ b/src/pack.c @@ -792,3 +792,8 @@ mrb_mruby_pack_gem_init(mrb_state *mrb) mrb_define_method(mrb, cArray, "pack", mrb_pack_pack, ARGS_REQ(1)); mrb_define_method(mrb, cString, "unpack", mrb_pack_unpack, ARGS_REQ(1)); } + +void +mrb_mruby_pack_gem_final(mrb_state *mrb) +{ +} -- cgit v1.2.3 From 558f6fc090f83614819513802ef6960739ad1e9b Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 09:00:55 +0900 Subject: update mrbgem.rake --- mrbgem.rake | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/mrbgem.rake b/mrbgem.rake index 6f6da3e78..8fef02a3c 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,17 +1,6 @@ MRuby::Gem::Specification.new('mruby-pack') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - - # spec.cflags = '' - - # spec.mruby_cflags = '' - # spec.mruby_ldflags = '' - # spec.mruby_libs = '' - spec.mruby_includes = ["#{build.root}/src"] - - # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } - # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") - # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } - # spec.test_preload = 'test/assert.rb' + + spec.cc.flags << "#{build.root}/src" end -- cgit v1.2.3 From f70a45ad3a8b3b937cfd033691ff3bb372e83b3d Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 10:09:15 +0900 Subject: update mrbgem.rake --- mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 8fef02a3c..2e2fac111 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -2,5 +2,5 @@ MRuby::Gem::Specification.new('mruby-pack') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - spec.cc.flags << "#{build.root}/src" + spec.cc.incude_paths << "#{build.root}/src" end -- cgit v1.2.3 From a0161d69a87a48c8335b28a05efe1230a0dcfa18 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 10:12:02 +0900 Subject: typo fix on mrbgem.rake --- mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 2e2fac111..4fac150d3 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -2,5 +2,5 @@ MRuby::Gem::Specification.new('mruby-pack') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - spec.cc.incude_paths << "#{build.root}/src" + spec.cc.include_paths << "#{build.root}/src" end -- cgit v1.2.3 From 0786e37ed6626e0c6cf98af247211c9888510ade Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 15:20:10 +0900 Subject: update mrbgem.rake --- mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 4fac150d3..2b9dea5b1 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,6 +1,6 @@ MRuby::Gem::Specification.new('mruby-pack') do |spec| spec.license = 'MIT' - spec.authors = 'mruby developers' + spec.authors = 'Internet Initiative Japan Inc.' spec.cc.include_paths << "#{build.root}/src" end -- cgit v1.2.3 From aadcbb1690f372f2a97f561e93e29c0e2d09dd54 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 15:20:41 +0900 Subject: add mrbgem test runner --- .gitignore | 1 + run_test.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 run_test.rb diff --git a/.gitignore b/.gitignore index f28a84016..55ef3162f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ gem_* gem-* mrb-*.a src/*.o +/tmp diff --git a/run_test.rb b/run_test.rb new file mode 100644 index 000000000..7be23b4d3 --- /dev/null +++ b/run_test.rb @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +DEPEND_GEMS = [] +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + if ARGV.first && ARGV.first.include?('iij') + repository, dir = 'https://github.com/iij/mruby.git', 'tmp/iij-mruby' + build_args = ARGV[1, ARGV.size] + end + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gems.clear + conf.gem File.expand_path(File.dirname(__FILE__)) + DEPEND_GEMS.each do |g| + conf.gem g + end +end -- cgit v1.2.3 From 53ff8bab179b65897d143f0a9c00d1cd7ce97a88 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 17:03:42 +0900 Subject: update README.md --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fff53d4b9..15d50cd77 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,26 @@ rake ENABLE_GEMS="true" - h : hex string (low nibble first) - m : base64 encoded string (see RFC 2045, count is width) + ## License -This software is licensed under the same license terms of the original mruby. + +Copyright (c) 2012 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. -- cgit v1.2.3 From a0c62dd4b8adccf27db46e73e4eca3a7fced6244 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 15 Feb 2013 10:39:04 +0900 Subject: fix an issue negative integer may not be packed/unpacked correctly. --- src/pack.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/pack.c b/src/pack.c index 0913a9389..290f3a3f8 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1,7 +1,5 @@ /* ** pack.c - Array#pack, String#unpack - ** - ** See Copyright Notice in mruby.h */ #include "mruby.h" @@ -139,7 +137,8 @@ unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned in static int pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) { - short n; + unsigned short n; + str = str_len_ensure(mrb, str, sidx + 2); n = mrb_fixnum(o); if (flags & PACK_FLAG_LITTLEENDIAN) { @@ -172,7 +171,7 @@ unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un static int pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) { - long n; + unsigned long n; str = str_len_ensure(mrb, str, sidx + 4); n = mrb_fixnum(o); if (flags & PACK_FLAG_LITTLEENDIAN) { @@ -192,7 +191,7 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { - long n; + unsigned long n; if (flags & PACK_FLAG_LITTLEENDIAN) { n = (src[3] << 24) + (src[2] << 16) + (src[1] << 8) + src[0]; @@ -200,13 +199,11 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un n = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; } if (flags & PACK_FLAG_SIGNED) { - if (sizeof(long) > sizeof(int)) - n = 0L - n; - if (!FIXABLE(n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", n); + if (!FIXABLE((mrb_int)n)) + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", (mrb_int)n); } else { if (!POSFIXABLE(n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %ld", n); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %lu", n); } mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); return 4; -- cgit v1.2.3 From 88fa5851f4967f1a1d1ec2bcb9be90adaaf3b82f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 15 Feb 2013 10:39:04 +0900 Subject: fix an issue large/negative integer may not be packed/unpacked correctly. --- src/pack.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/pack.c b/src/pack.c index 0913a9389..290f3a3f8 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1,7 +1,5 @@ /* ** pack.c - Array#pack, String#unpack - ** - ** See Copyright Notice in mruby.h */ #include "mruby.h" @@ -139,7 +137,8 @@ unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned in static int pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) { - short n; + unsigned short n; + str = str_len_ensure(mrb, str, sidx + 2); n = mrb_fixnum(o); if (flags & PACK_FLAG_LITTLEENDIAN) { @@ -172,7 +171,7 @@ unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un static int pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) { - long n; + unsigned long n; str = str_len_ensure(mrb, str, sidx + 4); n = mrb_fixnum(o); if (flags & PACK_FLAG_LITTLEENDIAN) { @@ -192,7 +191,7 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { - long n; + unsigned long n; if (flags & PACK_FLAG_LITTLEENDIAN) { n = (src[3] << 24) + (src[2] << 16) + (src[1] << 8) + src[0]; @@ -200,13 +199,11 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un n = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; } if (flags & PACK_FLAG_SIGNED) { - if (sizeof(long) > sizeof(int)) - n = 0L - n; - if (!FIXABLE(n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", n); + if (!FIXABLE((mrb_int)n)) + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", (mrb_int)n); } else { if (!POSFIXABLE(n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %ld", n); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %lu", n); } mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); return 4; -- cgit v1.2.3 From fc43022c95a871ab7d77546e7f2fff37413bb148 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 15 Feb 2013 10:52:37 +0900 Subject: support "V" and "v". --- src/pack.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/pack.c b/src/pack.c index 290f3a3f8..fc2248a1a 100644 --- a/src/pack.c +++ b/src/pack.c @@ -562,6 +562,11 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, size = 4; flags |= PACK_FLAG_SIGNED; break; + case 'm': + dir = PACK_DIR_BASE64; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH; + break; case 'N': /* = "L>" */ dir = PACK_DIR_LONG; type = PACK_TYPE_INTEGER; @@ -585,10 +590,17 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, size = 2; flags |= PACK_FLAG_SIGNED; break; - case 'm': - dir = PACK_DIR_BASE64; - type = PACK_TYPE_STRING; - flags |= PACK_FLAG_WIDTH; + case 'V': /* = "L<" */ + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_LT; + break; + case 'v': /* = "S<" */ + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_LT; break; case 'Z': dir = PACK_DIR_STR; -- cgit v1.2.3 From 858d67c1549a93eec4b36e5c94e22b21f55634b8 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 15 Feb 2013 10:54:36 +0900 Subject: add "v" and "V". --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 15d50cd77..ead796169 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ rake ENABLE_GEMS="true" - l : 32-bit signed, native endian (int32_t) - n : 16-bit unsigned, network (big-endian) byte order - N : 32-bit unsigned, network (big-endian) byte order + - v : 16-bit unsigned, VAX (little-endian) byte order + - V : 32-bit unsigned, VAX (little-endian) byte order - A : arbitrary binary string (space padded, count is width) - a : arbitrary binary string (null padded, count is width) - Z : same as "a", except that null is added with * -- cgit v1.2.3 From d5982b43c5935013bb8a3c163eb28ed303983c31 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 27 Apr 2013 09:47:05 +0900 Subject: put MRB_ prefix before ARGS_XXX macros --- src/pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pack.c b/src/pack.c index fc2248a1a..a2dc0bdd6 100644 --- a/src/pack.c +++ b/src/pack.c @@ -798,8 +798,8 @@ mrb_mruby_pack_gem_init(mrb_state *mrb) cArray = mrb->array_class; cString = mrb->string_class; - mrb_define_method(mrb, cArray, "pack", mrb_pack_pack, ARGS_REQ(1)); - mrb_define_method(mrb, cString, "unpack", mrb_pack_unpack, ARGS_REQ(1)); + mrb_define_method(mrb, cArray, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cString, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1)); } void -- cgit v1.2.3 From 8bfbca234f367d1475561ee847ccb9b2d832c4ae Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 2 May 2013 23:44:40 +0900 Subject: update run_test.rb --- run_test.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/run_test.rb b/run_test.rb index 7be23b4d3..d9566a2a6 100644 --- a/run_test.rb +++ b/run_test.rb @@ -3,16 +3,11 @@ # mrbgems test runner # -DEPEND_GEMS = [] gemname = File.basename(File.dirname(File.expand_path __FILE__)) if __FILE__ == $0 repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' build_args = ARGV - if ARGV.first && ARGV.first.include?('iij') - repository, dir = 'https://github.com/iij/mruby.git', 'tmp/iij-mruby' - build_args = ARGV[1, ARGV.size] - end build_args = ['all', 'test'] if build_args.nil? or build_args.empty? Dir.mkdir 'tmp' unless File.exist?('tmp') @@ -25,9 +20,7 @@ end MRuby::Build.new do |conf| toolchain :gcc - conf.gems.clear + conf.gembox 'default' + conf.gem File.expand_path(File.dirname(__FILE__)) - DEPEND_GEMS.each do |g| - conf.gem g - end end -- cgit v1.2.3 From 7618ca6bb300c7bc1599a6796105cd12c9d03cd7 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 2 May 2013 23:45:47 +0900 Subject: remove unused Makefile --- Makefile | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 4539ba01a..000000000 --- a/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -GEM := mruby-pack - -include $(MAKEFILE_4_GEM) - -GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) -GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) - -gem-all : $(GEM_OBJECTS) gem-c-files - -gem-clean : gem-clean-c-files - -gem-test : gem-test-c-files -- cgit v1.2.3 From 8c5cb5e782ac03f28ecaa3e2bf77b2062e6be279 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 8 May 2013 09:40:24 +0900 Subject: cannot pack objects other than the first one. closes #1. --- src/pack.c | 3 ++- test/pack.rb | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pack.c b/src/pack.c index a2dc0bdd6..659a0e424 100644 --- a/src/pack.c +++ b/src/pack.c @@ -664,6 +664,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) prepare_tmpl(mrb, &tmpl); result = mrb_str_new(mrb, NULL, 128); /* allocate initial buffer */ + aidx = 0; ridx = 0; while (has_tmpl(&tmpl)) { read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags); @@ -671,7 +672,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) if (dir == PACK_DIR_INVALID) continue; - for (aidx = 0; aidx < RARRAY_LEN(ary); aidx++) { + for (; aidx < RARRAY_LEN(ary); aidx++) { if (count == 0 && !(flags & PACK_FLAG_WIDTH)) break; diff --git a/test/pack.rb b/test/pack.rb index 7339bbdee..7789fb446 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -83,3 +83,8 @@ assert('["abc"].pack("A")') do "abc\0".unpack("A4") == ["abc"] and "abc ".unpack("A4") == ["abc"] end + +# regression tests +assert('issue #1') do + [1, 2].pack("nn") == "\000\001\000\002" +end -- cgit v1.2.3 From c869bdedc0ffcb7f6650ce2f519dceb9a41bae24 Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Tue, 7 May 2013 21:08:03 +0200 Subject: added support for E in pack (double) --- README.md | 1 + src/pack.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ead796169..0e11a61a5 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ rake ENABLE_GEMS="true" ## support template string - C : 8-bit unsigned (unsigned char) - c : 8-bit signed (signed char) + - E : 64-bit double, little endian - S : 16-bit unsigned, native endian (uint16_t) - s : 16-bit signed, native endian (int16_t) - L : 32-bit unsigned, native endian (uint32_t) diff --git a/src/pack.c b/src/pack.c index 659a0e424..4d26a1fe6 100644 --- a/src/pack.c +++ b/src/pack.c @@ -30,7 +30,7 @@ enum { //PACK_DIR_VAX, //PACK_DIR_UTF8, /* U */ //PACK_DIR_BER, - //PACK_DIR_DOUBLE, /* d */ + PACK_DIR_DOUBLE, /* E */ //PACK_DIR_FLOAT, /* f */ PACK_DIR_STR, /* A */ PACK_DIR_HEX, /* h */ @@ -188,6 +188,26 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl return 4; } +static int +pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + int i; + double d; + str = str_len_ensure(mrb, str, sidx + 8); + d = mrb_float(o); + uint8_t *buffer = (uint8_t *)&d; + +#ifdef MRB_ENDIAN_BIG + #error unsupported +#else + for(i = 0; i< 8; i++){ + RSTRING_PTR(str)[sidx+i] = buffer[i]; + } +#endif + + return 8; +} + static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { @@ -541,6 +561,12 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, size = 1; flags |= PACK_FLAG_SIGNED; break; + case 'E': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED; + break; case 'H': dir = PACK_DIR_HEX; type = PACK_TYPE_STRING; @@ -683,6 +709,10 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) } else if (!mrb_fixnum_p(o)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into Integer", mrb_obj_classname(mrb, o)); } + } else if (type == PACK_TYPE_FLOAT) { + if (!mrb_float_p(o)) { + o = mrb_funcall(mrb, o, "to_f", 0); + } } else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, o)); @@ -708,6 +738,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) case PACK_DIR_STR: ridx += pack_a(mrb, o, result, ridx, count, flags); break; + case PACK_DIR_DOUBLE: + ridx += pack_double(mrb, o, result, ridx, flags); + break; default: break; } -- cgit v1.2.3 From dce09fb7fd409eec1bada66c52c3a7f0a58e1e5f Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Tue, 7 May 2013 21:08:16 +0200 Subject: removed unused variables --- src/pack.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/pack.c b/src/pack.c index 4d26a1fe6..e28c0ca73 100644 --- a/src/pack.c +++ b/src/pack.c @@ -232,7 +232,7 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { - int copylen, dlen, slen, padlen; + int copylen, slen, padlen; char *dptr, *dptr0, pad, *sptr; sptr = RSTRING_PTR(src); @@ -269,7 +269,7 @@ static int unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags) { mrb_value dst; - const char *sptr, *sptr0; + const char *sptr; char *dptr, *dptr0; sptr = src; @@ -298,7 +298,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u static int pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { - unsigned int a, ashift, b, bshift, x; + unsigned int a, ashift, b, bshift; int slen; char *dptr, *dptr0, *sptr; @@ -343,9 +343,7 @@ static int unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags) { mrb_value dst; - unsigned long l; - int a, ashift, b, bshift, i, padding; - unsigned char c, ch[4]; + int a, ashift, b, bshift, padding; const char *sptr, *sptr0; char *dptr, *dptr0; const char hexadecimal[] = "0123456789abcdef"; -- cgit v1.2.3 From db14b8e7d4a1c8a6a8bdbe7dad0850e0ee1bbc87 Mon Sep 17 00:00:00 2001 From: h2so5 Date: Wed, 6 Nov 2013 11:25:33 +0900 Subject: avoid declaration error on VC++ --- src/pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pack.c b/src/pack.c index e28c0ca73..7d68dd338 100644 --- a/src/pack.c +++ b/src/pack.c @@ -193,9 +193,9 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i { int i; double d; + uint8_t *buffer = (uint8_t *)&d; str = str_len_ensure(mrb, str, sidx + 8); d = mrb_float(o); - uint8_t *buffer = (uint8_t *)&d; #ifdef MRB_ENDIAN_BIG #error unsupported -- cgit v1.2.3 From 78d2d909cfcc2e198c6ef56caef311af72ac024a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 20 Nov 2013 10:26:13 +0900 Subject: style --- src/pack.c | 93 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/src/pack.c b/src/pack.c index 7d68dd338..a9baa0d7d 100644 --- a/src/pack.c +++ b/src/pack.c @@ -45,16 +45,16 @@ enum { PACK_TYPE_NONE }; -#define PACK_FLAG_s 0x00000001 /* native size ("_" "!") */ -#define PACK_FLAG_a 0x00000002 /* null padding ("a") */ -#define PACK_FLAG_Z 0x00000004 /* append nul char ("z") */ -#define PACK_FLAG_SIGNED 0x00000008 /* native size ("_" "!") */ -#define PACK_FLAG_GT 0x00000010 /* big endian (">") */ -#define PACK_FLAG_LT 0x00000020 /* little endian ("<") */ -#define PACK_FLAG_WIDTH 0x00000040 /* */ -#define PACK_FLAG_LSB 0x00000080 /* LSB / low nibble first */ -#define PACK_FLAG_COUNT2 0x00000100 /* "count" is special... */ -#define PACK_FLAG_LITTLEENDIAN 0x00000200 /* little endian actually */ +#define PACK_FLAG_s 0x00000001 /* native size ("_" "!") */ +#define PACK_FLAG_a 0x00000002 /* null padding ("a") */ +#define PACK_FLAG_Z 0x00000004 /* append nul char ("z") */ +#define PACK_FLAG_SIGNED 0x00000008 /* native size ("_" "!") */ +#define PACK_FLAG_GT 0x00000010 /* big endian (">") */ +#define PACK_FLAG_LT 0x00000020 /* little endian ("<") */ +#define PACK_FLAG_WIDTH 0x00000040 /* */ +#define PACK_FLAG_LSB 0x00000080 /* LSB / low nibble first */ +#define PACK_FLAG_COUNT2 0x00000100 /* "count" is special... */ +#define PACK_FLAG_LITTLEENDIAN 0x00000200 /* little endian actually */ #define PACK_BASE64_IGNORE 0xff #define PACK_BASE64_PADDING 0xfe @@ -188,26 +188,6 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl return 4; } -static int -pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) -{ - int i; - double d; - uint8_t *buffer = (uint8_t *)&d; - str = str_len_ensure(mrb, str, sidx + 8); - d = mrb_float(o); - -#ifdef MRB_ENDIAN_BIG - #error unsupported -#else - for(i = 0; i< 8; i++){ - RSTRING_PTR(str)[sidx+i] = buffer[i]; - } -#endif - - return 8; -} - static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { @@ -229,6 +209,26 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un return 4; } +static int +pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + int i; + double d; + uint8_t *buffer = (uint8_t *)&d; + str = str_len_ensure(mrb, str, sidx + 8); + d = mrb_float(o); + +#ifdef MRB_ENDIAN_BIG + #error unsupported +#else + for(i = 0; i < 8; i++){ + RSTRING_PTR(str)[sidx+i] = buffer[i]; + } +#endif + + return 8; +} + static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { @@ -759,12 +759,12 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) struct tmpl tmpl; long count; unsigned int flags; - int dir, sidx, size, srclen, type; + int dir, size, srcidx, srclen, type; const char *sptr; prepare_tmpl(mrb, &tmpl); - sidx = 0; + srcidx = 0; srclen = RSTRING_LEN(str); result = mrb_ary_new(mrb); @@ -775,39 +775,39 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) continue; if (flags & PACK_FLAG_COUNT2) { - sptr = RSTRING_PTR(str) + sidx; + sptr = RSTRING_PTR(str) + srcidx; switch (dir) { case PACK_DIR_HEX: - sidx += unpack_h(mrb, sptr, srclen - sidx, result, count, flags); + srcidx += unpack_h(mrb, sptr, srclen - srcidx, result, count, flags); break; case PACK_DIR_STR: - sidx += unpack_a(mrb, sptr, srclen - sidx, result, count, flags); + srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags); break; } continue; } while (count != 0) { - if (srclen - sidx < size) { + if (srclen - srcidx < size) { while (count-- > 0) { mrb_ary_push(mrb, result, mrb_nil_value()); - } + } break; } - sptr = RSTRING_PTR(str) + sidx; + sptr = RSTRING_PTR(str) + srcidx; switch (dir) { case PACK_DIR_CHAR: - sidx += unpack_c(mrb, sptr, srclen - sidx, result, flags); + srcidx += unpack_c(mrb, sptr, srclen - srcidx, result, flags); break; case PACK_DIR_SHORT: - sidx += unpack_s(mrb, sptr, srclen - sidx, result, flags); + srcidx += unpack_s(mrb, sptr, srclen - srcidx, result, flags); break; case PACK_DIR_LONG: - sidx += unpack_l(mrb, sptr, srclen - sidx, result, flags); + srcidx += unpack_l(mrb, sptr, srclen - srcidx, result, flags); break; case PACK_DIR_BASE64: - sidx += unpack_m(mrb, sptr, srclen - sidx, result, flags); + srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); break; } if (count > 0) { @@ -822,16 +822,11 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) void mrb_mruby_pack_gem_init(mrb_state *mrb) { - struct RClass *cArray, *cString; - littleendian = check_little_endian(); make_base64_dec_tab(); - cArray = mrb->array_class; - cString = mrb->string_class; - - mrb_define_method(mrb, cArray, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, cString, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->string_class, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1)); } void -- cgit v1.2.3 From 2245818f913e1686d646e308770bcbcb773066ac Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 20 Nov 2013 12:13:34 +0900 Subject: make it more portable. --- src/pack.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/pack.c b/src/pack.c index a9baa0d7d..23bc6e667 100644 --- a/src/pack.c +++ b/src/pack.c @@ -191,19 +191,35 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { - unsigned long n; + char msg[60]; + unsigned long ul; + long sl; + mrb_int n; - if (flags & PACK_FLAG_LITTLEENDIAN) { - n = (src[3] << 24) + (src[2] << 16) + (src[1] << 8) + src[0]; - } else { - n = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; - } if (flags & PACK_FLAG_SIGNED) { - if (!FIXABLE((mrb_int)n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit signed number: %ld", (mrb_int)n); + if (flags & PACK_FLAG_LITTLEENDIAN) { + sl = (signed long)(signed char)src[3] * 256*256*256; + sl += (src[2] *256*256) + (src[1] * 256) + src[0]; + } else { + sl = (signed long)(signed char)src[0] * 256*256*256; + sl += (src[1] *256*256) + (src[2] * 256) + src[3]; + } + if (!FIXABLE(sl)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %ld", sl); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = sl; } else { - if (!POSFIXABLE(n)) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "cannot unpack to 32bit unsigned number: %lu", n); + if (flags & PACK_FLAG_LITTLEENDIAN) { + ul = src[3] * 256*256*256 + (src[2] *256*256) + (src[1] * 256) + src[0]; + } else { + ul = src[0] * 256*256*256 + (src[1] *256*256) + (src[2] * 256) + src[3]; + } + if (!POSFIXABLE(ul)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", ul); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = ul; } mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); return 4; -- cgit v1.2.3 From e641e9a380aeda07ccd99ee9d64724bf56a0f624 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 20 Nov 2013 12:14:54 +0900 Subject: suppress a compiler warning. --- src/pack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pack.c b/src/pack.c index 23bc6e667..e9550b501 100644 --- a/src/pack.c +++ b/src/pack.c @@ -649,6 +649,7 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, break; default: dir = PACK_DIR_INVALID; + type = PACK_TYPE_NONE; break; } -- cgit v1.2.3 From 80e01e3659e74a0823d2480a1fb391ff0a715e32 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:27:14 +0900 Subject: Create .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..09fa3368f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb" -- cgit v1.2.3 From 2bf49c923204a9d8b21d7112bc24bdb290a90204 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:31:45 +0900 Subject: Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 09fa3368f..ffe227284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,2 @@ script: - - "ruby run_test.rb" + - "ruby run_test.rb all test" -- cgit v1.2.3 From 28e00d82fb6691e28725351b62dc5fe715e41be7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 7 Apr 2014 13:15:54 +0900 Subject: suppress compiler warnings. --- src/pack.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pack.c b/src/pack.c index e9550b501..f130767ac 100644 --- a/src/pack.c +++ b/src/pack.c @@ -286,7 +286,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u { mrb_value dst; const char *sptr; - char *dptr, *dptr0; + char *dptr; sptr = src; @@ -294,7 +294,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u count = slen; dst = mrb_str_new(mrb, NULL, count); - dptr0 = dptr = RSTRING_PTR(dst); + dptr = RSTRING_PTR(dst); memcpy(dptr, sptr, count); if (flags & PACK_FLAG_Z) { @@ -359,7 +359,7 @@ static int unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags) { mrb_value dst; - int a, ashift, b, bshift, padding; + int a, ashift, b, bshift; const char *sptr, *sptr0; char *dptr, *dptr0; const char hexadecimal[] = "0123456789abcdef"; @@ -382,7 +382,6 @@ unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, un sptr0 = sptr; dptr0 = dptr; - padding = 0; while (slen > 0 && count > 0) { a = (*sptr >> ashift) & 0x0f; b = (*sptr >> bshift) & 0x0f; @@ -777,7 +776,7 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) long count; unsigned int flags; int dir, size, srcidx, srclen, type; - const char *sptr; + const unsigned char *sptr; prepare_tmpl(mrb, &tmpl); -- cgit v1.2.3 From 1997420a7f7fce627091c9046dca118f5e6697c0 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Fri, 13 Jun 2014 17:42:43 +0900 Subject: Fix raise format found with mruby-clang-plugin. --- src/pack.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pack.c b/src/pack.c index f130767ac..3e56454f2 100644 --- a/src/pack.c +++ b/src/pack.c @@ -665,7 +665,8 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, count = -1; } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') { if (strchr("sSiIlL", t) == NULL) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlL", ch); + char ch_str = ch; + mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlL", mrb_str_new(mrb, &ch_str, 1)); } if (ch == '_' || ch == '!') { flags |= PACK_FLAG_s; @@ -721,7 +722,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) if (mrb_float_p(o)) { o = mrb_funcall(mrb, o, "to_i", 0); } else if (!mrb_fixnum_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into Integer", mrb_obj_classname(mrb, o)); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Integer", mrb_class_path(mrb, mrb_obj_class(mrb, o))); } } else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { @@ -729,7 +730,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) } } else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, o)); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); } } -- cgit v1.2.3 From f4f968241b1518175192c4f5302c36d420497fa5 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Fri, 13 Jun 2014 17:56:36 +0900 Subject: Add support of little endian float. --- src/pack.c | 31 ++++++++++++++++++++++++++++++- test/pack.rb | 4 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/pack.c b/src/pack.c index 3e56454f2..f8cdcbaad 100644 --- a/src/pack.c +++ b/src/pack.c @@ -31,7 +31,7 @@ enum { //PACK_DIR_UTF8, /* U */ //PACK_DIR_BER, PACK_DIR_DOUBLE, /* E */ - //PACK_DIR_FLOAT, /* f */ + PACK_DIR_FLOAT, /* f */ PACK_DIR_STR, /* A */ PACK_DIR_HEX, /* h */ PACK_DIR_BASE64, /* m */ @@ -245,6 +245,26 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i return 8; } +static int +pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + int i; + float f; + uint8_t *buffer = (uint8_t *)&f; + str = str_len_ensure(mrb, str, sidx + 4); + f = mrb_float(o); + +#ifdef MRB_ENDIAN_BIG + #error unsupported +#else + for(i = 0; i < 4; i++){ + RSTRING_PTR(str)[sidx+i] = buffer[i]; + } +#endif + + return 4; +} + static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { @@ -580,6 +600,12 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, size = 8; flags |= PACK_FLAG_SIGNED; break; + case 'e': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 4; + flags |= PACK_FLAG_SIGNED; + break; case 'H': dir = PACK_DIR_HEX; type = PACK_TYPE_STRING; @@ -756,6 +782,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) case PACK_DIR_DOUBLE: ridx += pack_double(mrb, o, result, ridx, flags); break; + case PACK_DIR_FLOAT: + ridx += pack_float(mrb, o, result, ridx, flags); + break; default: break; } diff --git a/test/pack.rb b/test/pack.rb index 7789fb446..2d754dfc1 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -88,3 +88,7 @@ end assert('issue #1') do [1, 2].pack("nn") == "\000\001\000\002" end + +assert 'pack float' do + assert_equal "\x00\x00@@", [3.0].pack('e') +end -- cgit v1.2.3 From 7dc2b4f59f2b9019089d8a934c96148b1cdfd3b5 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Fri, 13 Jun 2014 18:22:56 +0900 Subject: Implement g/f/F/G/d/D packing. --- src/pack.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- test/pack.rb | 18 +++++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/pack.c b/src/pack.c index f8cdcbaad..93fd3f16b 100644 --- a/src/pack.c +++ b/src/pack.c @@ -234,14 +234,26 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i str = str_len_ensure(mrb, str, sidx + 8); d = mrb_float(o); + if (flags & PACK_FLAG_LT) { #ifdef MRB_ENDIAN_BIG - #error unsupported + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } #else - for(i = 0; i < 8; i++){ - RSTRING_PTR(str)[sidx+i] = buffer[i]; - } + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); +#endif + } else if (flags & PACK_FLAG_GT) { +#ifdef MRB_ENDIAN_BIG + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); +#else + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } #endif - + } else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); + } + return 8; } @@ -254,14 +266,26 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in str = str_len_ensure(mrb, str, sidx + 4); f = mrb_float(o); + if (flags & PACK_FLAG_LT) { #ifdef MRB_ENDIAN_BIG - #error unsupported + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } #else - for(i = 0; i < 4; i++){ - RSTRING_PTR(str)[sidx+i] = buffer[i]; - } + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); +#endif + } else if (flags & PACK_FLAG_GT) { +#ifdef MRB_ENDIAN_BIG + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); +#else + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } #endif - + } else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); + } + return 4; } @@ -594,17 +618,41 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, size = 1; flags |= PACK_FLAG_SIGNED; break; - case 'E': + case 'D': case 'd': dir = PACK_DIR_DOUBLE; type = PACK_TYPE_FLOAT; size = 8; flags |= PACK_FLAG_SIGNED; break; + case 'F': case 'f': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED; + break; + case 'E': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT; + break; case 'e': dir = PACK_DIR_FLOAT; type = PACK_TYPE_FLOAT; size = 4; - flags |= PACK_FLAG_SIGNED; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT; + break; + case 'G': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT; + break; + case 'g': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 4; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT; break; case 'H': dir = PACK_DIR_HEX; diff --git a/test/pack.rb b/test/pack.rb index 2d754dfc1..02265f126 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -91,4 +91,22 @@ end assert 'pack float' do assert_equal "\x00\x00@@", [3.0].pack('e') + assert_equal "@@\x00\x00", [3.0].pack('g') + + native = [3.0].pack 'f' + assert_true native == "\x00\x00@@" or native == "@@\x00\x00" + + native = [3.0].pack 'F' + assert_true native == "\x00\x00@@" or native == "@@\x00\x00" +end + +assert 'pack double' do + assert_equal "\x00\x00\x00\x00\x00\x00\b@", [3.0].pack('E') + assert_equal "@\b\x00\x00\x00\x00\x00\x00", [3.0].pack('G') + + native = [3.0].pack 'd' + assert_true native == "\x00\x00\x00\x00\x00\x00\b@" or native == "@\b\x00\x00\x00\x00\x00\x00" + + native = [3.0].pack 'D' + assert_true native == "\x00\x00\x00\x00\x00\x00\b@" or native == "@\b\x00\x00\x00\x00\x00\x00" end -- cgit v1.2.3 From 514450e891e015efa9fd01f13a46863d4f118c13 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Fri, 13 Jun 2014 20:19:47 +0900 Subject: Use PACK_FLAG_LITTLEENDIAN. --- src/pack.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/pack.c b/src/pack.c index 93fd3f16b..6b211c961 100644 --- a/src/pack.c +++ b/src/pack.c @@ -234,7 +234,7 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i str = str_len_ensure(mrb, str, sidx + 8); d = mrb_float(o); - if (flags & PACK_FLAG_LT) { + if (flags & PACK_FLAG_LITTLEENDIAN) { #ifdef MRB_ENDIAN_BIG for (i = 0; i < 8; ++i) { RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; @@ -242,7 +242,7 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i #else memcpy(RSTRING_PTR(str) + sidx, buffer, 8); #endif - } else if (flags & PACK_FLAG_GT) { + } else { #ifdef MRB_ENDIAN_BIG memcpy(RSTRING_PTR(str) + sidx, buffer, 8); #else @@ -250,8 +250,6 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; } #endif - } else { - memcpy(RSTRING_PTR(str) + sidx, buffer, 8); } return 8; @@ -266,7 +264,7 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in str = str_len_ensure(mrb, str, sidx + 4); f = mrb_float(o); - if (flags & PACK_FLAG_LT) { + if (flags & PACK_FLAG_LITTLEENDIAN) { #ifdef MRB_ENDIAN_BIG for (i = 0; i < 4; ++i) { RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; @@ -274,7 +272,7 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in #else memcpy(RSTRING_PTR(str) + sidx, buffer, 4); #endif - } else if (flags & PACK_FLAG_GT) { + } else { #ifdef MRB_ENDIAN_BIG memcpy(RSTRING_PTR(str) + sidx, buffer, 4); #else @@ -282,8 +280,6 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; } #endif - } else { - memcpy(RSTRING_PTR(str) + sidx, buffer, 4); } return 4; -- cgit v1.2.3 From 8f4b7ac15c77f24952364f1b3b1ac42e2e52ebd5 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Sat, 14 Jun 2014 13:16:13 +0900 Subject: Support float/double unpacking. --- src/pack.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- test/pack.rb | 41 +++++++++++++++++++++++-------------- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/pack.c b/src/pack.c index 6b211c961..69cf740ff 100644 --- a/src/pack.c +++ b/src/pack.c @@ -255,6 +255,35 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i return 8; } +static int +unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags) +{ + int i; + double d; + uint8_t *buffer = (uint8_t *)&d; + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } +#else + memcpy(buffer, src, 8); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(buffer, src, 8); +#else + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } +#endif + } + mrb_ary_push(mrb, ary, mrb_float_value(mrb, d)); + + return 8; +} + static int pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) { @@ -285,6 +314,35 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in return 4; } +static int +unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags) +{ + int i; + float f; + uint8_t *buffer = (uint8_t *)&f; + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } +#else + memcpy(buffer, src, 4); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(buffer, src, 4); +#else + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } +#endif + } + mrb_ary_push(mrb, ary, mrb_float_value(mrb, f)); + + return 4; +} + static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { @@ -623,7 +681,7 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, case 'F': case 'f': dir = PACK_DIR_FLOAT; type = PACK_TYPE_FLOAT; - size = 8; + size = 4; flags |= PACK_FLAG_SIGNED; break; case 'E': @@ -899,6 +957,12 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) case PACK_DIR_BASE64: srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); break; + case PACK_DIR_FLOAT: + srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_DOUBLE: + srcidx += unpack_double(mrb, sptr, srclen - srcidx, result, flags); + break; } if (count > 0) { count--; diff --git a/test/pack.rb b/test/pack.rb index 02265f126..c7899e2d7 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -89,24 +89,35 @@ assert('issue #1') do [1, 2].pack("nn") == "\000\001\000\002" end -assert 'pack float' do - assert_equal "\x00\x00@@", [3.0].pack('e') - assert_equal "@@\x00\x00", [3.0].pack('g') +def assert_pack tmpl, packed, unpacked + assert_equal packed, unpacked.pack(tmpl) + assert_equal unpacked, packed.unpack(tmpl) +end + +PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 - native = [3.0].pack 'f' - assert_true native == "\x00\x00@@" or native == "@@\x00\x00" +assert 'pack float' do + assert_pack 'e', "\x00\x00@@", [3.0] + assert_pack 'g', "@@\x00\x00", [3.0] - native = [3.0].pack 'F' - assert_true native == "\x00\x00@@" or native == "@@\x00\x00" + if PACK_IS_LITTLE_ENDIAN + assert_pack 'f', "\x00\x00@@", [3.0] + assert_pack 'F', "\x00\x00@@", [3.0] + else + assert_pack 'f', "@@\x00\x00", [3.0] + assert_pack 'F', "@@\x00\x00", [3.0] + end end assert 'pack double' do - assert_equal "\x00\x00\x00\x00\x00\x00\b@", [3.0].pack('E') - assert_equal "@\b\x00\x00\x00\x00\x00\x00", [3.0].pack('G') - - native = [3.0].pack 'd' - assert_true native == "\x00\x00\x00\x00\x00\x00\b@" or native == "@\b\x00\x00\x00\x00\x00\x00" - - native = [3.0].pack 'D' - assert_true native == "\x00\x00\x00\x00\x00\x00\b@" or native == "@\b\x00\x00\x00\x00\x00\x00" + assert_pack 'E', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + assert_pack 'G', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + + if PACK_IS_LITTLE_ENDIAN + assert_pack 'd', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + assert_pack 'D', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + else + assert_pack 'd', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + assert_pack 'D', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + end end -- cgit v1.2.3 From 7b2611ea28aad709d16f6196baabbdbdbd806087 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Sat, 14 Jun 2014 13:20:37 +0900 Subject: Update supported template list. --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e11a61a5..fb2ce15ec 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,12 @@ rake ENABLE_GEMS="true" ## support template string - C : 8-bit unsigned (unsigned char) - c : 8-bit signed (signed char) - - E : 64-bit double, little endian + - D, d: 64-bit float, native format + - F, f: 32-bit float, native format + - E : 64-bit float, little endian byte order + - e : 32-bit float, little endian byte order + - G : 64-bit float, network (big-endian) byte order + - g : 32-bit float, network (big-endian) byte order - S : 16-bit unsigned, native endian (uint16_t) - s : 16-bit signed, native endian (int16_t) - L : 32-bit unsigned, native endian (uint32_t) -- cgit v1.2.3 From 669fe705cc490eedd2f4a09ed558f8186813d7a5 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 12 Dec 2014 12:01:58 +0900 Subject: "i" and "I". --- src/pack.c | 19 +++++++++++++++++++ test/pack.rb | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/pack.c b/src/pack.c index 69cf740ff..fa8b5ef66 100644 --- a/src/pack.c +++ b/src/pack.c @@ -650,6 +650,7 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, tlen = RSTRING_LEN(tmpl->str); t = tptr[tmpl->idx++]; +alias: switch (t) { case 'A': dir = PACK_DIR_STR; @@ -718,6 +719,24 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, type = PACK_TYPE_STRING; flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB; break; + case 'I': + switch (sizeof(int)) { + case 2: t = 'S'; goto alias; + case 4: t = 'L'; goto alias; + case 8: t = 'Q'; goto alias; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + } + break; + case 'i': + switch (sizeof(int)) { + case 2: t = 's'; goto alias; + case 4: t = 'l'; goto alias; + case 8: t = 'q'; goto alias; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + } + break; case 'L': dir = PACK_DIR_LONG; type = PACK_TYPE_INTEGER; diff --git a/test/pack.rb b/test/pack.rb index c7899e2d7..5e9932f4f 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -121,3 +121,27 @@ assert 'pack double' do assert_pack 'D', "@\b\x00\x00\x00\x00\x00\x00", [3.0] end end + +assert 'pack/unpack "i"' do + int_size = [0].pack('i').size + raise "pack('i').size is too small (#{int_size})" if int_size < 2 + + if PACK_IS_LITTLE_ENDIAN + str = "\xC7\xCF" + "\xFF" * (int_size-2) + else + str = "\xFF" * (int_size-2) + "\xC7\xCF" + end + assert_pack 'i', str, [-12345] +end + +assert 'pack/unpack "I"' do + uint_size = [0].pack('I').size + raise "pack('I').size is too small (#{uint_size})" if uint_size < 2 + + if PACK_IS_LITTLE_ENDIAN + str = "\x39\x30" + "\0" * (uint_size-2) + else + str = "\0" * (uint_size-2) + "\x39\x30" + end + assert_pack 'I', str, [12345] +end -- cgit v1.2.3 From 2103bc99ba1f20597d91230ad22ef4b2dfe55969 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 12 Dec 2014 12:12:19 +0900 Subject: style --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fb2ce15ec..989b45cd4 100644 --- a/README.md +++ b/README.md @@ -11,29 +11,29 @@ rake ENABLE_GEMS="true" ./bin/mruby ${MRUBY_ROOT}/mrbgems/g/mruby-pack/example/sample.rb ``` -## support template string +## supported template string + - A : arbitrary binary string (space padded, count is width) + - a : arbitrary binary string (null padded, count is width) - C : 8-bit unsigned (unsigned char) - c : 8-bit signed (signed char) - D, d: 64-bit float, native format - - F, f: 32-bit float, native format - E : 64-bit float, little endian byte order - e : 32-bit float, little endian byte order + - F, f: 32-bit float, native format - G : 64-bit float, network (big-endian) byte order - g : 32-bit float, network (big-endian) byte order - - S : 16-bit unsigned, native endian (uint16_t) - - s : 16-bit signed, native endian (int16_t) - - L : 32-bit unsigned, native endian (uint32_t) - - l : 32-bit signed, native endian (int32_t) - - n : 16-bit unsigned, network (big-endian) byte order - - N : 32-bit unsigned, network (big-endian) byte order - - v : 16-bit unsigned, VAX (little-endian) byte order - - V : 32-bit unsigned, VAX (little-endian) byte order - - A : arbitrary binary string (space padded, count is width) - - a : arbitrary binary string (null padded, count is width) - - Z : same as "a", except that null is added with * - H : hex string (high nibble first) - h : hex string (low nibble first) + - L : 32-bit unsigned, native endian (`uint32_t`) + - l : 32-bit signed, native endian (`int32_t`) - 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 + - 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 + - v : 16-bit unsigned, VAX (little-endian) byte order + - Z : same as "a", except that null is added with * ## License -- cgit v1.2.3 From 121475638d3d043a7666163a5e49544a88aea89a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 12 Dec 2014 12:12:41 +0900 Subject: add "I" and "i". --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 989b45cd4..d253f7e72 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ rake ENABLE_GEMS="true" - g : 32-bit float, network (big-endian) byte order - H : hex string (high nibble first) - h : hex string (low nibble first) + - I : unsigned integer, native endian (`unsigned int` in C) + - i : signed integer, native endian (`int` in C) - L : 32-bit unsigned, native endian (`uint32_t`) - l : 32-bit signed, native endian (`int32_t`) - m : base64 encoded string (see RFC 2045, count is width) -- cgit v1.2.3 From 15de80a7cdf3a21ebedc5c39b8ec3478098279b9 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 22 May 2015 09:41:39 +0900 Subject: style. --- src/pack.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pack.c b/src/pack.c index fa8b5ef66..6dfcab29e 100644 --- a/src/pack.c +++ b/src/pack.c @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include struct tmpl { mrb_value str; @@ -51,7 +51,7 @@ enum { #define PACK_FLAG_SIGNED 0x00000008 /* native size ("_" "!") */ #define PACK_FLAG_GT 0x00000010 /* big endian (">") */ #define PACK_FLAG_LT 0x00000020 /* little endian ("<") */ -#define PACK_FLAG_WIDTH 0x00000040 /* */ +#define PACK_FLAG_WIDTH 0x00000040 /* "count" is "width" */ #define PACK_FLAG_LSB 0x00000080 /* LSB / low nibble first */ #define PACK_FLAG_COUNT2 0x00000100 /* "count" is special... */ #define PACK_FLAG_LITTLEENDIAN 0x00000200 /* little endian actually */ @@ -868,17 +868,17 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) if (type == PACK_TYPE_INTEGER) { if (mrb_float_p(o)) { o = mrb_funcall(mrb, o, "to_i", 0); - } else if (!mrb_fixnum_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Integer", mrb_class_path(mrb, mrb_obj_class(mrb, o))); - } + } else if (!mrb_fixnum_p(o)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Integer", mrb_class_path(mrb, mrb_obj_class(mrb, o))); + } } else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { o = mrb_funcall(mrb, o, "to_f", 0); } } else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); - } + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); + } } switch (dir) { -- cgit v1.2.3 From 2ba4933158c3c7635deaefa70cee661a0d60be9e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 22 May 2015 11:38:39 +0900 Subject: refactor "AaZ". fixes #6. --- src/pack.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/pack.c b/src/pack.c index 6dfcab29e..dcc03e0e5 100644 --- a/src/pack.c +++ b/src/pack.c @@ -357,7 +357,9 @@ pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u else pad = ' '; - if (count == -1) { + if (count == 0) { + return 0; + } else if (count == -1) { copylen = slen; padlen = (flags & PACK_FLAG_Z) ? 1 : 0; } else if (count < slen) { @@ -383,29 +385,31 @@ static int unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags) { mrb_value dst; - const char *sptr; - char *dptr; + const char *cp, *sptr; + long copylen; sptr = src; + if (count != -1 && count < slen) { + slen = count; + } + copylen = slen; - if (count == -1 || count > slen) - count = slen; - - dst = mrb_str_new(mrb, NULL, count); - dptr = RSTRING_PTR(dst); - - memcpy(dptr, sptr, count); - if (flags & PACK_FLAG_Z) { - if (count > 0 && dptr[count - 1] == '\0') - count--; - } else if (!(flags & PACK_FLAG_a)) { - while (count > 0 && (dptr[count - 1] == '\0' || isspace(dptr[count - 1]))) - count--; + if (flags & PACK_FLAG_Z) { /* "Z" */ + if ((cp = memchr(sptr, '\0', slen)) != NULL) { + copylen = cp - sptr; + if (count == -1) { + slen = copylen + 1; + } + } + } else if (!(flags & PACK_FLAG_a)) { /* "A" */ + while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) { + copylen--; + } } - dst = mrb_str_resize(mrb, dst, count); + dst = mrb_str_new(mrb, sptr, copylen); mrb_ary_push(mrb, ary, dst); - return count; + return slen; } @@ -909,6 +913,10 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) default: break; } + if (dir == PACK_DIR_STR) { /* always consumes 1 entry */ + aidx++; + break; + } if (count > 0) { count--; } -- cgit v1.2.3 From b913e7eefd90705ee8e3e832cbfa3c9af73e7597 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 22 May 2015 11:38:56 +0900 Subject: test suite for pack/unpack. --- packtest.rb | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 packtest.rb diff --git a/packtest.rb b/packtest.rb new file mode 100644 index 000000000..003131236 --- /dev/null +++ b/packtest.rb @@ -0,0 +1,143 @@ +# encoding: ascii + +# a = Array, s = String, t = Template + +def packtest(a, s, t) + begin + r = a.pack(t) + return if r == s + puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}" + rescue => r + unless r.is_a? s + puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}" + end + end +end + +def unpacktest(a, s, t) + r = s.unpack(t) + return if r == a + puts "#{s.inspect}.unpack(#{t.inspect}) -> #{r.inspect} should be #{a.inspect}" +end + +def pptest(a, s, t) + packtest(a, s, t) + unpacktest(a, s, t) +end + +pptest [1], "\x01", "C" + +packtest [1.1], "\x01", "C" +packtest [-1], "\xff", "C" +packtest [1,2], "\x01\x02", "C2" +#packtest [1], "X", ArgumentError + +unpacktest [48, nil], "0", "CC" +unpacktest [160, -96], "\xa0\xa0", "Cc" +unpacktest [49, 50, 51], "123", "C*" + +pptest [12849], "12", "S" +unpacktest [nil], "0", "S" +unpacktest [12849, nil], "123", "SS" +unpacktest [12849], "123", "S*" + +pptest [10000], "\x27\x10", "s>" +pptest [-10000], "\xd8\xf0", "s>" +pptest [50000], "\xc3\x50", "S>" + +pptest [10000], "\x10\x27", "s<" +pptest [-10000], "\xf0\xd8", "s<" +pptest [50000], "\x50\xc3", "S<" + +pptest [1000000000], "\x3b\x9a\xca\x00", "l>" +pptest [-1000000000], "\xc4\x65\x36\x00", "l>" + +pptest [1], "\x01\x00\x00\x00", "L<" +pptest [258], "\x02\x01\x00\x00", "L<" +pptest [66051], "\x03\x02\x01\x00", "L<" +pptest [16909060], "\x04\x03\x02\x01", "L<" +pptest [16909060], "\x01\x02\x03\x04", "L>" + +packtest [-1], "\xff\xff\xff\xff", "L<" + +pptest [16909060], "\x01\x02\x03\x04", "N" +pptest [258], "\x01\x02", "n" +pptest [32769], "\x80\x01", "n" + +pptest [16909060], "\x04\x03\x02\x01", "V" +pptest [258], "\x02\x01", "v" + +packtest [""], "", "m" +packtest ["a"], "YQ==\n", "m" +packtest ["ab"], "YWI=\n", "m" +packtest ["abc"], "YWJj\n", "m" +packtest ["abcd"], "YWJjZA==\n", "m" + +unpacktest [""], "", "m" +unpacktest ["a"], "YQ==\n", "m" +unpacktest ["ab"], "YWI=\n", "m" +unpacktest ["abc"], "YWJj\n", "m" +unpacktest ["abcd"], "YWJjZA==\n", "m" + +packtest [""], "\0", "H" +packtest ["3"], "0", "H" +packtest ["34"], "", "H0" +packtest ["34"], "0", "H" +packtest ["34"], "4", "H2" +packtest ["34"], "4\0", "H3" +packtest ["3456"], "4P", "H3" +packtest ["34563"], "4V0", "H*" +packtest ["5a"], "Z", "H*" +packtest ["5A"], "Z", "H*" + +unpacktest [""], "", "H" +unpacktest [""], "0", "H0" +unpacktest ["3"], "0", "H" +unpacktest ["30"], "0", "H2" +unpacktest ["30"], "0", "H3" +unpacktest ["303"], "01", "H3" +unpacktest ["303132"], "012", "H*" +unpacktest ["3031", 50], "012", "H4C" +unpacktest ["5a"], "Z", "H*" + +packtest [""], "\0", "h" +packtest ["3"], "\03", "h" +packtest ["34"], "", "h0" +packtest ["34"], "\03", "h" +packtest ["34"], "C", "h2" +packtest ["34"], "C\0", "h3" +packtest ["3456"], "C\05", "h3" +packtest ["34563"], "Ce\03", "h*" + +packtest [""], " ", "A" +unpacktest [""], "", "A" +pptest ["1"], "1", "A" +pptest ["1"], "1 ", "A2" +unpacktest ["1"], "1", "A2" +unpacktest ["1"], "1 ", "A2" +unpacktest ["1"], "1\0", "A2" +packtest ["12"], "1", "A" +unpacktest ["1"], "12", "A" +pptest ["123"], "123", "A*" +packtest ["1","2"], "2", "A0A" +unpacktest ["","2"], "2", "A0A" + +packtest [""], "\0", "a" +unpacktest [""], "", "a" +pptest ["1"], "1", "a" +pptest ["1 "], "1 ", "a2" +pptest ["1\0"], "1\0", "a2" +packtest ["1"], "1\0", "a2" +pptest ["123"], "123", "a*" + +packtest [""], "\0", "Z" +unpacktest [""], "", "Z" +pptest ["1"], "1", "Z" +pptest ["1"], "1\0", "Z2" +pptest ["1 "], "1 ", "Z2" +pptest ["123"], "123\0", "Z*" +pptest ["1","2"], "12", "ZZ" +pptest ["1","2"], "1\0002", "Z*Z" +unpacktest ["1","3"], "1\00023", "Z3Z" + +packtest [1, 2], "\x01\x02", "CyC" -- cgit v1.2.3 From d34db58797427ddc55ade11bcdcefbc614b20eba Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 6 Aug 2015 15:38:35 +0900 Subject: implicit type conversion caused unexpected result. fixes #8. --- src/pack.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pack.c b/src/pack.c index dcc03e0e5..276944e4b 100644 --- a/src/pack.c +++ b/src/pack.c @@ -211,9 +211,15 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un n = sl; } else { if (flags & PACK_FLAG_LITTLEENDIAN) { - ul = src[3] * 256*256*256 + (src[2] *256*256) + (src[1] * 256) + src[0]; + ul = (unsigned long)src[3] * 256*256*256; + ul += (unsigned long)src[2] *256*256; + ul += (unsigned long)src[1] *256; + ul += (unsigned long)src[0]; } else { - ul = src[0] * 256*256*256 + (src[1] *256*256) + (src[2] * 256) + src[3]; + ul = (unsigned long)src[0] * 256*256*256; + ul += (unsigned long)src[1] *256*256; + ul += (unsigned long)src[2] *256; + ul += (unsigned long)src[3]; } if (!POSFIXABLE(ul)) { snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", ul); -- cgit v1.2.3 From 359d2ae6fd60cff9593d145d4e7c881cf031fbd5 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 7 Aug 2015 11:48:45 +0900 Subject: support "q" and "Q". closes #7. --- README.md | 2 ++ packtest.rb | 8 ++++++ src/pack.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 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 */ @@ -231,6 +231,72 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un return 4; } +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) { @@ -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; -- cgit v1.2.3 From 4603047eb1a053cf566ab82444453b6f154b920a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 7 Aug 2015 11:49:56 +0900 Subject: update installation procedure. --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e82458f06..91addce80 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ mruby-pack (pack / unpack) ========= -## install by mrbgems -```bash -git clone git://github.com/iij/mruby-pack.git -cp -pr mruby-pack ${MRUBY_ROOT}/mrbgems/g/. -echo mruby-pack >> ${MRUBY_ROOT}/mrbgems/GEMS.active -cd ${MRUBY_ROOT} -rake ENABLE_GEMS="true" -./bin/mruby ${MRUBY_ROOT}/mrbgems/g/mruby-pack/example/sample.rb +mruby-pack provides `Array#pack` and `String#unpack` for mruby. + + +## Installation +Add the line below into your `build_config.rb`: + ``` + conf.gem :github => 'iij/mruby-pack' +``` + +There is no dependency on other mrbgems. + -## supported template string +## Supported template string - A : arbitrary binary string (space padded, count is width) - a : arbitrary binary string (null padded, count is width) - C : 8-bit unsigned (unsigned char) -- cgit v1.2.3 From e8efd10bd9750fd3769b46a0b2888ef9ae215991 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 7 Aug 2015 11:51:01 +0900 Subject: make pack_l simpler. --- src/pack.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/pack.c b/src/pack.c index 3a750eb69..1ceda8c11 100644 --- a/src/pack.c +++ b/src/pack.c @@ -192,37 +192,30 @@ static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { char msg[60]; - unsigned long ul; - long sl; + uint32_t ul; mrb_int n; + if (flags & PACK_FLAG_LITTLEENDIAN) { + ul = (uint32_t)src[3] * 256*256*256; + ul += (uint32_t)src[2] *256*256; + ul += (uint32_t)src[1] *256; + ul += (uint32_t)src[0]; + } else { + ul = (uint32_t)src[0] * 256*256*256; + ul += (uint32_t)src[1] *256*256; + ul += (uint32_t)src[2] *256; + ul += (uint32_t)src[3]; + } if (flags & PACK_FLAG_SIGNED) { - if (flags & PACK_FLAG_LITTLEENDIAN) { - sl = (signed long)(signed char)src[3] * 256*256*256; - sl += (src[2] *256*256) + (src[1] * 256) + src[0]; - } else { - sl = (signed long)(signed char)src[0] * 256*256*256; - sl += (src[1] *256*256) + (src[2] * 256) + src[3]; - } + int32_t sl = ul; if (!FIXABLE(sl)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %ld", sl); + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %ld", (long)sl); mrb_raise(mrb, E_RANGE_ERROR, msg); } n = sl; } else { - if (flags & PACK_FLAG_LITTLEENDIAN) { - ul = (unsigned long)src[3] * 256*256*256; - ul += (unsigned long)src[2] *256*256; - ul += (unsigned long)src[1] *256; - ul += (unsigned long)src[0]; - } else { - ul = (unsigned long)src[0] * 256*256*256; - ul += (unsigned long)src[1] *256*256; - ul += (unsigned long)src[2] *256; - ul += (unsigned long)src[3]; - } if (!POSFIXABLE(ul)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", ul); + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", (unsigned long)ul); mrb_raise(mrb, E_RANGE_ERROR, msg); } n = ul; -- cgit v1.2.3 From b9f7daf5b6734a71abc7069482fc213afcd493b6 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 1 Jul 2016 22:25:01 +0900 Subject: Suppress compiler warning [-Wpointer-sign] --- src/pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pack.c b/src/pack.c index 1ceda8c11..b865651f0 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1029,7 +1029,7 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) continue; if (flags & PACK_FLAG_COUNT2) { - sptr = RSTRING_PTR(str) + srcidx; + sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx; switch (dir) { case PACK_DIR_HEX: srcidx += unpack_h(mrb, sptr, srclen - srcidx, result, count, flags); @@ -1049,7 +1049,7 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) break; } - sptr = RSTRING_PTR(str) + srcidx; + sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx; switch (dir) { case PACK_DIR_CHAR: srcidx += unpack_c(mrb, sptr, srclen - srcidx, result, flags); -- cgit v1.2.3 From 26c1dedcabf6c845356653570f4dadd594c45709 Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Mon, 18 Jul 2016 16:04:26 +0200 Subject: Added 'U' pack support. --- packtest.rb | 3 +++ src/pack.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packtest.rb b/packtest.rb index feaed31f9..e8be7c76c 100644 --- a/packtest.rb +++ b/packtest.rb @@ -149,3 +149,6 @@ pptest ["1","2"], "1\0002", "Z*Z" unpacktest ["1","3"], "1\00023", "Z3Z" packtest [1, 2], "\x01\x02", "CyC" + +packtest [65], "A", 'U' +packtest [59411], "\xEE\xA0\x93", 'U' diff --git a/src/pack.c b/src/pack.c index 1ceda8c11..d8bd68d4c 100644 --- a/src/pack.c +++ b/src/pack.c @@ -28,7 +28,7 @@ enum { PACK_DIR_QUAD, /* Q */ //PACK_DIR_INT, /* i */ //PACK_DIR_VAX, - //PACK_DIR_UTF8, /* U */ + PACK_DIR_UTF8, /* U */ //PACK_DIR_BER, PACK_DIR_DOUBLE, /* E */ PACK_DIR_FLOAT, /* f */ @@ -408,6 +408,45 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar return 4; } +static int +pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, unsigned int flags) +{ + char utf8[4]; + int len; + + unsigned long c = mrb_fixnum(o); + + /* Unicode character */ + /* from mruby-compiler gem */ + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + + str = str_len_ensure(mrb, str, sidx + len); + memcpy(RSTRING_PTR(str) + sidx, utf8, len); + + return len; +} + static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { @@ -856,6 +895,10 @@ alias: size = 2; flags |= PACK_FLAG_SIGNED; break; + case 'U': + dir = PACK_DIR_UTF8; + type = PACK_TYPE_INTEGER; + break; case 'V': /* = "L<" */ dir = PACK_DIR_LONG; type = PACK_TYPE_INTEGER; @@ -989,6 +1032,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) case PACK_DIR_FLOAT: ridx += pack_float(mrb, o, result, ridx, flags); break; + case PACK_DIR_UTF8: + ridx += pack_utf8(mrb, o, result, ridx, count, flags); + break; default: break; } -- cgit v1.2.3 From 906b516cfa808a53aed0f8517fdef43a9fc9382b Mon Sep 17 00:00:00 2001 From: masahino Date: Fri, 9 Dec 2016 21:57:06 +0900 Subject: Add pointer casting --- src/pack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pack.c b/src/pack.c index c9023a5fb..9095ad03b 100644 --- a/src/pack.c +++ b/src/pack.c @@ -492,14 +492,14 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u const char *cp, *sptr; long copylen; - sptr = src; + sptr = (const char *)src; if (count != -1 && count < slen) { slen = count; } copylen = slen; if (flags & PACK_FLAG_Z) { /* "Z" */ - if ((cp = memchr(sptr, '\0', slen)) != NULL) { + if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) { copylen = cp - sptr; if (count == -1) { slen = copylen + 1; @@ -578,7 +578,7 @@ unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, un bshift = 0; } - sptr = src; + sptr = (const char *)src; if (count == -1) count = slen * 2; @@ -686,7 +686,7 @@ unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int const char *sptr, *sptr0; char *dptr, *dptr0; - sptr0 = sptr = src; + sptr0 = sptr = (const char *)src; dlen = slen / 4 * 3; /* an estimated value - may be shorter */ dst = mrb_str_new(mrb, NULL, dlen); -- cgit v1.2.3 From 88a7fedea413568a1ff0410e109ff55a03b63a5f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 9 Feb 2017 11:07:55 +0900 Subject: support "x". --- README.md | 2 ++ packtest.rb | 3 +++ src/pack.c | 55 ++++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 91addce80..d4613c700 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,11 @@ There is no dependency on other mrbgems. - s : 16-bit signed, native endian (`int16_t`) - V : 32-bit unsigned, VAX (little-endian) byte order - v : 16-bit unsigned, VAX (little-endian) byte order + - x : null byte - Z : same as "a", except that null is added with * + ## License Copyright (c) 2012 Internet Initiative Japan Inc. diff --git a/packtest.rb b/packtest.rb index e8be7c76c..459447af7 100644 --- a/packtest.rb +++ b/packtest.rb @@ -152,3 +152,6 @@ packtest [1, 2], "\x01\x02", "CyC" packtest [65], "A", 'U' packtest [59411], "\xEE\xA0\x93", 'U' + +pptest [1], "\x00\x01", "xC" +unpacktest [2], "\xcc\x02", "xC" diff --git a/src/pack.c b/src/pack.c index 9095ad03b..6a0075f5a 100644 --- a/src/pack.c +++ b/src/pack.c @@ -22,19 +22,20 @@ struct tmpl { }; enum { - PACK_DIR_CHAR, /* C */ - PACK_DIR_SHORT, /* S */ - PACK_DIR_LONG, /* L */ - PACK_DIR_QUAD, /* Q */ - //PACK_DIR_INT, /* i */ + PACK_DIR_CHAR, /* C */ + PACK_DIR_SHORT, /* S */ + PACK_DIR_LONG, /* L */ + PACK_DIR_QUAD, /* Q */ + //PACK_DIR_INT, /* i */ //PACK_DIR_VAX, - PACK_DIR_UTF8, /* U */ + PACK_DIR_UTF8, /* U */ //PACK_DIR_BER, - PACK_DIR_DOUBLE, /* E */ - PACK_DIR_FLOAT, /* f */ - PACK_DIR_STR, /* A */ - PACK_DIR_HEX, /* h */ - PACK_DIR_BASE64, /* m */ + PACK_DIR_DOUBLE, /* E */ + PACK_DIR_FLOAT, /* f */ + PACK_DIR_STR, /* A */ + PACK_DIR_HEX, /* h */ + PACK_DIR_BASE64, /* m */ + PACK_DIR_NUL, /* x */ PACK_DIR_INVALID }; @@ -731,6 +732,26 @@ done: return sptr - sptr0; } +static int +pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + long i; + + dst = str_len_ensure(mrb, dst, didx + count); + for (i = 0; i < count; i++) { + RSTRING_PTR(dst)[didx] = '\0'; + } + return count; +} + +static int +unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags) +{ + if (slen < count) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string"); + } + return count; +} static void prepare_tmpl(mrb_state *mrb, struct tmpl *tmpl) @@ -911,6 +932,10 @@ alias: size = 2; flags |= PACK_FLAG_LT; break; + case 'x': + dir = PACK_DIR_NUL; + type = PACK_TYPE_NONE; + break; case 'Z': dir = PACK_DIR_STR; type = PACK_TYPE_STRING; @@ -982,6 +1007,10 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) if (dir == PACK_DIR_INVALID) continue; + else if (dir == PACK_DIR_NUL) { + ridx += pack_x(mrb, mrb_nil_value(), result, ridx, count, flags); + continue; + } for (; aidx < RARRAY_LEN(ary); aidx++) { if (count == 0 && !(flags & PACK_FLAG_WIDTH)) @@ -1073,6 +1102,10 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) if (dir == PACK_DIR_INVALID) continue; + else if (dir == PACK_DIR_NUL) { + srcidx += unpack_x(mrb, sptr, srclen - srcidx, result, count, flags); + continue; + } if (flags & PACK_FLAG_COUNT2) { sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx; -- cgit v1.2.3 From a80a745b699965169b7ffebbfbe2a7568d7afd98 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 3 Apr 2017 23:01:41 +0900 Subject: Support unpack template "U" --- src/pack.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- test/pack.rb | 14 ++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/pack.c b/src/pack.c index 6a0075f5a..8c76b2638 100644 --- a/src/pack.c +++ b/src/pack.c @@ -448,6 +448,80 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, return len; } +static const unsigned long utf8_limits[] = { + 0x0, /* 1 */ + 0x80, /* 2 */ + 0x800, /* 3 */ + 0x10000, /* 4 */ + 0x200000, /* 5 */ + 0x4000000, /* 6 */ + 0x80000000, /* 7 */ +}; + +static unsigned long +utf8_to_uv(mrb_state *mrb, const char *p, long *lenp) +{ + int c = *p++ & 0xff; + unsigned long uv = c; + long n; + + if (!(uv & 0x80)) { + *lenp = 1; + return uv; + } + if (!(uv & 0x40)) { + *lenp = 1; + mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character"); + } + + if (!(uv & 0x20)) { n = 2; uv &= 0x1f; } + else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; } + else if (!(uv & 0x08)) { n = 4; uv &= 0x07; } + else if (!(uv & 0x04)) { n = 5; uv &= 0x03; } + else if (!(uv & 0x02)) { n = 6; uv &= 0x01; } + else { + *lenp = 1; + mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character"); + } + if (n > *lenp) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %S bytes, given %S bytes)", + mrb_fixnum_value(n), mrb_fixnum_value(*lenp)); + } + *lenp = n--; + if (n != 0) { + while (n--) { + c = *p++ & 0xff; + if ((c & 0xc0) != 0x80) { + *lenp -= n + 1; + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character"); + } + else { + c &= 0x3f; + uv = uv << 6 | c; + } + } + } + n = *lenp - 1; + if (uv < utf8_limits[n]) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence"); + } + return uv; +} + +static int +unpack_utf8(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags) +{ + unsigned long uv; + long lenp = srclen; + + if (srclen == 0) { + return 1; + } + uv = utf8_to_uv(mrb, (const char *)src, &lenp); + mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)uv)); + return (int)lenp; +} + static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { @@ -482,7 +556,7 @@ pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u while (padlen-- > 0) { *dptr++ = pad; } - + return dptr - dptr0; } @@ -541,7 +615,7 @@ pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u } else if (slen > count) { slen = count; } - + dst = str_len_ensure(mrb, dst, didx + count); dptr = RSTRING_PTR(dst) + didx; @@ -1151,6 +1225,11 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) case PACK_DIR_DOUBLE: srcidx += unpack_double(mrb, sptr, srclen - srcidx, result, flags); break; + case PACK_DIR_UTF8: + srcidx += unpack_utf8(mrb, sptr, srclen - srcidx, result, flags); + break; + default: + mrb_raise(mrb, E_RUNTIME_ERROR, "mruby-pack's bug"); } if (count > 0) { count--; diff --git a/test/pack.rb b/test/pack.rb index 5e9932f4f..e9f5fb040 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -145,3 +145,17 @@ assert 'pack/unpack "I"' do end assert_pack 'I', str, [12345] end + +assert 'pack/unpack "U"' do + assert_equal [], "".unpack("U") + assert_equal [], "".unpack("U*") + assert_equal [65, 66], "ABC".unpack("U2") + assert_equal [12371, 12435, 12395, 12385, 12399, 19990, 30028], "こんにちは世界".unpack("U*") + + assert_equal "", [].pack("U") + assert_equal "", [].pack("U*") + assert_equal "AB", [65, 66, 67].pack("U2") + assert_equal "こんにちは世界", [12371, 12435, 12395, 12385, 12399, 19990, 30028].pack("U*") + + assert_equal "\000", [0].pack("U") +end -- cgit v1.2.3 From f691a73c26342dbc15f9b99cb9e763186da36e23 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 3 Apr 2017 23:02:49 +0900 Subject: Should raise RangeError --- src/pack.c | 20 ++++++++++++++------ test/pack.rb | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/pack.c b/src/pack.c index 8c76b2638..ba561249e 100644 --- a/src/pack.c +++ b/src/pack.c @@ -77,7 +77,7 @@ check_little_endian(void) static unsigned int hex2int(unsigned char ch) { - if (ch >= '0' && ch <= '9') + if (ch >= '0' && ch <= '9') return ch - '0'; else if (ch >= 'A' && ch <= 'F') return 10 + (ch - 'A'); @@ -414,8 +414,12 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, { char utf8[4]; int len; - - unsigned long c = mrb_fixnum(o); + unsigned long c = 0; + + if (mrb_float_p(o)) { + goto range_error; + } + c = mrb_fixnum(o); /* Unicode character */ /* from mruby-compiler gem */ @@ -434,17 +438,21 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, utf8[2] = (char)(0x80 | ( c & 0x3F)); len = 3; } - else { + else if (c < 0x200000) { utf8[0] = (char)(0xF0 | (c >> 18) ); utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); utf8[3] = (char)(0x80 | ( c & 0x3F)); len = 4; } - + else { +range_error: + mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range"); + } + str = str_len_ensure(mrb, str, sidx + len); memcpy(RSTRING_PTR(str) + sidx, utf8, len); - + return len; } diff --git a/test/pack.rb b/test/pack.rb index e9f5fb040..f518ca4fa 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -158,4 +158,8 @@ assert 'pack/unpack "U"' do assert_equal "こんにちは世界", [12371, 12435, 12395, 12385, 12399, 19990, 30028].pack("U*") assert_equal "\000", [0].pack("U") + + assert_raise(RangeError) { [-0x40000000].pack("U") } + assert_raise(RangeError) { [-1].pack("U") } + assert_raise(RangeError) { [0x40000000].pack("U") } end -- cgit v1.2.3 From 0dbd1d59926da2b52ae7e52388d3cf0199905d53 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 3 Apr 2017 23:20:02 +0900 Subject: Add "U" template to doc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d4613c700..95733e2d5 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ There is no dependency on other mrbgems. - q : 64-bit signed, native endian (`int64_t`) - S : 16-bit unsigned, native endian (`uint16_t`) - s : 16-bit signed, native endian (`int16_t`) + - U : UTF-8 character - V : 32-bit unsigned, VAX (little-endian) byte order - v : 16-bit unsigned, VAX (little-endian) byte order - x : null byte -- cgit v1.2.3 From d83e15e866d38cabbaad7c0f29cd93ef97be43b5 Mon Sep 17 00:00:00 2001 From: ksss Date: Tue, 4 Apr 2017 11:10:34 +0900 Subject: Should use `to_int` instead of `to_i` For CRuby compatibility --- src/pack.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pack.c b/src/pack.c index 6a0075f5a..5a5b97b75 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1018,11 +1018,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) o = mrb_ary_ref(mrb, ary, aidx); if (type == PACK_TYPE_INTEGER) { - if (mrb_float_p(o)) { - o = mrb_funcall(mrb, o, "to_i", 0); - } else if (!mrb_fixnum_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Integer", mrb_class_path(mrb, mrb_obj_class(mrb, o))); - } + o = mrb_to_int(mrb, o); } else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { o = mrb_funcall(mrb, o, "to_f", 0); -- cgit v1.2.3