diff --git a/inkcpp/CMakeLists.txt b/inkcpp/CMakeLists.txt index 7ea88661..305db42a 100644 --- a/inkcpp/CMakeLists.txt +++ b/inkcpp/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCES system.cpp value.h value.cpp string_table.h string_table.cpp avl_array.h + header.cpp ) source_group(Collections REGULAR_EXPRESSION collections/.*) add_library(inkcpp ${SOURCES}) @@ -36,4 +37,4 @@ install(TARGETS inkcpp DESTINATION lib) # Unreal installation install(DIRECTORY "include/" DESTINATION "inkcpp/Source/inkcpp/Public/ink/" COMPONENT unreal) -install(FILES ${SOURCES} DESTINATION "inkcpp/Source/inkcpp/Private/ink/" COMPONENT unreal) \ No newline at end of file +install(FILES ${SOURCES} DESTINATION "inkcpp/Source/inkcpp/Private/ink/" COMPONENT unreal) diff --git a/inkcpp/header.cpp b/inkcpp/header.cpp new file mode 100644 index 00000000..e80b2858 --- /dev/null +++ b/inkcpp/header.cpp @@ -0,0 +1,38 @@ +#include "header.h" +#include "version.h" + +namespace ink::internal { + + header header::parse_header(const char *data) + { + header res; + const char* ptr = data; + res.endien = *reinterpret_cast(ptr); + ptr += sizeof(header::endian_types); + + using v_t = decltype(header::ink_version_number); + using vcpp_t = decltype(header::ink_bin_version_number); + + if (res.endien == header::endian_types::same) { + res.ink_version_number = + *reinterpret_cast(ptr); + ptr += sizeof(v_t); + res.ink_bin_version_number = + *reinterpret_cast(ptr); + + } else if (res.endien == header::endian_types::differ) { + res.ink_version_number = + swap_bytes(*reinterpret_cast(ptr)); + ptr += sizeof(v_t); + res.ink_bin_version_number = + swap_bytes(*reinterpret_cast(ptr)); + } else { + throw ink_exception("Failed to parse endian encoding!"); + } + + if (res.ink_bin_version_number != InkBinVersion) { + throw ink_exception("InkCpp-version mismatch: file was compiled with different InkCpp-version!"); + } + return res; + } +} diff --git a/inkcpp/runner_impl.cpp b/inkcpp/runner_impl.cpp index f97b7326..60f07bb0 100644 --- a/inkcpp/runner_impl.cpp +++ b/inkcpp/runner_impl.cpp @@ -3,6 +3,7 @@ #include "command.h" #include "choice.h" #include "globals_impl.h" +#include "header.h" namespace ink::runtime { @@ -23,11 +24,15 @@ namespace ink::runtime::internal template inline T runner_impl::read() { + using header = ink::internal::header; // Sanity inkAssert(_ptr + sizeof(T) <= _story->end(), "Unexpected EOF in Ink execution"); // Read memory T val = *(const T*)_ptr; + if (_story->get_header().endien == header::endian_types::differ) { + val = header::swap_bytes(val); + } // Advance ip _ptr += sizeof(T); @@ -1067,4 +1072,4 @@ namespace ink::runtime::internal return out; } #endif -} \ No newline at end of file +} diff --git a/inkcpp/story_impl.cpp b/inkcpp/story_impl.cpp index 7a905a75..ba0d3290 100644 --- a/inkcpp/story_impl.cpp +++ b/inkcpp/story_impl.cpp @@ -2,6 +2,7 @@ #include "platform.h" #include "runner_impl.h" #include "globals_impl.h" +#include "version.h" #ifdef INK_ENABLE_STL #include @@ -24,6 +25,7 @@ namespace ink::runtime namespace ink::runtime::internal { + #ifdef INK_ENABLE_STL unsigned char* read_file_into_memory(const char* filename, size_t* read) { @@ -177,8 +179,11 @@ namespace ink::runtime::internal void story_impl::setup_pointers() { - // String table is after the version information - _string_table = (char*)_file + sizeof(int); + using header = ink::internal::header; + _header = header::parse_header(reinterpret_cast(_file)); + + // String table is after the header + _string_table = (char*)_file + header::Size; // Pass over strings const char* ptr = _string_table; @@ -252,4 +257,4 @@ namespace ink::runtime::internal } }*/ } -} \ No newline at end of file +} diff --git a/inkcpp/story_impl.h b/inkcpp/story_impl.h index abe0ee1e..c07d7e6b 100644 --- a/inkcpp/story_impl.h +++ b/inkcpp/story_impl.h @@ -4,6 +4,7 @@ #include #include "types.h" #include "story.h" +#include "header.h" namespace ink::runtime::internal { @@ -11,6 +12,7 @@ namespace ink::runtime::internal class story_impl : public story { public: + #ifdef INK_ENABLE_STL story_impl(const char* filename); #endif @@ -34,6 +36,8 @@ namespace ink::runtime::internal virtual globals new_globals() override; virtual runner new_runner(globals store = nullptr) override; + + const ink::internal::header& get_header() const { return _header; } private: void setup_pointers(); @@ -42,6 +46,8 @@ namespace ink::runtime::internal unsigned char* _file; size_t _length; + ink::internal::header _header; + // string table const char* _string_table; @@ -63,4 +69,4 @@ namespace ink::runtime::internal // whether we need to delete our binary data after we destruct bool _managed; }; -} \ No newline at end of file +} diff --git a/inkcpp_compiler/binary_emitter.cpp b/inkcpp_compiler/binary_emitter.cpp index 465f7fc6..ffa4b58e 100644 --- a/inkcpp_compiler/binary_emitter.cpp +++ b/inkcpp_compiler/binary_emitter.cpp @@ -1,5 +1,8 @@ #include "binary_emitter.h" +#include "header.h" +#include "version.h" + #include #include #include @@ -173,7 +176,12 @@ namespace ink::compiler::internal void binary_emitter::output(std::ostream& out) { // Write the ink version - out.write((const char*)&_ink_version, sizeof(int)); + // TODO: define this order in header? + using header = ink::internal::header; + header::endian_types same = header::endian_types::same; + out.write((const char*)&same, sizeof(decltype(same))); + out.write((const char*)&_ink_version, sizeof(decltype(_ink_version))); + out.write((const char*)&ink::InkBinVersion, sizeof(decltype(ink::InkBinVersion))); // Write the string table _strings.write_to(out); diff --git a/inkcpp_compiler/emitter.h b/inkcpp_compiler/emitter.h index 2d888ca9..45e07694 100644 --- a/inkcpp_compiler/emitter.h +++ b/inkcpp_compiler/emitter.h @@ -78,4 +78,4 @@ namespace ink::compiler::internal // ink version int _ink_version; }; -} \ No newline at end of file +} diff --git a/shared/private/header.h b/shared/private/header.h new file mode 100644 index 00000000..faae2d4f --- /dev/null +++ b/shared/private/header.h @@ -0,0 +1,31 @@ +#pragma once + +#include "system.h" + +namespace ink::internal { + + struct header { + static header parse_header(const char* data); + + template + static T swap_bytes(const T& value) { + char data[sizeof(T)]; + for (int i = 0; i < sizeof(T); ++i) { + data[i] = reinterpret_cast(&value)[sizeof(T)-1-i]; + } + return *reinterpret_cast(data); + } + + enum class endian_types: uint16_t { + none = 0, + same = 0x0001, + differ = 0x0100 + } endien = endian_types::none; + uint32_t ink_version_number = 0; + uint32_t ink_bin_version_number = 0; + static constexpr size_t Size = ///< actual data size of Header, + /// because padding of struct may + /// differ between platforms + sizeof(uint16_t) + 2 * sizeof(uint32_t); + }; +} diff --git a/shared/public/version.h b/shared/public/version.h new file mode 100644 index 00000000..ae3a1638 --- /dev/null +++ b/shared/public/version.h @@ -0,0 +1,7 @@ +#pragma once + +#include "system.h" + +namespace ink { + constexpr uint32_t InkBinVersion = 0; +};