diff --git a/.editorconfig b/.editorconfig index 604cc306..c6a6539f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*.{py,txt,editorconfig}] indent_style = space -indent_size = 2 +indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8434d906..2c285836 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,10 @@ jobs: # Use minimum supported version cmake-version: '3.13.x' + - name: Patch MSVC 4.2 + run: | + python tools/patch_c2.py msvc420/bin/C2.EXE + - name: Build shell: cmd run: | @@ -79,7 +83,7 @@ jobs: shell: bash run: | python3 tools/reccmp/reccmp.py -S ISLEPROGRESS.SVG --svg-icon tools/reccmp/isle.png -H ISLEPROGRESS.HTML legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . | tee ISLEPROGRESS.TXT - python3 tools/reccmp/reccmp.py -S LEGO1PROGRESS.SVG -T 1929 --svg-icon tools/reccmp/lego1.png -H LEGO1PROGRESS.HTML legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . | tee LEGO1PROGRESS.TXT + python3 tools/reccmp/reccmp.py -S LEGO1PROGRESS.SVG -T 4252 --svg-icon tools/reccmp/lego1.png -H LEGO1PROGRESS.HTML legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . | tee LEGO1PROGRESS.TXT - name: Compare Accuracy With Current Master shell: bash diff --git a/.pylintrc b/.pylintrc index 7afd8185..ab83fceb 100644 --- a/.pylintrc +++ b/.pylintrc @@ -165,7 +165,7 @@ class-naming-style=PascalCase #class-rgx= # Naming style matching correct constant names. -const-naming-style=snake_case +const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. If left empty, constant names will be checked with the set naming @@ -511,7 +511,7 @@ ignore-imports=yes ignore-signatures=yes # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=16 [SPELLING] diff --git a/CMakeLists.txt b/CMakeLists.txt index e1fa4db2..4a60e3d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ add_library(lego1 SHARED LEGO1/legovehiclebuildstate.cpp LEGO1/legovideomanager.cpp LEGO1/legoworld.cpp + LEGO1/legoworldlist.cpp LEGO1/legoworldpresenter.cpp LEGO1/motorcycle.cpp LEGO1/mxactionnotificationparam.cpp @@ -288,8 +289,9 @@ if (MSVC) # These flags have been taken from the defaults for a Visual C++ 4.20 project (the compiler the # game was originally built with) and tweaked slightly to produce more debugging info for reccmp. # They ensure a recompilation that can be byte/instruction accurate to the original binaries. - - target_compile_options(isle PRIVATE "/ML$<$:d>") + if (ISLE_BUILD_APP) + target_compile_options(isle PRIVATE "/ML$<$:d>") + endif() target_compile_options(lego1 PRIVATE "/MT$<$:d>") set(CMAKE_CXX_FLAGS "/W3 /GX /D \"WIN32\" /D \"_WINDOWS\"") diff --git a/LEGO1/compat.h b/LEGO1/compat.h index d9cc2170..9616b254 100644 --- a/LEGO1/compat.h +++ b/LEGO1/compat.h @@ -18,12 +18,6 @@ // Impossible to avoid this if using STL map or set. // This removes most (but not all) occurrences of the warning. #pragma warning(disable : 4786) -// To really remove *all* of the warnings, we have to employ the following, -// obscure workaround from https://www.earthli.com/news/view_article.php?id=376 -static class msVC6_4786WorkAround { -public: - msVC6_4786WorkAround() {} -} msVC6_4786WorkAround; #define MSVC420_VERSION 1020 diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 887b8cad..51bb0c0a 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -11,6 +11,7 @@ #include "legoutil.h" #include "legovideomanager.h" #include "legoworld.h" +#include "legoworldlist.h" #include "mxautolocker.h" #include "mxbackgroundaudiomanager.h" #include "mxdsfile.h" @@ -358,7 +359,7 @@ void LegoOmni::Init() m_inputMgr = NULL; m_unk6c = 0; m_gifManager = NULL; - m_unk78 = 0; + m_worldList = NULL; m_currentWorld = NULL; m_unk80 = FALSE; m_currentVehicle = NULL; @@ -427,9 +428,9 @@ MxResult LegoOmni::Create(MxOmniCreateParam& p) m_animationManager = new LegoAnimationManager(); m_buildingManager = new LegoBuildingManager(); m_gameState = new LegoGameState(); - // TODO: initialize list at m_unk78 + m_worldList = new LegoWorldList(); - if (m_unk6c && m_gifManager && m_unk78 && m_plantManager && m_animationManager && m_buildingManager) { + if (m_unk6c && m_gifManager && m_worldList && m_plantManager && m_animationManager && m_buildingManager) { // TODO: initialize a bunch of MxVariables RegisterScripts(); FUN_1001a700(); diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index d5063235..644f2536 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -21,6 +21,7 @@ class LegoSoundManager; class LegoUnkSaveDataWriter; class LegoVideoManager; class LegoWorld; +class LegoWorldList; class MxAtomId; class MxBackgroundAudioManager; class MxDSFile; @@ -117,7 +118,7 @@ class LegoOmni : public MxOmni { undefined4 m_unk6c; LegoInputManager* m_inputMgr; // 0x70 GifManager* m_gifManager; - undefined4 m_unk78; + LegoWorldList* m_worldList; // 0x78 LegoWorld* m_currentWorld; MxBool m_unk80; LegoNavController* m_navController; // 0x84 diff --git a/LEGO1/legoworld.cpp b/LEGO1/legoworld.cpp index 938abe3a..5129cca6 100644 --- a/LEGO1/legoworld.cpp +++ b/LEGO1/legoworld.cpp @@ -67,6 +67,24 @@ MxResult LegoWorld::SetAsCurrentWorld(MxDSObject& p_dsObject) return SUCCESS; } +// SYNTHETIC: LEGO1 0x1001eed0 +// MxPresenterListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001ef40 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1001ef90 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f000 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f070 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1001f0c0 +// MxPresenterListCursor::~MxPresenterListCursor + // FUNCTION: LEGO1 0x1001f5e0 MxLong LegoWorld::Notify(MxParam& p_param) { diff --git a/LEGO1/legoworldlist.cpp b/LEGO1/legoworldlist.cpp new file mode 100644 index 00000000..a62173b0 --- /dev/null +++ b/LEGO1/legoworldlist.cpp @@ -0,0 +1,36 @@ +#include "legoworldlist.h" + +#include "legoworld.h" + +// FUNCTION: LEGO1 0x100598d0 +MxS8 LegoWorldList::Compare(LegoWorld* p_a, LegoWorld* p_b) +{ + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; +} + +// TEMPLATE: LEGO1 0x100598f0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x10059900 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x10059950 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x10059960 +// MxList::~MxList + +// FUNCTION: LEGO1 0x100599f0 +void LegoWorldList::Destroy(LegoWorld* p_world) +{ + delete p_world; +} + +// SYNTHETIC: LEGO1 0x10059ac0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10059b30 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10059be0 +// MxPtrList::`scalar deleting destructor' diff --git a/LEGO1/legoworldlist.h b/LEGO1/legoworldlist.h new file mode 100644 index 00000000..5e9a7c37 --- /dev/null +++ b/LEGO1/legoworldlist.h @@ -0,0 +1,27 @@ +#ifndef LEGOWORLDLIST_H +#define LEGOWORLDLIST_H + +#include "mxlist.h" +#include "mxtypes.h" + +class LegoWorld; + +// VTABLE: LEGO1 0x100d8700 +// class MxCollection + +// VTABLE: LEGO1 0x100d8718 +// class MxList + +// VTABLE: LEGO1 0x100d8730 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8680 +// SIZE 0x18 +class LegoWorldList : public MxPtrList { +public: + LegoWorldList() : MxPtrList(Destroy) {} + virtual MxS8 Compare(LegoWorld*, LegoWorld*) override; // vtable+0x14 + static void Destroy(LegoWorld*); +}; + +#endif // LEGOWORLDLIST_H diff --git a/LEGO1/mxdsactionlist.h b/LEGO1/mxdsactionlist.h index 19929d20..a467bf52 100644 --- a/LEGO1/mxdsactionlist.h +++ b/LEGO1/mxdsactionlist.h @@ -26,6 +26,13 @@ class MxDSActionList : public MxList { undefined m_unk18; }; -typedef MxListCursorChild MxDSActionListCursor; +// VTABLE: LEGO1 0x100d7e68 +// class MxListCursor + +// VTABLE: LEGO1 0x100d7e50 +class MxDSActionListCursor : public MxListCursor { +public: + MxDSActionListCursor(MxDSActionList* p_list) : MxListCursor(p_list){}; +}; #endif // MXDSACTIONLIST_H diff --git a/LEGO1/mxdsmultiaction.cpp b/LEGO1/mxdsmultiaction.cpp index 27cd806e..b2b31abe 100644 --- a/LEGO1/mxdsmultiaction.cpp +++ b/LEGO1/mxdsmultiaction.cpp @@ -2,6 +2,19 @@ DECOMP_SIZE_ASSERT(MxDSMultiAction, 0x9c) +// TODO: Should be moved later +// SYNTHETIC: LEGO1 0x1004ad10 +// MxDSActionListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1004ad80 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x1004add0 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1004ae40 +// MxDSActionListCursor::~MxDSActionListCursor + // FUNCTION: LEGO1 0x100c9b90 MxDSMultiAction::MxDSMultiAction() { diff --git a/LEGO1/mxdsselectaction.cpp b/LEGO1/mxdsselectaction.cpp index 4bdfbd60..ed9b78ba 100644 --- a/LEGO1/mxdsselectaction.cpp +++ b/LEGO1/mxdsselectaction.cpp @@ -33,6 +33,18 @@ void MxDSSelectAction::CopyFrom(MxDSSelectAction& p_dsSelectAction) this->m_unk0xac->Append(string); } +// SYNTHETIC: LEGO1 0x100cbbd0 +// MxStringListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100cbc40 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x100cbc90 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100cbd00 +// MxStringListCursor::~MxStringListCursor + // FUNCTION: LEGO1 0x100cbd50 MxDSSelectAction& MxDSSelectAction::operator=(MxDSSelectAction& p_dsSelectAction) { @@ -130,3 +142,6 @@ void MxDSSelectAction::Deserialize(char** p_source, MxS16 p_unk24) *p_source += extraFlag; } + +// TEMPLATE: LEGO1 0x100cc450 +// MxListEntry::GetValue diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h index a55aae6e..e3428f98 100644 --- a/LEGO1/mxlist.h +++ b/LEGO1/mxlist.h @@ -100,18 +100,10 @@ class MxListCursor : public MxCore { MxListEntry* m_match; }; -// Unclear purpose template -class MxListCursorChild : public MxListCursor { +class MxPtrListCursor : public MxListCursor { public: - MxListCursorChild(MxList* p_list) : MxListCursor(p_list) {} -}; - -// Unclear purpose -template -class MxListCursorChildChild : public MxListCursorChild { -public: - MxListCursorChildChild(MxList* p_list) : MxListCursorChild(p_list) {} + MxPtrListCursor(MxPtrList* p_list) : MxListCursor(p_list){}; }; template diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index b1b064cc..6ffdab71 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -21,6 +21,19 @@ void MxMediaPresenter::Destroy() Destroy(FALSE); } +// TODO: These probably belong in another class +// SYNTHETIC: LEGO1 0x100b46e0 +// MxStreamChunkListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b4750 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x100b47a0 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100b4810 +// MxStreamChunkListCursor::~MxStreamChunkListCursor + // FUNCTION: LEGO1 0x100b54e0 void MxMediaPresenter::Init() { diff --git a/LEGO1/mxpresenterlist.h b/LEGO1/mxpresenterlist.h index d96374b9..23e7f6c2 100644 --- a/LEGO1/mxpresenterlist.h +++ b/LEGO1/mxpresenterlist.h @@ -15,7 +15,17 @@ class MxPresenterList : public MxPtrList { virtual MxS8 Compare(MxPresenter*, MxPresenter*) override; // vtable+0x14 }; -typedef MxListCursorChildChild MxPresenterListCursor; +// VTABLE: LEGO1 0x100d6488 +// class MxListCursor + +// VTABLE: LEGO1 0x100d6530 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d6470 +class MxPresenterListCursor : public MxPtrListCursor { +public: + MxPresenterListCursor(MxPresenterList* p_list) : MxPtrListCursor(p_list){}; +}; // VTABLE: LEGO1 0x100d6350 // class MxCollection diff --git a/LEGO1/mxregion.cpp b/LEGO1/mxregion.cpp index afd546d6..0ac28be1 100644 --- a/LEGO1/mxregion.cpp +++ b/LEGO1/mxregion.cpp @@ -86,6 +86,24 @@ void MxRegion::vtable18(MxRect32& p_rect) m_rect.UpdateBounds(p_rect); } +// SYNTHETIC: LEGO1 0x100c3be0 +// MxRegionListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c3c50 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100c3ca0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c3d10 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c3d80 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x100c3dd0 +// MxRegionListCursor::~MxRegionListCursor + // FUNCTION: LEGO1 0x100c3e20 MxBool MxRegion::vtable1c(MxRect32& p_rect) { @@ -105,6 +123,21 @@ MxBool MxRegion::vtable1c(MxRect32& p_rect) return FALSE; } +// SYNTHETIC: LEGO1 0x100c4790 +// MxRegionLeftRightListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c4800 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100c4850 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c48c0 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c4930 +// MxListCursor::~MxListCursor + // FUNCTION: LEGO1 0x100c4c90 MxRegionTopBottom::MxRegionTopBottom(MxS32 p_top, MxS32 p_bottom) { @@ -167,6 +200,15 @@ void MxRegionTopBottom::FUN_100c5280(MxS32 p_left, MxS32 p_right) } } +// TEMPLATE: LEGO1 0x100c54f0 +// MxListCursor::MxListCursor + +// FUNCTION: LEGO1 0x100c5560 +// MxRegionLeftRightListCursor::~MxRegionLeftRightListCursor + +// TEMPLATE: LEGO1 0x100c55b0 +// MxListCursor::operator= + // FUNCTION: LEGO1 0x100c55d0 MxRegionTopBottom* MxRegionTopBottom::Clone() { diff --git a/LEGO1/mxregionlist.h b/LEGO1/mxregionlist.h index 3aa0487b..2938e38b 100644 --- a/LEGO1/mxregionlist.h +++ b/LEGO1/mxregionlist.h @@ -23,13 +23,21 @@ class MxRegionList : public MxPtrList { static void Destroy(MxRegionTopBottom*); }; -// VTABLE: LEGO1 0x100dcb88 -// class MxListCursorChildChild -typedef MxListCursorChildChild MxRegionListCursor; +// VTABLE: LEGO1 0x100dcb70 +// class MxPtrListCursor -// VTABLE: LEGO1 0x100dcc10 -// class MxListCursorChildChild -typedef MxListCursorChildChild MxRegionLeftRightListCursor; +// VTABLE: LEGO1 0x100dcba0 +// class MxListCursor + +// TODO: The initialize list param type should be MxRegionList, but doing that +// drastically reduced the match percentage for MxRegion::vtable18. +// It also works with MxPtrList, so we'll do that until we figure this out. + +// VTABLE: LEGO1 0x100dcb88 +class MxRegionListCursor : public MxPtrListCursor { +public: + MxRegionListCursor(MxPtrList* p_list) : MxPtrListCursor(p_list){}; +}; // VTABLE: LEGO1 0x100dcc40 // class MxCollection @@ -48,4 +56,16 @@ class MxRegionLeftRightList : public MxPtrList { static void Destroy(MxRegionLeftRight*); }; +// VTABLE: LEGO1 0x100dcbf8 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100dcc28 +// class MxListCursor + +// VTABLE: LEGO1 0x100dcc10 +class MxRegionLeftRightListCursor : public MxPtrListCursor { +public: + MxRegionLeftRightListCursor(MxRegionLeftRightList* p_list) : MxPtrListCursor(p_list){}; +}; + #endif // MXREGIONLIST_H diff --git a/LEGO1/mxstreamchunklist.h b/LEGO1/mxstreamchunklist.h index 4924b6ff..9661229c 100644 --- a/LEGO1/mxstreamchunklist.h +++ b/LEGO1/mxstreamchunklist.h @@ -23,6 +23,13 @@ class MxStreamChunkList : public MxList { static void Destroy(MxStreamChunk* p_chunk); }; -typedef MxListCursorChild MxStreamChunkListCursor; +// VTABLE: LEGO1 0x100dc510 +class MxStreamChunkListCursor : public MxListCursor { +public: + MxStreamChunkListCursor(MxStreamChunkList* p_list) : MxListCursor(p_list){}; +}; + +// VTABLE: LEGO1 0x100dc528 +// class MxListCursor #endif // MXSTREAMCHUNKLIST_H diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index 2ecf0b43..cdc8eff3 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -51,13 +51,13 @@ MxStreamController::MxStreamController() // TEMPLATE: LEGO1 0x100c0ee0 // list >::_Buynode -// TEMPLATE: LEGO1 0x100c0fc0 +// FUNCTION: LEGO1 0x100c0fc0 // MxStreamListMxDSSubscriber::~MxStreamListMxDSSubscriber -// TEMPLATE: LEGO1 0x100c1010 +// FUNCTION: LEGO1 0x100c1010 // MxStreamListMxDSAction::~MxStreamListMxDSAction -// TEMPLATE: LEGO1 0x100c1060 +// FUNCTION: LEGO1 0x100c1060 // MxStreamListMxNextActionDataStart::~MxStreamListMxNextActionDataStart // TEMPLATE: LEGO1 0x100c10b0 diff --git a/LEGO1/mxstringlist.h b/LEGO1/mxstringlist.h index 08754405..cacb0be5 100644 --- a/LEGO1/mxstringlist.h +++ b/LEGO1/mxstringlist.h @@ -9,6 +9,12 @@ class MxStringList : public MxList {}; // VTABLE: LEGO1 0x100dd058 -typedef MxListCursorChild MxStringListCursor; +class MxStringListCursor : public MxListCursor { +public: + MxStringListCursor(MxStringList* p_list) : MxListCursor(p_list){}; +}; + +// VTABLE: LEGO1 0x100dd070 +// class MxListCursor #endif // MXSTRINGLIST_H diff --git a/tools/checkorder/checkorder.py b/tools/checkorder/checkorder.py index 02636c09..0cdba670 100644 --- a/tools/checkorder/checkorder.py +++ b/tools/checkorder/checkorder.py @@ -49,7 +49,7 @@ def check_file(filename: str, verbose: bool = False) -> bool: f"{fun.end_line - fun.line_number:4} lines", f"{order_lookup[fun.offset]:3}", " ", - sig_truncate(fun.signature), + sig_truncate(fun.name), ] ) print(msg) diff --git a/tools/patch_c2.py b/tools/patch_c2.py new file mode 100644 index 00000000..58cc4760 --- /dev/null +++ b/tools/patch_c2.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +import argparse +import hashlib +import pathlib +import shutil + +ORIGINAL_C2_MD5 = "dcd69f1dd28b02dd03dd7ed02984299a" # original C2.EXE + +C2_MD5 = ( + ORIGINAL_C2_MD5, + "e70acde41802ddec06c4263bb357ac30", # patched C2.EXE +) + +C2_SIZE = 549888 + + +def main(): + parser = argparse.ArgumentParser( + allow_abbrev=False, + description="Path to C2.EXE of Microsoft Visual Studio 4.2.0 to disable C4786 warning", + ) + parser.add_argument("path", type=pathlib.Path, help="Path of C2.EXE") + parser.add_argument( + "-f", dest="force", default=False, action="store_true", help="force" + ) + args = parser.parse_args() + + if not args.path.is_file(): + parser.error("Input is not a file") + + binary = bytearray(args.path.open("rb").read()) + md5 = hashlib.md5(binary).hexdigest() + print(md5, C2_MD5) + + msg_cb = parser.error if not args.force else print + if len(binary) != C2_SIZE: + msg_cb("file size is not correct") + if md5 not in C2_MD5: + msg_cb("md5 checksum does not match") + + if md5 == ORIGINAL_C2_MD5: + backup = f"{args.path}.BAK" + print(f'Creating backup "{backup}"') + shutil.copyfile(args.path, backup) + + def nop_patch(start, count, expected=None): + replacement = [0x90] * count + if expected: + current = list(binary[start : start + count]) + assert len(expected) == count + assert current in (expected, replacement) + print(f"Nopping {count} bytes at 0x{start:08x}") + binary[start : start + count] = replacement + + print( + "Disable C4786 warning: '%Fs' : identifier was truncated to '%d' characters in the debug information" + ) + nop_patch(0x52F07, 5, [0xE8, 0x4F, 0xB3, 0xFE, 0xFF]) # 0x00453b07 + nop_patch(0x74832, 5, [0xE8, 0x24, 0x9A, 0xFC, 0xFF]) # 0x00475432 + + args.path.open("wb").write(binary) + print("done") + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index d2a7f23a..98a8a4d9 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -23,6 +23,7 @@ import colorama from pystache import Renderer + REGISTER_LIST = set( [ "ax", @@ -200,7 +201,8 @@ def gen_svg(svg_file, name_svg, icon, svg_implemented_funcs, total_funcs, raw_ac # Do the actual work -if __name__ == "__main__": +def main(): + # pylint: disable=too-many-locals, too-many-nested-blocks, too-many-branches, too-many-statements parser = argparse.ArgumentParser( allow_abbrev=False, description="Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.", @@ -483,3 +485,7 @@ def gen_svg(svg_file, name_svg, icon, svg_implemented_funcs, total_funcs, raw_ac function_count, total_effective_accuracy, ) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/verexp/verexp.py b/tools/verexp/verexp.py index 37e3e641..455791e1 100755 --- a/tools/verexp/verexp.py +++ b/tools/verexp/verexp.py @@ -8,61 +8,71 @@ from isledecomp.utils import print_diff -parser = argparse.ArgumentParser( - allow_abbrev=False, description="Verify Exports: Compare the exports of two DLLs." -) -parser.add_argument("original", metavar="original-binary", help="The original binary") -parser.add_argument( - "recompiled", metavar="recompiled-binary", help="The recompiled binary" -) -parser.add_argument( - "--no-color", "-n", action="store_true", help="Do not color the output" -) -args = parser.parse_args() +def main(): + parser = argparse.ArgumentParser( + allow_abbrev=False, + description="Verify Exports: Compare the exports of two DLLs.", + ) + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "--no-color", "-n", action="store_true", help="Do not color the output" + ) -if not os.path.isfile(args.original): - parser.error(f"Original binary file {args.original} does not exist") + args = parser.parse_args() -if not os.path.isfile(args.recompiled): - parser.error(f"Recompiled binary {args.recompiled} does not exist") + if not os.path.isfile(args.original): + parser.error(f"Original binary file {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + def get_file_in_script_dir(fn): + return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) + + def get_exports(file): + call = [get_file_in_script_dir("DUMPBIN.EXE"), "/EXPORTS"] + + if os.name != "nt": + call.insert(0, "wine") + file = ( + subprocess.check_output(["winepath", "-w", file]) + .decode("utf-8") + .strip() + ) + + call.append(file) + + raw = subprocess.check_output(call).decode("utf-8").split("\r\n") + exports = [] + + start = False + + for line in raw: + if not start: + if line == " ordinal hint name": + start = True + else: + if line: + exports.append(line[27 : line.rindex(" (")]) + elif exports: + break + + return exports + + og_exp = get_exports(args.original) + re_exp = get_exports(args.recompiled) + + udiff = difflib.unified_diff(og_exp, re_exp) + has_diff = print_diff(udiff, args.no_color) + + return 1 if has_diff else 0 -def get_file_in_script_dir(fn): - return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) - - -def get_exports(file): - call = [get_file_in_script_dir("DUMPBIN.EXE"), "/EXPORTS"] - - if os.name != "nt": - call.insert(0, "wine") - file = subprocess.check_output(["winepath", "-w", file]).decode("utf-8").strip() - - call.append(file) - - raw = subprocess.check_output(call).decode("utf-8").split("\r\n") - exports = [] - - start = False - - for line in raw: - if not start: - if line == " ordinal hint name": - start = True - else: - if line: - exports.append(line[27 : line.rindex(" (")]) - elif exports: - break - - return exports - - -og_exp = get_exports(args.original) -re_exp = get_exports(args.recompiled) - -udiff = difflib.unified_diff(og_exp, re_exp) -has_diff = print_diff(udiff, args.no_color) - -sys.exit(1 if has_diff else 0) +if __name__ == "__main__": + raise SystemExit(main())