summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTomoyuki Sahara <[email protected]>2014-06-15 19:54:08 +0900
committerTomoyuki Sahara <[email protected]>2014-06-15 19:54:08 +0900
commit5b65ca3ebb3fb718138e1d23c4881a129b8606e2 (patch)
tree88be8c9a72e80f0fe49eaf67239bdbcb97333ace
parenta0c4ca24067dc23ecbae59665e83cf49b8fa5bb1 (diff)
parent7b2611ea28aad709d16f6196baabbdbdbd806087 (diff)
downloadmruby-5b65ca3ebb3fb718138e1d23c4881a129b8606e2.tar.gz
mruby-5b65ca3ebb3fb718138e1d23c4881a129b8606e2.zip
Merge pull request #5 from take-cheeze/float
Add full support of float templates.
-rw-r--r--README.md7
-rw-r--r--src/pack.c149
-rw-r--r--test/pack.rb33
3 files changed, 182 insertions, 7 deletions
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)
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