summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-pack
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-pack')
-rw-r--r--mrbgems/mruby-pack/README.md61
-rw-r--r--mrbgems/mruby-pack/src/pack.c394
-rw-r--r--mrbgems/mruby-pack/test/pack.rb55
3 files changed, 353 insertions, 157 deletions
diff --git a/mrbgems/mruby-pack/README.md b/mrbgems/mruby-pack/README.md
index efa51cc1b..712cf8e1c 100644
--- a/mrbgems/mruby-pack/README.md
+++ b/mrbgems/mruby-pack/README.md
@@ -1,5 +1,4 @@
-mruby-pack (pack / unpack)
-=========
+# mruby-pack (pack / unpack)
mruby-pack provides `Array#pack` and `String#unpack` for mruby.
@@ -8,41 +7,41 @@ mruby-pack provides `Array#pack` and `String#unpack` for mruby.
Add the line below into your build configuration:
```
- conf.gem :github => 'iij/mruby-pack'
+ conf.gem :core => 'mruby-pack'
```
There is no dependency on other mrbgems.
## 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
- - 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
- - 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)
- - 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`)
- - 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
- - Z : same as "a", except that null is added with *
+- 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
+- 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
+- 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)
+- 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`)
+- 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
+- Z : same as "a", except that null is added with *
## License
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c
index e52171d6b..f0d4b8d9e 100644
--- a/mrbgems/mruby-pack/src/pack.c
+++ b/mrbgems/mruby-pack/src/pack.c
@@ -18,18 +18,23 @@
#define INT_OVERFLOW_P(n) ((n) < MRB_INT_MIN || (n) > MRB_INT_MAX)
#define UINT_OVERFLOW_P(n) ((n) > MRB_INT_MAX)
+#ifndef EOF
+# define EOF (-1) /* for MRB_NO_STDIO */
+#endif
+
struct tmpl {
mrb_value str;
int idx;
};
-enum {
+enum pack_dir {
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_BER, /* w */
PACK_DIR_UTF8, /* U */
//PACK_DIR_BER,
PACK_DIR_DOUBLE, /* E */
@@ -37,30 +42,33 @@ enum {
PACK_DIR_STR, /* A */
PACK_DIR_HEX, /* h */
PACK_DIR_BASE64, /* m */
+ PACK_DIR_QENC, /* M */
PACK_DIR_NUL, /* x */
+ PACK_DIR_BACK, /* X */
+ PACK_DIR_ABS, /* @ */
PACK_DIR_INVALID
};
-enum {
+enum pack_type {
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 /* "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 */
+#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 /* "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 */
-#define PACK_BASE64_IGNORE 0xff
-#define PACK_BASE64_PADDING 0xfe
+#define PACK_BASE64_IGNORE 0xff
+#define PACK_BASE64_PADDING 0xfe
const static unsigned char base64chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -76,7 +84,7 @@ hex2int(unsigned char ch)
else if (ch >= 'a' && ch <= 'f')
return 10 + (ch - 'a');
else
- return 0;
+ return -1;
}
static void
@@ -113,7 +121,7 @@ str_len_ensure(mrb_state *mrb, mrb_value str, mrb_int len)
static int
-pack_c(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+pack_char(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] = (char)mrb_integer(o);
@@ -121,7 +129,7 @@ pack_c(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl
}
static int
-unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned int flags)
+unpack_char(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));
@@ -131,7 +139,7 @@ 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)
+pack_short(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
{
uint16_t n;
@@ -148,7 +156,7 @@ pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl
}
static int
-unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+unpack_short(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
{
int n;
@@ -165,7 +173,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)
+pack_long(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
{
uint32_t n;
@@ -219,7 +227,7 @@ u32tostr(char *buf, size_t len, uint32_t n)
#endif /* MRB_INT64 */
static int
-unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+unpack_long(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
{
#ifndef MRB_INT64
char msg[60];
@@ -254,7 +262,7 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un
}
static int
-pack_q(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+pack_quad(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
{
uint64_t n;
@@ -336,7 +344,7 @@ i64tostr(char *buf, size_t len, int64_t n)
#endif /* MRB_INT64 */
static int
-unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+unpack_quad(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
{
char msg[60];
uint64_t ull;
@@ -375,6 +383,46 @@ unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un
return 8;
}
+static int
+pack_BER(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+ mrb_int n = mrb_integer(o);
+ size_t i;
+ char *p;
+
+ if (n < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "can't compress negative numbers");
+ }
+ for (i=1; i<sizeof(mrb_int)+1; i++) {
+ mrb_int mask = ~((1L<<(7*i))-1);
+ if ((n & mask) == 0) break;
+ }
+ str = str_len_ensure(mrb, str, sidx + i);
+ p = RSTRING_PTR(str)+sidx;
+ for (size_t j=i; j>0; p++,j--) {
+ mrb_int x = (n>>(7*(j-1)))&0x7f;
+ *p = (char)x;
+ if (j > 1) *p |= 0x80;
+ }
+ return i;
+}
+
+static int
+unpack_BER(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+ mrb_int i, n = 0;
+ const unsigned char *p = src;
+ const unsigned char *e = p + srclen;
+
+ for (i=1; p<e; p++,i++) {
+ n <<= 7;
+ n |= *p & 0x7f;
+ if ((*p & 0x80) == 0) break;
+ }
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, n));
+ return i;
+}
+
#ifndef MRB_NO_FLOAT
static int
pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
@@ -504,7 +552,7 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar
#endif
static int
-pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, unsigned int flags)
+pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, int count, unsigned int flags)
{
char utf8[4];
int len = 0;
@@ -621,7 +669,7 @@ unpack_utf8(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary
}
static int
-pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+pack_str(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, unsigned int flags)
{
mrb_int copylen, slen, padlen;
char *dptr, *dptr0, pad, *sptr;
@@ -659,7 +707,7 @@ pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
}
static int
-unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags)
+unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
{
mrb_value dst;
const char *cp, *sptr;
@@ -693,7 +741,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)
+pack_hex(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, unsigned int flags)
{
unsigned int a, ashift, b, bshift;
long slen;
@@ -724,10 +772,12 @@ pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
a = b = 0;
if (slen > 0) {
a = hex2int(*sptr++);
+ if (a < 0) break;
slen--;
}
if (slen > 0) {
b = hex2int(*sptr++);
+ if (b < 0) break;
slen--;
}
*dptr++ = (a << ashift) + (b << bshift);
@@ -737,7 +787,7 @@ pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
}
static int
-unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
+unpack_hex(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
{
mrb_value dst;
int a, ashift, b, bshift;
@@ -783,9 +833,8 @@ unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, un
return (int)(sptr - sptr0);
}
-
static int
-pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+pack_base64(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count)
{
mrb_int dstlen;
unsigned long l;
@@ -851,7 +900,7 @@ pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
}
static int
-unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int flags)
+unpack_base64(mrb_state *mrb, const void *src, int slen, mrb_value ary)
{
mrb_value dst;
int dlen;
@@ -874,13 +923,13 @@ unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int
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++;
- }
+ if (c >= sizeof(base64_dec_tab))
+ continue;
+ ch[i] = base64_dec_tab[c];
+ if (ch[i] == PACK_BASE64_PADDING) {
+ ch[i] = 0;
+ padding++;
+ }
} while (c >= sizeof(base64_dec_tab) || ch[i] == PACK_BASE64_IGNORE);
}
@@ -907,25 +956,117 @@ done:
}
static int
-pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+pack_qenc(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count)
+{
+ static const char hex_table[] = "0123456789ABCDEF";
+ char buff[1024];
+ char *s = RSTRING_PTR(src);
+ char *send = s + RSTRING_LEN(src);
+ int i = 0, n = 0, prev = EOF;
+ int dlen = 0;
+
+ if (count <= 1) count = 72;
+ while (s < send) {
+ if ((*s > 126) ||
+ (*s < 32 && *s != '\n' && *s != '\t') ||
+ (*s == '=')) {
+ buff[i++] = '=';
+ buff[i++] = hex_table[(*s & 0xf0) >> 4];
+ buff[i++] = hex_table[*s & 0x0f];
+ n += 3;
+ prev = EOF;
+ }
+ else if (*s == '\n') {
+ if (prev == ' ' || prev == '\t') {
+ buff[i++] = '=';
+ buff[i++] = *s;
+ }
+ buff[i++] = *s;
+ n = 0;
+ prev = *s;
+ }
+ else {
+ buff[i++] = *s;
+ n++;
+ prev = *s;
+ }
+ if (n > count) {
+ buff[i++] = '=';
+ buff[i++] = '\n';
+ n = 0;
+ prev = '\n';
+ }
+ if (i > 1024 - 5) {
+ str_len_ensure(mrb, dst, didx+dlen+i);
+ memcpy(RSTRING_PTR(dst)+didx+dlen, buff, i);
+ dlen += i;
+ i = 0;
+ }
+ s++;
+ }
+ if (n > 0) {
+ buff[i++] = '=';
+ buff[i++] = '\n';
+ }
+ if (i > 0) {
+ str_len_ensure(mrb, dst, didx+dlen+i);
+ memcpy(RSTRING_PTR(dst)+didx+dlen, buff, i);
+ dlen += i;
+ }
+ return dlen;
+}
+
+static int
+unpack_qenc(mrb_state *mrb, const void *src, int slen, mrb_value ary)
+{
+ mrb_value buf = mrb_str_new(mrb, 0, slen);
+ const char *s = (const char*)src, *ss = s;
+ const char *send = s + slen;
+ char *ptr = RSTRING_PTR(buf);
+ int c1, c2;
+
+ while (s < send) {
+ if (*s == '=') {
+ if (++s == send) break;
+ if (s+1 < send && *s == '\r' && *(s+1) == '\n')
+ s++;
+ if (*s != '\n') {
+ if ((c1 = hex2int(*s)) == -1) break;
+ if (++s == send) break;
+ if ((c2 = hex2int(*s)) == -1) break;
+ *ptr++ = (char)(c1 << 4 | c2);
+ }
+ }
+ else {
+ *ptr++ = *s;
+ }
+ s++;
+ ss = s;
+ }
+ buf = mrb_str_resize(mrb, buf, (mrb_int)(ptr - RSTRING_PTR(buf)));
+ mrb_str_cat(mrb, buf, ss, send-ss);
+ mrb_ary_push(mrb, ary, buf);
+ return slen;
+}
+
+static int
+pack_nul(mrb_state *mrb, mrb_value dst, mrb_int didx, int count)
{
long i;
- if (count < 0) return 0;
dst = str_len_ensure(mrb, dst, didx + count);
for (i = 0; i < count; i++) {
RSTRING_PTR(dst)[didx + i] = '\0';
}
return count;
}
-static int
-unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
+
+static void
+check_x(mrb_state *mrb, int a, int count, char c)
{
- if (count < 0) return slen;
- if (slen < count) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string");
+ if (a < count) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "%c outside of string", c);
}
- return count;
}
static void
@@ -942,10 +1083,12 @@ has_tmpl(const struct tmpl *tmpl)
}
static void
-read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, int *countp, unsigned int *flagsp)
+read_tmpl(mrb_state *mrb, struct tmpl *tmpl, enum pack_dir *dirp, enum pack_type *typep, int *sizep, int *countp, unsigned int *flagsp)
{
mrb_int t, tlen;
- int ch, dir, type, size = 0;
+ int ch, size = 0;
+ enum pack_dir dir;
+ enum pack_type type;
int count = 1;
unsigned int flags = 0;
const char *tptr;
@@ -1052,11 +1195,21 @@ alias:
size = 4;
flags |= PACK_FLAG_SIGNED;
break;
+ case 'w':
+ dir = PACK_DIR_BER;
+ type = PACK_TYPE_INTEGER;
+ flags |= PACK_FLAG_SIGNED;
+ break;
case 'm':
dir = PACK_DIR_BASE64;
type = PACK_TYPE_STRING;
flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2;
break;
+ case 'M':
+ dir = PACK_DIR_QENC;
+ type = PACK_TYPE_STRING;
+ flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2;
+ break;
case 'N': /* = "L>" */
dir = PACK_DIR_LONG;
type = PACK_TYPE_INTEGER;
@@ -1111,11 +1264,23 @@ alias:
dir = PACK_DIR_NUL;
type = PACK_TYPE_NONE;
break;
+ case 'X':
+ dir = PACK_DIR_BACK;
+ type = PACK_TYPE_NONE;
+ break;
+ case '@':
+ dir = PACK_DIR_ABS;
+ type = PACK_TYPE_NONE;
+ break;
case 'Z':
dir = PACK_DIR_STR;
type = PACK_TYPE_STRING;
flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z;
break;
+ case 'p': case 'P':
+ case '%':
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "%c is not supported", (char)t);
+ break;
default:
dir = PACK_DIR_INVALID;
type = PACK_TYPE_NONE;
@@ -1124,19 +1289,21 @@ alias:
/* read suffix [0-9*_!<>] */
while (tmpl->idx < tlen) {
- ch = tptr[tmpl->idx++];
+ ch = tptr[tmpl->idx];
if (ISDIGIT(ch)) {
- count = ch - '0';
- while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) {
- int ch = tptr[tmpl->idx++] - '0';
- if (count+ch > INT_MAX/10) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length");
- }
- count = count * 10 + ch;
+ char *e;
+ mrb_int n = mrb_int_read(tptr+tmpl->idx, tptr+tlen, &e);
+ if (e == NULL || n > INT_MAX) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length");
}
- continue; /* special case */
+ count = (int)n;
+ tmpl->idx = e - tptr;
+ continue;
} else if (ch == '*') {
- count = -1;
+ if (type == PACK_TYPE_NONE)
+ count = 0;
+ else
+ count = -1;
} else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
if (strchr("sSiIlLqQ", (int)t) == NULL) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlLqQ", ch);
@@ -1148,10 +1315,11 @@ alias:
} else if (ch == '>') {
flags |= PACK_FLAG_GT;
}
- } else {
- tmpl->idx--;
+ }
+ else {
break;
}
+ tmpl->idx++;
}
if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) {
@@ -1173,7 +1341,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
struct tmpl tmpl;
int count;
unsigned int flags;
- int dir, ridx, size, type;
+ enum pack_dir dir;
+ enum pack_type type;
+ int ridx, size;
prepare_tmpl(mrb, &tmpl);
@@ -1186,8 +1356,22 @@ 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);
- if (ridx < 0) goto overflow;
+ grow:
+ if (ridx > INT_MAX - count) goto overflow;
+ ridx += pack_nul(mrb, result, ridx, count);
+ continue;
+ }
+ else if (dir == PACK_DIR_BACK) {
+ check_x(mrb, ridx, count, 'X');
+ ridx -= count;
+ continue;
+ }
+ else if (dir == PACK_DIR_ABS) {
+ count -= ridx;
+ if (count > 0) goto grow;
+ count = -count;
+ check_x(mrb, ridx, count, '@');
+ ridx -= count;
continue;
}
@@ -1200,12 +1384,12 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
o = mrb_ary_ref(mrb, ary, aidx);
if (type == PACK_TYPE_INTEGER) {
- o = mrb_to_int(mrb, o);
+ o = mrb_to_integer(mrb, o);
}
#ifndef MRB_NO_FLOAT
else if (type == PACK_TYPE_FLOAT) {
if (!mrb_float_p(o)) {
- mrb_float f = mrb_to_flo(mrb, o);
+ mrb_float f = mrb_as_float(mrb, o);
o = mrb_float_value(mrb, f);
}
}
@@ -1218,25 +1402,31 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
switch (dir) {
case PACK_DIR_CHAR:
- ridx += pack_c(mrb, o, result, ridx, flags);
+ ridx += pack_char(mrb, o, result, ridx, flags);
break;
case PACK_DIR_SHORT:
- ridx += pack_s(mrb, o, result, ridx, flags);
+ ridx += pack_short(mrb, o, result, ridx, flags);
break;
case PACK_DIR_LONG:
- ridx += pack_l(mrb, o, result, ridx, flags);
+ ridx += pack_long(mrb, o, result, ridx, flags);
break;
case PACK_DIR_QUAD:
- ridx += pack_q(mrb, o, result, ridx, flags);
+ ridx += pack_quad(mrb, o, result, ridx, flags);
+ break;
+ case PACK_DIR_BER:
+ ridx += pack_BER(mrb, o, result, ridx, flags);
break;
case PACK_DIR_BASE64:
- ridx += pack_m(mrb, o, result, ridx, count, flags);
+ ridx += pack_base64(mrb, o, result, ridx, count);
+ break;
+ case PACK_DIR_QENC:
+ ridx += pack_qenc(mrb, o, result, ridx, count);
break;
case PACK_DIR_HEX:
- ridx += pack_h(mrb, o, result, ridx, count, flags);
+ ridx += pack_hex(mrb, o, result, ridx, count, flags);
break;
case PACK_DIR_STR:
- ridx += pack_a(mrb, o, result, ridx, count, flags);
+ ridx += pack_str(mrb, o, result, ridx, count, flags);
break;
#ifndef MRB_NO_FLOAT
case PACK_DIR_DOUBLE:
@@ -1252,7 +1442,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
default:
break;
}
- if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64 || dir == PACK_DIR_HEX) {
+ if (flags & PACK_FLAG_COUNT2) {
/* always consumes 1 entry */
aidx++;
break;
@@ -1278,7 +1468,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
struct tmpl tmpl;
int count;
unsigned int flags;
- int dir, size, type;
+ enum pack_dir dir;
+ enum pack_type type;
+ int size;
int srcidx, srclen;
const unsigned char *sptr;
@@ -1294,24 +1486,39 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
if (dir == PACK_DIR_INVALID)
continue;
else if (dir == PACK_DIR_NUL) {
- srcidx += unpack_x(mrb, sptr, srclen - srcidx, result, count, flags);
+ check_x(mrb, srclen-srcidx, count, 'x');
+ srcidx += count;
+ continue;
+ }
+ else if (dir == PACK_DIR_BACK) {
+ check_x(mrb, srcidx, count, 'X');
+ srcidx -= count;
+ continue;
+ }
+ else if (dir == PACK_DIR_ABS) {
+ check_x(mrb, srclen, count, '@');
+ srcidx = count;
continue;
}
- if (flags & PACK_FLAG_COUNT2) {
- sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx;
- switch (dir) {
- case PACK_DIR_HEX:
- srcidx += unpack_h(mrb, sptr, srclen - srcidx, result, count, flags);
- break;
- case PACK_DIR_STR:
- srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags);
- break;
- case PACK_DIR_BASE64:
- srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags);
- break;
- }
+ /* PACK_FLAG_COUNT2 directions */
+ sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx;
+ switch (dir) {
+ case PACK_DIR_HEX:
+ srcidx += unpack_hex(mrb, sptr, srclen - srcidx, result, count, flags);
+ continue;
+ case PACK_DIR_STR:
+ srcidx += unpack_str(mrb, sptr, srclen - srcidx, result, count, flags);
continue;
+ case PACK_DIR_BASE64:
+ srcidx += unpack_base64(mrb, sptr, srclen - srcidx, result);
+ continue;
+ break;
+ case PACK_DIR_QENC:
+ srcidx += unpack_qenc(mrb, sptr, srclen - srcidx, result);
+ continue;
+ default:
+ break;
}
while (count != 0) {
@@ -1325,16 +1532,19 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
sptr = (const unsigned char*)RSTRING_PTR(str) + srcidx;
switch (dir) {
case PACK_DIR_CHAR:
- srcidx += unpack_c(mrb, sptr, srclen - srcidx, result, flags);
+ srcidx += unpack_char(mrb, sptr, srclen - srcidx, result, flags);
break;
case PACK_DIR_SHORT:
- srcidx += unpack_s(mrb, sptr, srclen - srcidx, result, flags);
+ srcidx += unpack_short(mrb, sptr, srclen - srcidx, result, flags);
break;
case PACK_DIR_LONG:
- srcidx += unpack_l(mrb, sptr, srclen - srcidx, result, flags);
+ srcidx += unpack_long(mrb, sptr, srclen - srcidx, result, flags);
break;
case PACK_DIR_QUAD:
- srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags);
+ srcidx += unpack_quad(mrb, sptr, srclen - srcidx, result, flags);
+ break;
+ case PACK_DIR_BER:
+ srcidx += unpack_BER(mrb, sptr, srclen - srcidx, result, flags);
break;
#ifndef MRB_NO_FLOAT
case PACK_DIR_FLOAT:
diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb
index a248174a5..16db6607b 100644
--- a/mrbgems/mruby-pack/test/pack.rb
+++ b/mrbgems/mruby-pack/test/pack.rb
@@ -10,78 +10,59 @@ def assert_pack tmpl, packed, unpacked
end
# pack & unpack 'm' (base64)
-assert('[""].pack("m")') do
+assert('pack("m")') do
assert_pack "m", "", [""]
-end
-
-assert('["\0"].pack("m")') do
assert_pack "m", "AA==\n", ["\0"]
-end
-
-assert('["\0\0"].pack("m")') do
assert_pack "m", "AAA=\n", ["\0\0"]
-end
-
-assert('["\0\0\0"].pack("m")') do
assert_pack "m", "AAAA\n", ["\0\0\0"]
-end
-
-assert('["abc..xyzABC..XYZ"].pack("m")') do
assert_pack "m", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
-end
-assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do
ary = ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m")
assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m")
-end
-assert('["A", "B"].pack') do
assert_equal "QQ==\n", ["A", "B"].pack("m50")
assert_equal ["A"], "QQ==\n".unpack("m50")
assert_equal "QQ==Qg==", ["A", "B"].pack("m0 m0")
assert_equal ["A", "B"], "QQ==Qg==".unpack("m10 m10")
+ assert_pack "m0", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
end
-assert('["abc..xyzABC..XYZ"].pack("m0")') do
- assert_pack "m0", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
+# pack & unpack 'M' (Quoted-printable)
+assert('pack("M")') do
+ assert_pack "M", "123=\n", ["123"]
+ assert_pack "M", "=3D\n", ["=\n"]
+ assert_pack "M", "=E3=81=82=\n", ["あ"]
+
+ assert_equal ["123"], "123=\n".unpack("M")
+ assert_equal ["=\n"], "=3D\n".unpack("M")
+ assert_equal ["あ"], "=E3=81=82=\n".unpack("M")
end
# pack & unpack 'H'
-assert('["3031"].pack("H*")') do
+assert('pack("H")') do
assert_pack "H*", "01", ["3031"]
-end
-
-assert('["10"].pack("H*")') do
assert_pack "H*", "\020", ["10"]
end
-assert('[0,1,127,128,255].pack("C*")') do
+assert('pack("C")') do
assert_pack "C*", "\x00\x01\x7F\x80\xFF", [0, 1, 127, 128, 255]
end
-# pack "a"
-assert('["abc"].pack("a")') do
+assert('pack("a")') do
assert_equal "a", ["abc"].pack("a")
assert_equal "abc", ["abc"].pack("a*")
assert_equal "abc\0", ["abc"].pack("a4")
-end
-# upack "a"
-assert('["abc"].pack("a")') do
assert_equal ["abc\0"], "abc\0".unpack("a4")
assert_equal ["abc "], "abc ".unpack("a4")
end
-# pack "A"
-assert('["abc"].pack("A")') do
+assert('pack("A")') do
assert_equal "a", ["abc"].pack("A")
assert_equal "abc", ["abc"].pack("A*")
assert_equal "abc ", ["abc"].pack("A4")
-end
-# upack "A"
-assert('["abc"].pack("A")') do
assert_equal ["abc"], "abc\0".unpack("A4")
assert_equal ["abc"], "abc ".unpack("A4")
end
@@ -143,6 +124,12 @@ assert 'pack/unpack "I"' do
assert_pack 'I', str, [12345]
end
+assert 'pack/unpack "w"' do
+ for x in [0,1,127,128,16383,16384,65535,65536]
+ assert_equal [x], [x].pack("w").unpack("w")
+ end
+end
+
assert 'pack/unpack "U"' do
assert_equal [], "".unpack("U")
assert_equal [], "".unpack("U*")