diff --git a/Common.cmake b/Common.cmake index 05200f8..255c230 100644 --- a/Common.cmake +++ b/Common.cmake @@ -13,5 +13,14 @@ endif() # This method was taken from https://www.pragmaticlinux.com/2022/07/enable-compiler-warnings-with-cmake/ target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W4 /WX> - $<$>:-Wall -Wextra -Wpedantic -Werror> + $<$>: + -Wall -Wextra -Wpedantic -Werror + # See : + # + # > Level 1: (...) it has very few false negatives. However, it has many false positives. + # + # If we encounter into false positives in the future, we can increase the level, but let's + # start with the most aggressive option to make sure we don't miss anything. + -fstrict-aliasing -Wstrict-aliasing=1 + > ) diff --git a/kaitai/kaitaistream.cpp b/kaitai/kaitaistream.cpp index bd914c3..d3b2fcd 100644 --- a/kaitai/kaitaistream.cpp +++ b/kaitai/kaitaistream.cpp @@ -32,10 +32,57 @@ #include #endif +#include // std::memcpy #include #include #include +#ifdef KAITAI_STREAM_H_CPP11_SUPPORT +#include // 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 +typename std::enable_if< + sizeof(To) == sizeof(From) && + std::is_trivially_copyable::value && + std::is_trivially_copyable::value, + To +>::type +// constexpr support needs compiler magic +static bit_cast(const From &src) noexcept +{ + static_assert(std::is_trivially_constructible::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 +struct StaticAssert; + +// template specialized on true +template <> +struct StaticAssert {}; + +template +To +static bit_cast(const From &src) +{ + StaticAssert(); + + 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(t); + return bit_cast(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(t); + return bit_cast(t); } // ........................................................................ @@ -285,7 +332,7 @@ float kaitai::kstream::read_f4le() { #if __BYTE_ORDER == __BIG_ENDIAN t = bswap_32(t); #endif - return reinterpret_cast(t); + return bit_cast(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(t); + return bit_cast(t); } // ======================================================================== diff --git a/kaitai/kaitaistream.h b/kaitai/kaitaistream.h index c8b5a3a..d58ae8e 100644 --- a/kaitai/kaitaistream.h +++ b/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 #include #include