diff --git a/src/dos_parser.cpp b/src/dos_parser.cpp index f59871e..3fde579 100644 --- a/src/dos_parser.cpp +++ b/src/dos_parser.cpp @@ -8,7 +8,7 @@ // mostly adapted from the ImHex PE pattern made by WerWolv struct DOSHeader { - char signature[2]; + uint16_t signature; uint16_t extraPageSize; uint16_t numberOfPages; uint16_t relocations; @@ -187,7 +187,7 @@ struct OptionalHeader { }; struct COFFHeader { - char signature[4]; + uint32_t signature; ArchitectureType architecture; uint16_t numberOfSections; uint32_t timeDateStamp; @@ -246,10 +246,18 @@ SegmentData getSegmentOffsets(std::span data) { auto ptr = (uint8_t*)data.data(); auto dos_header = (DOSHeader*)ptr; + if(dos_header->signature != 0x5A4D) { // 'ZM' + throw std::runtime_error("invalid dos header"); + } auto coff_header_ptr = (COFFHeader*)(ptr + dos_header->coffHeaderPointer); + if(coff_header_ptr->signature != 0x00004550) { // 'PE\0\0' + throw std::runtime_error("invalid coff_header"); + } auto coff_optional_header = (OptionalHeader*)(ptr + dos_header->coffHeaderPointer + sizeof(COFFHeader)); + if(coff_optional_header->magic != PEFormat::PE32Plus) { + throw std::runtime_error("invalid coff_optional_header"); + } auto section_ptr = (SectionHeader*)(ptr + dos_header->coffHeaderPointer + sizeof(COFFHeader) + coff_header_ptr->sizeOfOptionalHeader); - // assert(coff_header_ptr->optionalHeader.magic == PEFormat::PE32Plus); auto image_base = coff_optional_header->imageBase; std::span dat; diff --git a/src/glStuff.hpp b/src/glStuff.hpp index 3812504..8444702 100644 --- a/src/glStuff.hpp +++ b/src/glStuff.hpp @@ -130,7 +130,7 @@ struct Texture { int n; auto* dat = stbi_load_from_memory(data.data(), data.size(), &width, &height, &n, 4); if(dat == nullptr) { - throw std::runtime_error("missing texture"); + throw std::runtime_error("failed to load texture"); } glBindTexture(GL_TEXTURE_2D, id); diff --git a/src/main.cpp b/src/main.cpp index b41fd0c..9d698e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -499,7 +499,7 @@ static void LoadAtlas(std::span data) { int width, height, n; auto* dat = stbi_load_from_memory(data.data(), data.size(), &width, &height, &n, 4); if(dat == nullptr) { - throw std::runtime_error("invalid texture atlas format"); + throw std::runtime_error("failed to load texture atlas"); } atlas = std::make_unique(); @@ -529,72 +529,77 @@ static void LoadAtlas(std::span data) { static bool load_game(const std::string& path) { if(!std::filesystem::exists(path)) { - ErrorDialog.push("File not found"); return false; } rawData = readFile(path.c_str()); - auto sections = getSegmentOffsets(rawData); + try { + auto sections = getSegmentOffsets(rawData); - assert(sections.data.size() >= sizeof(asset_entry) * 676); - auto assets = std::span((asset_entry*)sections.data.data(), 676); + assert(sections.data.size() >= sizeof(asset_entry) * 676); + auto assets = std::span((asset_entry*)sections.data.data(), 676); - std::vector decryptBuffer; + std::vector decryptBuffer; - auto get_asset = [&](int id) { - assert(id >= 0 && id < 676); - auto& asset = assets[id]; - assert(sections.rdata.size() >= asset.ptr - sections.rdata_pointer_offset + asset.length); - auto dat = sections.rdata.subspan(asset.ptr - sections.rdata_pointer_offset, asset.length); + auto get_asset = [&](int id) { + assert(id >= 0 && id < 676); + auto& asset = assets[id]; + assert(sections.rdata.size() >= asset.ptr - sections.rdata_pointer_offset + asset.length); + auto dat = sections.rdata.subspan(asset.ptr - sections.rdata_pointer_offset, asset.length); - if(tryDecrypt(asset, dat, decryptBuffer)) { - return std::span(decryptBuffer); + if(tryDecrypt(asset, dat, decryptBuffer)) { + return std::span(decryptBuffer); + } + return dat; + }; + + LoadAtlas(get_asset(255)); + + if(bg_tex == nullptr) { + bg_tex = std::make_unique(); } - return dat; - }; + glBindTexture(GL_TEXTURE_2D_ARRAY, bg_tex->id); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 320, 180, 19, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + bg_tex->LoadSubImage(1 - 1, get_asset(14)); + bg_tex->LoadSubImage(2 - 1, get_asset(22)); + bg_tex->LoadSubImage(3 - 1, get_asset(22)); + bg_tex->LoadSubImage(4 - 1, get_asset(19)); + bg_tex->LoadSubImage(5 - 1, get_asset(19)); + bg_tex->LoadSubImage(6 - 1, get_asset(15)); + bg_tex->LoadSubImage(7 - 1, get_asset(13)); + bg_tex->LoadSubImage(8 - 1, get_asset(13)); + bg_tex->LoadSubImage(9 - 1, get_asset(16)); + bg_tex->LoadSubImage(10 - 1, get_asset(17)); + bg_tex->LoadSubImage(11 - 1, get_asset(16)); + bg_tex->LoadSubImage(12 - 1, get_asset(26)); + bg_tex->LoadSubImage(13 - 1, get_asset(11)); + bg_tex->LoadSubImage(14 - 1, get_asset(12)); + bg_tex->LoadSubImage(15 - 1, get_asset(20)); + bg_tex->LoadSubImage(16 - 1, get_asset(18)); + bg_tex->LoadSubImage(17 - 1, get_asset(23)); + bg_tex->LoadSubImage(18 - 1, get_asset(24)); + bg_tex->LoadSubImage(19 - 1, get_asset(21)); - LoadAtlas(get_asset(255)); - - bg_tex = std::make_unique(); - glBindTexture(GL_TEXTURE_2D_ARRAY, bg_tex->id); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 320, 180, 19, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - bg_tex->LoadSubImage(1 - 1, get_asset(14)); - bg_tex->LoadSubImage(2 - 1, get_asset(22)); - bg_tex->LoadSubImage(3 - 1, get_asset(22)); - bg_tex->LoadSubImage(4 - 1, get_asset(19)); - bg_tex->LoadSubImage(5 - 1, get_asset(19)); - bg_tex->LoadSubImage(6 - 1, get_asset(15)); - bg_tex->LoadSubImage(7 - 1, get_asset(13)); - bg_tex->LoadSubImage(8 - 1, get_asset(13)); - bg_tex->LoadSubImage(9 - 1, get_asset(16)); - bg_tex->LoadSubImage(10 - 1, get_asset(17)); - bg_tex->LoadSubImage(11 - 1, get_asset(16)); - bg_tex->LoadSubImage(12 - 1, get_asset(26)); - bg_tex->LoadSubImage(13 - 1, get_asset(11)); - bg_tex->LoadSubImage(14 - 1, get_asset(12)); - bg_tex->LoadSubImage(15 - 1, get_asset(20)); - bg_tex->LoadSubImage(16 - 1, get_asset(18)); - bg_tex->LoadSubImage(17 - 1, get_asset(23)); - bg_tex->LoadSubImage(18 - 1, get_asset(24)); - bg_tex->LoadSubImage(19 - 1, get_asset(21)); - - for(size_t i = 0; i < 5; i++) { - maps[i] = Map(get_asset(mapIds[i])); - } + for(size_t i = 0; i < 5; i++) { + maps[i] = Map(get_asset(mapIds[i])); + } - for(auto el : spriteMapping) { - sprites[el.tile_id] = parse_sprite(get_asset(el.asset_id)); - } + for(auto el : spriteMapping) { + sprites[el.tile_id] = parse_sprite(get_asset(el.asset_id)); + } - uvs = parse_uvs(get_asset(254)); + uvs = parse_uvs(get_asset(254)); - updateRender(); + updateRender(); + return true; + } catch(std::exception& e) { + ErrorDialog.push(e.what()); + } - ImGui::CloseCurrentPopup(); - return true; + return false; } static void load_game_dialog() { @@ -1229,7 +1234,7 @@ ImGuiID DockSpaceOverViewport() { if(ImGui::MenuItem("Export Map")) { static std::string lastPath = std::filesystem::current_path().string(); std::string path; - auto result = NFD::SaveDialog({{"Map", {"map"}}}, std::filesystem::current_path().string().c_str(), path, window); + auto result = NFD::SaveDialog({{"Map", {"map"}}}, lastPath.c_str(), path, window); if(result == NFD::Result::Error) { ErrorDialog.push(NFD::GetError()); diff --git a/src/structures/asset.cpp b/src/structures/asset.cpp index 5dad455..cac27d5 100644 --- a/src/structures/asset.cpp +++ b/src/structures/asset.cpp @@ -4,7 +4,6 @@ #include #include "../aes.hpp" -#include "../dos_parser.hpp" static std::array keys[3] = { {'G', 'o', 'o', 'd', 'L', 'U', 'c', 'K', 'M', 'y', 'F', 'r', 'i', 'E', 'n', 'd'}, diff --git a/src/structures/asset.hpp b/src/structures/asset.hpp index 2b23a37..6125734 100644 --- a/src/structures/asset.hpp +++ b/src/structures/asset.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include diff --git a/src/structures/entity.hpp b/src/structures/entity.hpp index da1ac02..ca937e3 100644 --- a/src/structures/entity.hpp +++ b/src/structures/entity.hpp @@ -217,13 +217,16 @@ constexpr TileMapping spriteMapping[] = { {0x9d, 0xaf, 0x33e}, }; -SpriteData parse_sprite(std::span data) { - // assert(asset.info.type == AssetType::SpriteData); - assert(data.size() >= 0x30); +inline SpriteData parse_sprite(std::span data) { + if(data.size() < 0x30) { + throw std::runtime_error("invalid sprite header size"); + } auto ptr = (char*)data.data(); auto magic = *(uint32_t*)ptr; - assert(magic == 0x0003AC1D); + if(magic != 0x0003AC1D) { + throw std::runtime_error("invalid sprite header"); + } SpriteData out; out.composite_size.x = *(uint16_t*)(ptr + 4); @@ -233,20 +236,27 @@ SpriteData parse_sprite(std::span data) { out.subsprite_count = *(uint8_t*)(ptr + 12); out.animation_count = *(uint8_t*)(ptr + 13); - assert(data.size() >= 0x30 + out.animation_count * sizeof(SpriteAnimation) + out.layer_count * out.composition_count + out.subsprite_count * sizeof(SubSprite) + out.layer_count * sizeof(SpriteLayer)); + auto anim_size = out.animation_count * sizeof(SpriteAnimation); + auto comp_size = out.layer_count * out.composition_count; + auto subs_size = out.subsprite_count * sizeof(SubSprite); + auto layer_size = out.layer_count * sizeof(SpriteLayer); + + if(data.size() < 0x30 + anim_size + comp_size + subs_size + layer_size) { + throw std::runtime_error("invalid sprite data size"); + } ptr += 0x30; out.animations = {(SpriteAnimation*)ptr, ((SpriteAnimation*)ptr) + out.animation_count}; - ptr += out.animation_count * sizeof(SpriteAnimation); + ptr += anim_size; - out.compositions = {ptr, ptr + out.layer_count * out.composition_count}; - ptr += out.layer_count * out.composition_count; + out.compositions = {ptr, ptr + comp_size}; + ptr += comp_size; out.sub_sprites = {(SubSprite*)ptr, ((SubSprite*)ptr) + out.subsprite_count}; - ptr += out.subsprite_count * sizeof(SubSprite); + ptr += subs_size; - out.layers = {(SpriteLayer*)ptr, (SpriteLayer*)(ptr + out.layer_count * sizeof(SpriteLayer))}; + out.layers = {(SpriteLayer*)ptr, (SpriteLayer*)(ptr) + out.layer_count}; return out; } diff --git a/src/structures/map.hpp b/src/structures/map.hpp index c911ff8..5fe0bbd 100644 --- a/src/structures/map.hpp +++ b/src/structures/map.hpp @@ -154,7 +154,7 @@ class Map { 8, 0xF0F0CAFE, }; - std::memcpy(data.data() + 0x10, rooms.data(), rooms.size() * sizeof(Room)); + std::memcpy(data.data() + sizeof(MapHeader), rooms.data(), rooms.size() * sizeof(Room)); return data; } diff --git a/src/structures/tile.hpp b/src/structures/tile.hpp index 31de585..e8dc69a 100644 --- a/src/structures/tile.hpp +++ b/src/structures/tile.hpp @@ -33,21 +33,27 @@ struct uv_data { }; static_assert(sizeof(uv_data) == 10); -std::vector parse_uvs(std::span data) { - assert(data.size() >= 0xC); +inline std::vector parse_uvs(std::span data) { + if(data.size() < 0xC) { + throw std::runtime_error("invalid uv header size"); + } auto magic = *(uint32_t *)data.data(); - assert(magic == 0x00B00B00); + if(magic != 0x00B00B00) { + throw std::runtime_error("invalid uv header"); + } auto count = *(uint32_t *)(data.data() + 4); auto unused = *(uint32_t *)(data.data() + 8); // null in the given asset - assert(data.size() >= 0xC + count * sizeof(uv_data)); + if(data.size() < 0xC + count * sizeof(uv_data)) { + throw std::runtime_error("invalid uv data size"); + } auto ptr = (uv_data *)(data.data() + 0xC); return std::vector(ptr, ptr + count); } -std::vector save_uvs(std::span uvs) { +inline std::vector save_uvs(std::span uvs) { std::vector data(0xC + uvs.size() * sizeof(uv_data)); *((uint32_t*)data.data() + 0) = 0x00B00B00; diff --git a/src/windows/errors.hpp b/src/windows/errors.hpp index 2f8a45d..f644a4b 100644 --- a/src/windows/errors.hpp +++ b/src/windows/errors.hpp @@ -23,6 +23,7 @@ class { for(auto& e : errors) { ImGui::Indent(); ImGui::Text(e.c_str()); + ImGui::Unindent(); } }