diff options
Diffstat (limited to 'mrbgems/mruby-pack/src/pack.c')
| -rw-r--r-- | mrbgems/mruby-pack/src/pack.c | 214 |
1 files changed, 130 insertions, 84 deletions
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index d96ef1002..9f091194b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -3,7 +3,7 @@ */ #include "mruby.h" -#include "error.h" +#include "mruby/error.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/numeric.h" @@ -60,19 +60,39 @@ enum { #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 unsigned char base64_dec_tab[128]; +#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER__) +# define BYTE_ORDER __BYTE_ORDER__ +#endif +#if !defined(BIG_ENDIAN) && defined(__ORDER_BIG_ENDIAN__) +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif +#if !defined(LITTLE_ENDIAN) && defined(__ORDER_LITTLE_ENDIAN__) +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif -static int +#ifdef BYTE_ORDER +# if BYTE_ORDER == BIG_ENDIAN +# define littleendian 0 +# define check_little_endian() (void)0 +# elif BYTE_ORDER == LITTLE_ENDIAN +# define littleendian 1 +# define check_little_endian() (void)0 +# endif +#endif +#ifndef littleendian +/* can't distinguish endian in compile time */ +static int littleendian = 0; +static void check_little_endian(void) { unsigned int n = 1; - return (*(unsigned char *)&n == 1); + littleendian = (*(unsigned char *)&n == 1); } +#endif static unsigned int hex2int(unsigned char ch) @@ -98,9 +118,9 @@ make_base64_dec_tab(void) 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; + base64_dec_tab['+'+0] = 62; + base64_dec_tab['/'+0] = 63; + base64_dec_tab['='+0] = PACK_BASE64_PADDING; } static mrb_value @@ -313,21 +333,23 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i d = mrb_float(o); if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 8; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + if (littleendian) { + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); + } + else { + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } } -#else - memcpy(RSTRING_PTR(str) + sidx, buffer, 8); -#endif } else { -#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]; + if (littleendian) { + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } + } + else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); } -#endif } return 8; @@ -341,21 +363,23 @@ unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value a 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]; + if (littleendian) { + memcpy(buffer, src, 8); + } + else { + 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]; + if (littleendian) { + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } + } + else { + memcpy(buffer, src, 8); } -#endif } mrb_ary_push(mrb, ary, mrb_float_value(mrb, d)); @@ -372,21 +396,23 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in f = (float)mrb_float(o); if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 4; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + if (littleendian) { + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); + } + else { + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } } -#else - memcpy(RSTRING_PTR(str) + sidx, buffer, 4); -#endif } else { -#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]; + if (littleendian) { + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } + } + else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); } -#endif } return 4; @@ -400,21 +426,23 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar 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]; + if (littleendian) { + memcpy(buffer, src, 4); + } + else { + 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]; + if (littleendian) { + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } + } + else { + memcpy(buffer, src, 4); } -#endif } mrb_ary_push(mrb, ary, mrb_float_value(mrb, f)); @@ -429,11 +457,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, int len = 0; uint32_t c = 0; -#ifndef MRB_WITHOUT_FLOAT - if (mrb_float_p(o)) { - goto range_error; - } -#endif c = (uint32_t)mrb_fixnum(o); /* Unicode character */ @@ -461,9 +484,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, len = 4; } else { -#ifndef MRB_WITHOUT_FLOAT -range_error: -#endif mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range"); } @@ -510,7 +530,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp) } 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)); + mrb_fixnum_value(n), mrb_fixnum_value(*lenp)); } *lenp = n--; if (n != 0) { @@ -598,19 +618,21 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u } copylen = slen; - if (flags & PACK_FLAG_Z) { /* "Z" */ + if (slen >= 0 && flags & PACK_FLAG_Z) { /* "Z" */ if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) { copylen = (int)(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]))) { + } + else if (!(flags & PACK_FLAG_a)) { /* "A" */ + while (copylen > 0 && (sptr[copylen - 1] == '\0' || ISSPACE(sptr[copylen - 1]))) { copylen--; } } + if (copylen < 0) copylen = 0; dst = mrb_str_new(mrb, sptr, (mrb_int)copylen); mrb_ary_push(mrb, ary, dst); return slen; @@ -980,7 +1002,7 @@ alias: case 'm': dir = PACK_DIR_BASE64; type = PACK_TYPE_STRING; - flags |= PACK_FLAG_WIDTH; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2; break; case 'N': /* = "L>" */ dir = PACK_DIR_LONG; @@ -1050,13 +1072,14 @@ alias: /* read suffix [0-9*_!<>] */ while (tmpl->idx < tlen) { ch = tptr[tmpl->idx++]; - if (isdigit(ch)) { + if (ISDIGIT(ch)) { count = ch - '0'; - while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { - count = count * 10 + (tptr[tmpl->idx++] - '0'); - if (count < 0) { - mrb_raisef(mrb, E_RUNTIME_ERROR, "too big template length"); + 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; } continue; /* special case */ } else if (ch == '*') { @@ -1122,13 +1145,16 @@ 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); + } #ifndef MRB_WITHOUT_FLOAT - } else if (type == PACK_TYPE_FLOAT) { + else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { - o = mrb_funcall(mrb, o, "to_f", 0); + mrb_float f = mrb_to_flo(mrb, o); + o = mrb_float_value(mrb, f); } + } #endif - } else if (type == PACK_TYPE_STRING) { + 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))); } @@ -1170,7 +1196,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) default: break; } - if (dir == PACK_DIR_STR) { /* always consumes 1 entry */ + if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64) { /* always consumes 1 entry */ aidx++; break; } @@ -1188,7 +1214,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) } static mrb_value -mrb_pack_unpack(mrb_state *mrb, mrb_value str) +pack_unpack(mrb_state *mrb, mrb_value str, int single) { mrb_value result; struct tmpl tmpl; @@ -1223,6 +1249,9 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) 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; } continue; } @@ -1249,9 +1278,6 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) 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; #ifndef MRB_WITHOUT_FLOAT case PACK_DIR_FLOAT: srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags); @@ -1270,19 +1296,39 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) count--; } } + if (single) break; } + if (single) { + if (RARRAY_LEN(result) > 0) { + return RARRAY_PTR(result)[0]; + } + return mrb_nil_value(); + } return result; } +static mrb_value +mrb_pack_unpack(mrb_state *mrb, mrb_value str) +{ + return pack_unpack(mrb, str, 0); +} + +static mrb_value +mrb_pack_unpack1(mrb_state *mrb, mrb_value str) +{ + return pack_unpack(mrb, str, 1); +} + void mrb_mruby_pack_gem_init(mrb_state *mrb) { - littleendian = check_little_endian(); + check_little_endian(); make_base64_dec_tab(); 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)); + mrb_define_method(mrb, mrb->string_class, "unpack1", mrb_pack_unpack1, MRB_ARGS_REQ(1)); } void |
