diff options
| author | Tomoyuki Sahara <[email protected]> | 2014-06-15 19:54:08 +0900 |
|---|---|---|
| committer | Tomoyuki Sahara <[email protected]> | 2014-06-15 19:54:08 +0900 |
| commit | 5b65ca3ebb3fb718138e1d23c4881a129b8606e2 (patch) | |
| tree | 88be8c9a72e80f0fe49eaf67239bdbcb97333ace | |
| parent | a0c4ca24067dc23ecbae59665e83cf49b8fa5bb1 (diff) | |
| parent | 7b2611ea28aad709d16f6196baabbdbdbd806087 (diff) | |
| download | mruby-5b65ca3ebb3fb718138e1d23c4881a129b8606e2.tar.gz mruby-5b65ca3ebb3fb718138e1d23c4881a129b8606e2.zip | |
Merge pull request #5 from take-cheeze/float
Add full support of float templates.
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | src/pack.c | 149 | ||||
| -rw-r--r-- | test/pack.rb | 33 |
3 files changed, 182 insertions, 7 deletions
@@ -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) diff --git a/src/pack.c b/src/pack.c index 3e56454f2..69cf740ff 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 */ @@ -234,18 +234,116 @@ 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_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + 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 - #error unsupported + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); #else - for(i = 0; i < 8; i++){ - RSTRING_PTR(str)[sidx+i] = buffer[i]; + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } +#endif } + + 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) +{ + int i; + float f; + uint8_t *buffer = (uint8_t *)&f; + str = str_len_ensure(mrb, str, sidx + 4); + f = 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]; + } +#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]; + } +#endif + } + + 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) { int copylen, slen, padlen; @@ -574,12 +672,42 @@ 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 = 4; + 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 | 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; type = PACK_TYPE_STRING; @@ -756,6 +884,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; } @@ -826,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 7789fb446..c7899e2d7 100644 --- a/test/pack.rb +++ b/test/pack.rb @@ -88,3 +88,36 @@ end assert('issue #1') do [1, 2].pack("nn") == "\000\001\000\002" end + +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 + +assert 'pack float' do + assert_pack 'e', "\x00\x00@@", [3.0] + assert_pack 'g', "@@\x00\x00", [3.0] + + 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_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 |
