From 9a0ac7c7fd06a60f0e61b88828eaa59c0ee30fdd Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 2 Dec 2022 03:53:23 +0100 Subject: serialize: work on recovering from corrupted saves --- serialize/CMakeLists.txt | 10 ++++++---- serialize/binary-reader.hpp | 14 +++++++------- serialize/binary-reader.inl | 26 ++++++++++++------------- serialize/binary-serializer.hpp | 10 ++-------- serialize/world-reader.cpp | 43 ++++++++++++++++++++--------------------- 5 files changed, 49 insertions(+), 54 deletions(-) (limited to 'serialize') diff --git a/serialize/CMakeLists.txt b/serialize/CMakeLists.txt index 501dc448..7b7efb76 100644 --- a/serialize/CMakeLists.txt +++ b/serialize/CMakeLists.txt @@ -5,14 +5,16 @@ target_link_libraries( ${self}_o PUBLIC Magnum::Magnum nlohmann_json::nlohmann_json + fmt::fmt ) + +if(MSVC) + add_compile_options(-EHsc) +endif() + add_library(${self} STATIC dummy.cc) target_link_libraries(${self} PUBLIC ${self}_o floormat-loader floormat) if(FLOORMAT_PRECOMPILED-HEADERS) target_precompile_headers(${self}_o PRIVATE precomp.hpp) endif() - -if(MSVC) - add_compile_options(-EHsc) -endif() diff --git a/serialize/binary-reader.hpp b/serialize/binary-reader.hpp index 530d9f0c..0c597772 100644 --- a/serialize/binary-reader.hpp +++ b/serialize/binary-reader.hpp @@ -26,12 +26,12 @@ template struct binary_reader final { template explicit constexpr binary_reader(const Seq& seq) noexcept; constexpr binary_reader(It begin, It end) noexcept; - constexpr void assert_end() noexcept; + constexpr void assert_end() noexcept(false); - template constexpr T read() noexcept; - template constexpr std::array read() noexcept; constexpr std::size_t bytes_read() const noexcept { return num_bytes_read; } - template constexpr auto read_asciiz_string() noexcept; + template constexpr T read() noexcept(false); + template constexpr std::array read() noexcept(false); + template constexpr auto read_asciiz_string() noexcept(false); binary_reader(binary_reader&&) noexcept = default; binary_reader& operator=(binary_reader&&) noexcept = default; @@ -44,14 +44,14 @@ private: }; template -void operator<<(T& x, binary_reader& reader) noexcept; +void operator<<(T& x, binary_reader& reader) noexcept(false); template -binary_reader& operator>>(binary_reader& reader, T& x) noexcept; +binary_reader& operator>>(binary_reader& reader, T& x) noexcept(false); template binary_reader(It&& begin, It&& end) -> binary_reader>; template -binary_reader(Array&& array) -> binary_reader>; +binary_reader(const Array& array) -> binary_reader>; } // namespace floormat::Serialize diff --git a/serialize/binary-reader.inl b/serialize/binary-reader.inl index d1abcec9..7b831f30 100644 --- a/serialize/binary-reader.inl +++ b/serialize/binary-reader.inl @@ -1,26 +1,26 @@ #pragma once #include "binary-reader.hpp" -#include "compat/assert.hpp" +#include "compat/exception.hpp" namespace floormat::Serialize { template template constexpr binary_reader::binary_reader(const Seq& seq) noexcept - : it{std::begin(seq)}, end{std::end(seq)} + : it{std::cbegin(seq)}, end{std::cend(seq)} {} template constexpr binary_reader::binary_reader(It begin, It end) noexcept : - it{begin}, end{end} + it{std::move(begin)}, end{std::move(end)} {} template template -constexpr T binary_reader::read() noexcept +constexpr T binary_reader::read() noexcept(false) { constexpr std::size_t N = sizeof(T); - fm_assert((std::ptrdiff_t)N <= std::distance(it, end)); + fm_soft_assert((std::ptrdiff_t)N <= std::distance(it, end)); num_bytes_read += N; char buf[N]; for (std::size_t i = 0; i < N; i++) @@ -30,12 +30,12 @@ constexpr T binary_reader::read() noexcept template template -constexpr std::array binary_reader::read() noexcept +constexpr std::array binary_reader::read() noexcept(false) { std::array array; if (std::is_constant_evaluated()) array = {}; - fm_assert(N <= (std::size_t)std::distance(it, end)); + fm_soft_assert(N <= (std::size_t)std::distance(it, end)); num_bytes_read += N; for (std::size_t i = 0; i < N; i++) array[i] = *it++; @@ -43,27 +43,27 @@ constexpr std::array binary_reader::read() noexcept } template -constexpr void binary_reader::assert_end() noexcept +constexpr void binary_reader::assert_end() noexcept(false) { - fm_assert(it == end); + fm_soft_assert(it == end); } template -binary_reader& operator>>(binary_reader& reader, T& x) noexcept +binary_reader& operator>>(binary_reader& reader, T& x) noexcept(false) { x = reader.template read(); return reader; } template -void operator<<(T& x, binary_reader& reader) noexcept +void operator<<(T& x, binary_reader& reader) noexcept(false) { x = reader.template read(); } template template -constexpr auto binary_reader::read_asciiz_string() noexcept +constexpr auto binary_reader::read_asciiz_string() noexcept(false) { static_assert(MAX > 0); @@ -84,7 +84,7 @@ constexpr auto binary_reader::read_asciiz_string() noexcept return ret; } } - fm_abort("can't find string terminator"); + fm_throw("can't find string terminator"_cf); } } // namespace floormat::Serialize diff --git a/serialize/binary-serializer.hpp b/serialize/binary-serializer.hpp index 057b3c4d..338173c2 100644 --- a/serialize/binary-serializer.hpp +++ b/serialize/binary-serializer.hpp @@ -10,12 +10,6 @@ namespace floormat::Serialize { static_assert(std::endian::native == std::endian::big || std::endian::native == std::endian::little); -enum class value_type : unsigned char { - none, uc, u8, u16, u32, u64, - f32, f64, - COUNT -}; - template struct make_integer; template using make_integer_t = typename make_integer::type; @@ -39,13 +33,13 @@ concept serializable = requires(T x) { }; template -constexpr inline T maybe_byteswap(T x) +constexpr inline T maybe_byteswap(T x) noexcept { return x; } template -constexpr inline T maybe_byteswap(T x) +constexpr inline T maybe_byteswap(T x) noexcept { if constexpr(std::endian::native == std::endian::big) return std::byteswap(x); diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index d95f81b5..b6cf8839 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -6,6 +6,7 @@ #include "loader/scenery.hpp" #include "src/tile-atlas.hpp" #include "src/anim-atlas.hpp" + #include namespace { @@ -66,23 +67,23 @@ void reader_state::read_sceneries(reader_t& s) std::uint16_t magic; magic << s; if (magic != scenery_magic) - fm_abort("bad scenery magic"); + fm_throw("bad scenery magic"_cf); atlasid sz; sz << s; - fm_assert(sz < scenery_id_max); + fm_soft_assert(sz < scenery_id_max); sceneries.resize(sz); std::size_t i = 0; while (i < sz) { std::uint8_t num; num << s; - fm_assert(num > 0); + fm_soft_assert(num > 0); auto str = s.read_asciiz_string(); const auto sc_ = loader.scenery(str); for (std::size_t n = 0; n < num; n++) { atlasid id; id << s; - fm_assert(id < sz); - fm_assert(!sceneries[id]); + fm_soft_assert(id < sz); + fm_soft_assert(!sceneries[id]); scenery_proto sc = sc_; bool short_frame = read_scenery_flags(s, sc.frame); fm_debug_assert(sc.atlas != nullptr); @@ -90,14 +91,12 @@ void reader_state::read_sceneries(reader_t& s) sc.frame.frame = s.read(); else sc.frame.frame << s; - fm_assert(sc.frame.frame < sc.atlas->info().nframes); + fm_soft_assert(sc.frame.frame < sc.atlas->info().nframes); sceneries[id] = sc; } i += num; } - fm_assert(i == sz); - for (const scenery_proto& sc : sceneries) - fm_assert(sc); + fm_soft_assert(i == sz); } const std::shared_ptr& reader_state::lookup_atlas(atlasid id) @@ -105,7 +104,7 @@ const std::shared_ptr& reader_state::lookup_atlas(atlasid id) if (id < atlases.size()) return atlases[id]; else - fm_abort("no such atlas: '%zu'", (std::size_t)id); + fm_throw("no such atlas: '{}'"_cf, id); } const scenery_proto& reader_state::lookup_scenery(atlasid id) @@ -113,7 +112,7 @@ const scenery_proto& reader_state::lookup_scenery(atlasid id) if (id < sceneries.size()) return sceneries[id]; else - fm_abort("no such scenery: '%zu'", (std::size_t)id); + fm_throw("no such scenery: '{}'"_cf, id); } void reader_state::read_chunks(reader_t& s) @@ -125,7 +124,7 @@ void reader_state::read_chunks(reader_t& s) std::decay_t magic; magic << s; if (magic != chunk_magic) - fm_abort("bad chunk magic"); + fm_throw("bad chunk magic"_cf); chunk_coords coord; coord.x << s; coord.y << s; @@ -145,7 +144,7 @@ void reader_state::read_chunks(reader_t& s) ? s.read() : std::uint8_t(s.read()); auto atlas = lookup_atlas(id); - fm_assert(v < atlas->num_tiles()); + fm_soft_assert(v < atlas->num_tiles()); return { atlas, v }; }; @@ -186,7 +185,7 @@ void reader_state::read_chunks(reader_t& s) t.pass_mode() = x; break; default: [[unlikely]] - fm_abort("bad pass mode '%zu' for tile %zu", i, (std::size_t)x); + fm_throw("bad pass mode '{}' for tile {}"_cf, i, x); } } } @@ -196,11 +195,11 @@ void reader_state::deserialize_world(ArrayView buf) { auto s = binary_reader{buf}; if (!!::memcmp(s.read().data(), file_magic, std::size(file_magic)-1)) - fm_abort("bad magic"); + fm_throw("bad magic"_cf); proto_t proto; proto << s; if (!(proto >= min_proto_version && proto <= proto_version)) - fm_abort("bad proto version '%zu' (should be between '%zu' and '%zu')", + fm_throw("bad proto version '{}' (should be between '{}' and '{}')"_cf, (std::size_t)proto, (std::size_t)min_proto_version, (std::size_t)proto_version); PROTO = proto; read_atlases(s); @@ -225,17 +224,17 @@ world world::deserialize(StringView filename) (void)::strerror_s(buf, std::size(buf), errno); #endif }; - fm_assert(filename.flags() & StringViewFlag::NullTerminated); + fm_soft_assert(filename.flags() & StringViewFlag::NullTerminated); FILE_raii f = ::fopen(filename.data(), "rb"); if (!f) { get_error_string(errbuf); - fm_abort("fopen(\"%s\", \"r\"): %s", filename.data(), errbuf); + fm_throw("fopen(\"{}\", \"r\"): {}"_cf, filename.data(), errbuf); } if (int ret = ::fseek(f, 0, SEEK_END); ret != 0) { get_error_string(errbuf); - fm_abort("fseek(SEEK_END): %s", errbuf); + fm_throw("fseek(SEEK_END): {}"_cf, errbuf); } std::size_t len; if (auto len_ = ::ftell(f); len_ >= 0) @@ -243,19 +242,19 @@ world world::deserialize(StringView filename) else { get_error_string(errbuf); - fm_abort("ftell: %s", errbuf); + fm_throw("ftell: {}"_cf, errbuf); } if (int ret = ::fseek(f, 0, SEEK_SET); ret != 0) { get_error_string(errbuf); - fm_abort("fseek(SEEK_SET): %s", errbuf); + fm_throw("fseek(SEEK_SET): {}"_cf, errbuf); } auto buf_ = std::make_unique(len); if (auto ret = ::fread(&buf_[0], 1, len, f); ret != len) { get_error_string(errbuf); - fm_abort("fread short read: %s", errbuf); + fm_throw("fread short read: {}"_cf, errbuf); } world w; -- cgit v1.2.3