diff --git a/Files.cmake b/Files.cmake index f355755a..70c030f7 100644 --- a/Files.cmake +++ b/Files.cmake @@ -142,6 +142,7 @@ LIST (APPEND msgpackc_HEADERS include/msgpack/predef/version_number.h include/msgpack/sbuffer.h include/msgpack/sysdep.h + include/msgpack/timestamp.h include/msgpack/unpack.h include/msgpack/unpack_define.h include/msgpack/unpack_template.h diff --git a/include/msgpack/pack.h b/include/msgpack/pack.h index 0924bff7..f2dddb3c 100644 --- a/include/msgpack/pack.h +++ b/include/msgpack/pack.h @@ -12,6 +12,7 @@ #include "pack_define.h" #include "object.h" +#include "timestamp.h" #include #ifdef __cplusplus @@ -98,6 +99,8 @@ static int msgpack_pack_bin_body(msgpack_packer* pk, const void* b, size_t l); static int msgpack_pack_ext(msgpack_packer* pk, size_t l, int8_t type); static int msgpack_pack_ext_body(msgpack_packer* pk, const void* b, size_t l); +static int msgpack_pack_timestamp(msgpack_packer* pk, const msgpack_timestamp* d); + MSGPACK_DLLEXPORT int msgpack_pack_object(msgpack_packer* pk, msgpack_object d); diff --git a/include/msgpack/pack_template.h b/include/msgpack/pack_template.h index 17abb521..5e2313cb 100644 --- a/include/msgpack/pack_template.h +++ b/include/msgpack/pack_template.h @@ -890,6 +890,34 @@ msgpack_pack_inline_func(_ext_body)(msgpack_pack_user x, const void* b, size_t l msgpack_pack_append_buffer(x, (const unsigned char*)b, l); } +msgpack_pack_inline_func(_timestamp)(msgpack_pack_user x, const msgpack_timestamp* d) +{ + if ((((int64_t)d->tv_sec) >> 34) == 0) { + uint64_t data64 = ((uint64_t) d->tv_nsec << 34) | d->tv_sec; + if ((data64 & 0xffffffff00000000L) == 0) { + // timestamp 32 + char buf[4]; + uint32_t data32 = (uint32_t)data64; + msgpack_pack_ext(x, 4, -1); + _msgpack_store32(buf, data32); + msgpack_pack_append_buffer(x, buf, 4); + } else { + // timestamp 64 + char buf[8]; + msgpack_pack_ext(x, 8, -1); + _msgpack_store64(buf, data64); + msgpack_pack_append_buffer(x, buf, 8); + } + } else { + // timestamp 96 + char buf[12]; + _msgpack_store32(&buf[0], d->tv_nsec); + _msgpack_store64(&buf[4], d->tv_sec); + msgpack_pack_ext(x, 12, -1); + msgpack_pack_append_buffer(x, buf, 12); + } +} + #undef msgpack_pack_inline_func #undef msgpack_pack_user #undef msgpack_pack_append_buffer diff --git a/include/msgpack/timestamp.h b/include/msgpack/timestamp.h new file mode 100644 index 00000000..4d7df83d --- /dev/null +++ b/include/msgpack/timestamp.h @@ -0,0 +1,54 @@ +/* + * MessagePack for C TimeStamp + * + * Copyright (C) 2018 KONDO Takatoshi + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef MSGPACK_TIMESTAMP_H +#define MSGPACK_TIMESTAMP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct msgpack_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; +} msgpack_timestamp; + +static inline bool msgpack_object_to_timestamp(const msgpack_object* obj, msgpack_timestamp* ts) { + if (obj->type != MSGPACK_OBJECT_EXT) return false; + if (obj->via.ext.type != -1) return false; + switch (obj->via.ext.size) { + case 4: + ts->tv_nsec = 0; + _msgpack_load32(uint32_t, obj->via.ext.ptr, &ts->tv_sec); + return true; + case 8: { + uint64_t value; + _msgpack_load64(uint64_t, obj->via.ext.ptr, &value); + ts->tv_nsec = (uint32_t)(value >> 34); + ts->tv_sec = value & 0x00000003ffffffffL; + return true; + } + case 12: + _msgpack_load32(uint32_t, obj->via.ext.ptr, &ts->tv_nsec); + _msgpack_load64(int64_t, obj->via.ext.ptr + 4, &ts->tv_sec); + return true; + default: + return false; + } +} + + +#ifdef __cplusplus +} +#endif + +#endif /* msgpack/timestamp.h */ diff --git a/test/msgpack_c.cpp b/test/msgpack_c.cpp index 4029273d..c979177a 100644 --- a/test/msgpack_c.cpp +++ b/test/msgpack_c.cpp @@ -627,6 +627,105 @@ TEST(MSGPACKC, simple_buffer_fixext_4byte_65536) msgpack_sbuffer_destroy(&sbuf); } +TEST(MSGPACKC, simple_buffer_timestamp_32) +{ + msgpack_timestamp ts = { + 0xffffffff, + 0 + }; + + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + msgpack_packer pk; + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + msgpack_pack_timestamp(&pk, &ts); + msgpack_zone z; + msgpack_zone_init(&z, 2048); + msgpack_object obj; + msgpack_unpack_return ret = + msgpack_unpack(sbuf.data, sbuf.size, NULL, &z, &obj); + EXPECT_EQ(MSGPACK_UNPACK_SUCCESS, ret); + EXPECT_EQ(MSGPACK_OBJECT_EXT, obj.type); + EXPECT_EQ(4u, obj.via.ext.size); + EXPECT_EQ(-1, obj.via.ext.type); + msgpack_timestamp ts2; + bool r = msgpack_object_to_timestamp(&obj, &ts2); + + EXPECT_TRUE(r); + EXPECT_EQ(ts.tv_sec, ts2.tv_sec); + EXPECT_EQ(ts.tv_nsec, ts2.tv_nsec); + + msgpack_zone_destroy(&z); + msgpack_sbuffer_destroy(&sbuf); +} + +TEST(MSGPACKC, simple_buffer_timestamp_64) +{ + msgpack_timestamp ts = { + 0x3ffffffffL, + 999999999 + }; + + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + msgpack_packer pk; + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + msgpack_pack_timestamp(&pk, &ts); + msgpack_zone z; + msgpack_zone_init(&z, 2048); + msgpack_object obj; + msgpack_unpack_return ret = + msgpack_unpack(sbuf.data, sbuf.size, NULL, &z, &obj); + EXPECT_EQ(MSGPACK_UNPACK_SUCCESS, ret); + EXPECT_EQ(MSGPACK_OBJECT_EXT, obj.type); + EXPECT_EQ(8u, obj.via.ext.size); + EXPECT_EQ(-1, obj.via.ext.type); + msgpack_timestamp ts2; + bool r = msgpack_object_to_timestamp(&obj, &ts2); + + EXPECT_TRUE(r); + EXPECT_EQ(ts.tv_sec, ts2.tv_sec); + EXPECT_EQ(ts.tv_nsec, ts2.tv_nsec); + + msgpack_zone_destroy(&z); + msgpack_sbuffer_destroy(&sbuf); +} + +TEST(MSGPACKC, simple_buffer_timestamp_96) +{ + msgpack_timestamp ts = { + 0x7fffffffffffffffLL, + 999999999 + }; + + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + msgpack_packer pk; + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + msgpack_pack_timestamp(&pk, &ts); + msgpack_zone z; + msgpack_zone_init(&z, 2048); + msgpack_object obj; + msgpack_unpack_return ret = + msgpack_unpack(sbuf.data, sbuf.size, NULL, &z, &obj); + EXPECT_EQ(MSGPACK_UNPACK_SUCCESS, ret); + EXPECT_EQ(MSGPACK_OBJECT_EXT, obj.type); + EXPECT_EQ(12u, obj.via.ext.size); + EXPECT_EQ(-1, obj.via.ext.type); + msgpack_timestamp ts2; + bool r = msgpack_object_to_timestamp(&obj, &ts2); + + EXPECT_TRUE(r); + EXPECT_EQ(ts.tv_sec, ts2.tv_sec); + EXPECT_EQ(ts.tv_nsec, ts2.tv_nsec); + + msgpack_zone_destroy(&z); + msgpack_sbuffer_destroy(&sbuf); +} + TEST(MSGPACKC, simple_buffer_array) { unsigned int array_size = 5;