summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-pack/src/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-pack/src/pack.c')
-rw-r--r--mrbgems/mruby-pack/src/pack.c191
1 files changed, 108 insertions, 83 deletions
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c
index 5caf7b62b..159ba09ac 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 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");
}
@@ -509,8 +529,8 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
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));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %d bytes, given %d bytes)",
+ n, *lenp);
}
*lenp = n--;
if (n != 0) {
@@ -607,7 +627,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u
}
}
else if (!(flags & PACK_FLAG_a)) { /* "A" */
- while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) {
+ while (copylen > 0 && (sptr[copylen - 1] == '\0' || ISSPACE(sptr[copylen - 1]))) {
copylen--;
}
}
@@ -956,7 +976,7 @@ 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)));
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %d", (int)sizeof(int));
}
break;
case 'i':
@@ -965,7 +985,7 @@ 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)));
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %d", (int)sizeof(int));
}
break;
case 'L':
@@ -982,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;
@@ -1052,21 +1072,21 @@ 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) {
+ 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 == '*') {
count = -1;
} else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
if (strchr("sSiIlLqQ", (int)t) == NULL) {
- char ch_str = (char)ch;
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlLqQ", mrb_str_new(mrb, &ch_str, 1));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlLqQ", ch);
}
if (ch == '_' || ch == '!') {
flags |= PACK_FLAG_s;
@@ -1135,7 +1155,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
#endif
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 %T into String", o);
}
}
@@ -1175,7 +1195,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;
}
@@ -1228,6 +1248,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
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;
}
@@ -1254,9 +1277,6 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
case PACK_DIR_QUAD:
srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags);
break;
- case PACK_DIR_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);
@@ -1278,7 +1298,12 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
if (single) break;
}
- if (single) return RARRAY_PTR(result)[0];
+ if (single) {
+ if (RARRAY_LEN(result) > 0) {
+ return RARRAY_PTR(result)[0];
+ }
+ return mrb_nil_value();
+ }
return result;
}
@@ -1297,7 +1322,7 @@ mrb_pack_unpack1(mrb_state *mrb, mrb_value str)
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));