https://github.com/kaitai-io/kaitai_struct_cpp_stl_runtime/commit/c01f5300159a698b6e706caba21e1965d5fc94a7.patch diff --git a/lib/kaitai/kaitai/kaitaistream.cpp b/lib/kaitai/kaitai/kaitaistream.cpp index bd914c3..d3b2fcd 100644 --- a/lib/kaitai/kaitai/kaitaistream.cpp +++ b/lib/kaitai/kaitai/kaitaistream.cpp @@ -32,10 +32,57 @@ #include <byteswap.h> #endif +#include <cstring> // std::memcpy #include <iostream> #include <vector> #include <stdexcept> +#ifdef KAITAI_STREAM_H_CPP11_SUPPORT +#include <type_traits> // std::enable_if, std::is_trivially_copyable, std::is_trivially_constructible + +// Taken from https://en.cppreference.com/w/cpp/numeric/bit_cast#Possible_implementation +// (only adjusted for C++11 compatibility) +template<class To, class From> +typename std::enable_if< + sizeof(To) == sizeof(From) && + std::is_trivially_copyable<From>::value && + std::is_trivially_copyable<To>::value, + To +>::type +// constexpr support needs compiler magic +static bit_cast(const From &src) noexcept +{ + static_assert(std::is_trivially_constructible<To>::value, + "This implementation additionally requires " + "destination type to be trivially constructible"); + + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} +#else +// The following implementation of `StaticAssert` was inspired by https://stackoverflow.com/a/6765840 + +// empty default template +template <bool b> +struct StaticAssert; + +// template specialized on true +template <> +struct StaticAssert<true> {}; + +template<class To, class From> +To +static bit_cast(const From &src) +{ + StaticAssert<sizeof(To) == sizeof(From)>(); + + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} +#endif + kaitai::kstream::kstream(std::istream *io) { m_io = io; init(); @@ -263,7 +310,7 @@ float kaitai::kstream::read_f4be() { #if __BYTE_ORDER == __LITTLE_ENDIAN t = bswap_32(t); #endif - return reinterpret_cast<float &>(t); + return bit_cast<float>(t); } double kaitai::kstream::read_f8be() { @@ -272,7 +319,7 @@ double kaitai::kstream::read_f8be() { #if __BYTE_ORDER == __LITTLE_ENDIAN t = bswap_64(t); #endif - return reinterpret_cast<double &>(t); + return bit_cast<double>(t); } // ........................................................................ @@ -285,7 +332,7 @@ float kaitai::kstream::read_f4le() { #if __BYTE_ORDER == __BIG_ENDIAN t = bswap_32(t); #endif - return reinterpret_cast<float &>(t); + return bit_cast<float>(t); } double kaitai::kstream::read_f8le() { @@ -294,7 +341,7 @@ double kaitai::kstream::read_f8le() { #if __BYTE_ORDER == __BIG_ENDIAN t = bswap_64(t); #endif - return reinterpret_cast<double &>(t); + return bit_cast<double>(t); } // ======================================================================== diff --git a/lib/kaitai/kaitai/kaitaistream.h b/lib/kaitai/kaitai/kaitaistream.h index c8b5a3a..d58ae8e 100644 --- a/lib/kaitai/kaitai/kaitaistream.h +++ b/lib/kaitai/kaitai/kaitaistream.h @@ -4,6 +4,11 @@ // Kaitai Struct runtime API version: x.y.z = 'xxxyyyzzz' decimal #define KAITAI_STRUCT_VERSION 11000L +// check for C++11 support - https://stackoverflow.com/a/40512515 +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define KAITAI_STREAM_H_CPP11_SUPPORT +#endif + #include <istream> #include <sstream> #include <stdint.h>