mirror of
https://github.com/isledecomp/isle.git
synced 2026-01-19 06:21:16 +00:00
Merge branch 'isledecomp:master' into master
This commit is contained in:
commit
7950a29e8b
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -60,11 +60,14 @@ jobs:
|
|||||||
C:\msys64\usr\bin\wget.exe https://legoisland.org/download/ISLE.EXE
|
C:\msys64\usr\bin\wget.exe https://legoisland.org/download/ISLE.EXE
|
||||||
C:\msys64\usr\bin\wget.exe https://legoisland.org/download/LEGO1.DLL
|
C:\msys64\usr\bin\wget.exe https://legoisland.org/download/LEGO1.DLL
|
||||||
pip install capstone
|
pip install capstone
|
||||||
python3 tools/reccomp/reccomp.py ISLE.EXE Release/ISLE.EXE Release/ISLE.PDB ISLE
|
python3 tools/reccmp/reccmp.py -H ISLEPROGRESS.HTML ISLE.EXE Release/ISLE.EXE Release/ISLE.PDB ISLE
|
||||||
python3 tools/reccomp/reccomp.py LEGO1.DLL Release/LEGO1.DLL Release/LEGO1.PDB LEGO1
|
python3 tools/reccmp/reccmp.py -H LEGO1PROGRESS.HTML LEGO1.DLL Release/LEGO1.DLL Release/LEGO1.PDB LEGO1
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@master
|
uses: actions/upload-artifact@master
|
||||||
with:
|
with:
|
||||||
name: Win32
|
name: Win32
|
||||||
path: Release
|
path: |
|
||||||
|
Release
|
||||||
|
ISLEPROGRESS.HTML
|
||||||
|
LEGO1PROGRESS.HTML
|
||||||
|
|||||||
@ -37,13 +37,7 @@ Isle::Isle()
|
|||||||
m_frameDelta = 10;
|
m_frameDelta = 10;
|
||||||
m_windowActive = 1;
|
m_windowActive = 1;
|
||||||
|
|
||||||
MxRect32 rect;
|
m_videoParam = MxVideoParam(MxRect32(0, 0, 639, 479), NULL, 1, MxVideoParamFlags());
|
||||||
rect.m_left = 0;
|
|
||||||
rect.m_top = 0;
|
|
||||||
rect.m_right = 639;
|
|
||||||
rect.m_bottom = 479;
|
|
||||||
|
|
||||||
m_videoParam = MxVideoParam(rect, NULL, 1, MxVideoParamFlags());
|
|
||||||
m_videoParam.flags().Enable16Bit(MxDirectDraw::GetPrimaryBitDepth() == 16);
|
m_videoParam.flags().Enable16Bit(MxDirectDraw::GetPrimaryBitDepth() == 16);
|
||||||
|
|
||||||
m_windowHandle = NULL;
|
m_windowHandle = NULL;
|
||||||
@ -116,7 +110,7 @@ void Isle::Close()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: ISLE 0x402740
|
// OFFSET: ISLE 0x402740
|
||||||
BOOL ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize)
|
BOOL Isle::ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize)
|
||||||
{
|
{
|
||||||
HKEY hKey;
|
HKEY hKey;
|
||||||
DWORD valueType;
|
DWORD valueType;
|
||||||
@ -135,7 +129,7 @@ BOOL ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: ISLE 0x4027b0
|
// OFFSET: ISLE 0x4027b0
|
||||||
int ReadRegBool(LPCSTR name, BOOL *out)
|
int Isle::ReadRegBool(LPCSTR name, BOOL *out)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
@ -143,28 +137,30 @@ int ReadRegBool(LPCSTR name, BOOL *out)
|
|||||||
if (read) {
|
if (read) {
|
||||||
if (strcmp("YES", buffer) == 0) {
|
if (strcmp("YES", buffer) == 0) {
|
||||||
*out = TRUE;
|
*out = TRUE;
|
||||||
return TRUE;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp("NO", buffer) == 0) {
|
if (strcmp("NO", buffer) == 0) {
|
||||||
*out = FALSE;
|
*out = FALSE;
|
||||||
return TRUE;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read = FALSE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: ISLE 0x402880
|
// OFFSET: ISLE 0x402880
|
||||||
int ReadRegInt(LPCSTR name, int *out)
|
int Isle::ReadRegInt(LPCSTR name, int *out)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
if (ReadReg(name, buffer, sizeof(buffer))) {
|
BOOL read = ReadReg(name, buffer, sizeof(buffer));
|
||||||
|
if (read) {
|
||||||
*out = atoi(buffer);
|
*out = atoi(buffer);
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: ISLE 0x4028d0
|
// OFFSET: ISLE 0x4028d0
|
||||||
@ -256,16 +252,18 @@ void Isle::SetupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers,
|
|||||||
// OFFSET: ISLE 0x4013b0
|
// OFFSET: ISLE 0x4013b0
|
||||||
BOOL Isle::SetupLegoOmni()
|
BOOL Isle::SetupLegoOmni()
|
||||||
{
|
{
|
||||||
|
BOOL result = FALSE;
|
||||||
char mediaPath[256];
|
char mediaPath[256];
|
||||||
GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath));
|
GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath));
|
||||||
|
|
||||||
if (Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__ *) m_windowHandle, m_videoParam, MxOmniCreateFlags())) != FAILURE) {
|
BOOL failure = Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__ *) m_windowHandle, m_videoParam, MxOmniCreateFlags())) == FAILURE;
|
||||||
|
if (!failure) {
|
||||||
VariableTable()->SetVariable("ACTOR_01", "");
|
VariableTable()->SetVariable("ACTOR_01", "");
|
||||||
TickleManager()->vtable1c(VideoManager(), 10);
|
TickleManager()->vtable1c(VideoManager(), 10);
|
||||||
return TRUE;
|
result = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: ISLE 0x402e80
|
// OFFSET: ISLE 0x402e80
|
||||||
@ -283,6 +281,14 @@ void Isle::SetupCursor(WPARAM wParam)
|
|||||||
break;
|
break;
|
||||||
case 0xB:
|
case 0xB:
|
||||||
m_cursorCurrent = NULL;
|
m_cursorCurrent = NULL;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
case 0xA:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,11 @@ class Isle
|
|||||||
Isle();
|
Isle();
|
||||||
~Isle();
|
~Isle();
|
||||||
|
|
||||||
static void Close();
|
void Close();
|
||||||
|
|
||||||
|
BOOL ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize);
|
||||||
|
int ReadRegBool(LPCSTR name, BOOL *out);
|
||||||
|
int ReadRegInt(LPCSTR name, int *out);
|
||||||
|
|
||||||
MxResult SetupWindow(HINSTANCE hInstance);
|
MxResult SetupWindow(HINSTANCE hInstance);
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,14 @@
|
|||||||
class MxRect32
|
class MxRect32
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
MxRect32(int p_left, int p_top, int p_right, int p_bottom)
|
||||||
|
{
|
||||||
|
this->m_left = p_left;
|
||||||
|
this->m_top = p_top;
|
||||||
|
this->m_right = p_right;
|
||||||
|
this->m_bottom = p_bottom;
|
||||||
|
}
|
||||||
|
|
||||||
int m_left;
|
int m_left;
|
||||||
int m_top;
|
int m_top;
|
||||||
int m_right;
|
int m_right;
|
||||||
|
|||||||
@ -11,6 +11,60 @@ MxString::MxString()
|
|||||||
this->m_length = 0;
|
this->m_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae2a0
|
||||||
|
MxString::MxString(const MxString &str)
|
||||||
|
{
|
||||||
|
this->m_length = str.m_length;
|
||||||
|
this->m_data = (char *)malloc(this->m_length + 1);
|
||||||
|
strcpy(this->m_data, str.m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae350
|
||||||
|
MxString::MxString(const char *str)
|
||||||
|
{
|
||||||
|
if (str) {
|
||||||
|
this->m_length = strlen(str);
|
||||||
|
this->m_data = (char *)malloc(this->m_length + 1);
|
||||||
|
strcpy(this->m_data, str);
|
||||||
|
} else {
|
||||||
|
this->m_data = (char *)malloc(1);
|
||||||
|
this->m_data[0] = 0;
|
||||||
|
this->m_length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae420
|
||||||
|
MxString::~MxString()
|
||||||
|
{
|
||||||
|
free(this->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae490
|
||||||
|
void MxString::ToUpperCase()
|
||||||
|
{
|
||||||
|
strupr(this->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae4a0
|
||||||
|
void MxString::ToLowerCase()
|
||||||
|
{
|
||||||
|
strlwr(this->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100ae4b0
|
||||||
|
const MxString &MxString::operator=(MxString *param)
|
||||||
|
{
|
||||||
|
if (this->m_data != param->m_data)
|
||||||
|
{
|
||||||
|
free(this->m_data);
|
||||||
|
this->m_length = param->m_length;
|
||||||
|
this->m_data = (char *)malloc(this->m_length + 1);
|
||||||
|
strcpy(this->m_data, param->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this *mostly* matches, again weird with the comparison
|
// TODO: this *mostly* matches, again weird with the comparison
|
||||||
// OFFSET: LEGO1 0x100ae510
|
// OFFSET: LEGO1 0x100ae510
|
||||||
const MxString &MxString::operator=(const char *param)
|
const MxString &MxString::operator=(const char *param)
|
||||||
@ -25,9 +79,3 @@ const MxString &MxString::operator=(const char *param)
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: LEGO1 0x100ae420
|
|
||||||
MxString::~MxString()
|
|
||||||
{
|
|
||||||
free(this->m_data);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -11,6 +11,10 @@ class MxString : public MxCore
|
|||||||
__declspec(dllexport) const MxString &operator=(const char *);
|
__declspec(dllexport) const MxString &operator=(const char *);
|
||||||
|
|
||||||
MxString();
|
MxString();
|
||||||
|
MxString(const char *);
|
||||||
|
void ToUpperCase();
|
||||||
|
void ToLowerCase();
|
||||||
|
const MxString &operator=(MxString *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *m_data;
|
char *m_data;
|
||||||
|
|||||||
@ -10,17 +10,18 @@ long MxTimer::s_LastTimeTimerStarted = 0;
|
|||||||
|
|
||||||
// OFFSET: LEGO1 0x100ae060
|
// OFFSET: LEGO1 0x100ae060
|
||||||
MxTimer::MxTimer()
|
MxTimer::MxTimer()
|
||||||
{
|
{
|
||||||
this->m_isRunning = MX_FALSE;
|
this->m_isRunning = MX_FALSE;
|
||||||
MxTimer::s_LastTimeCalculated = timeGetTime();
|
m_startTime = timeGetTime();
|
||||||
this->m_startTime = MxTimer::s_LastTimeCalculated;
|
// yeah this is somehow what the asm is
|
||||||
|
s_LastTimeCalculated = m_startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: LEGO1 0x100ae160
|
// OFFSET: LEGO1 0x100ae160
|
||||||
void MxTimer::Start()
|
void MxTimer::Start()
|
||||||
{
|
{
|
||||||
|
s_LastTimeTimerStarted = this->GetRealTime();
|
||||||
this->m_isRunning = MX_TRUE;
|
this->m_isRunning = MX_TRUE;
|
||||||
MxTimer::s_LastTimeTimerStarted = timeGetTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFFSET: LEGO1 0x100ae180
|
// OFFSET: LEGO1 0x100ae180
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
from capstone import *
|
from capstone import *
|
||||||
import difflib
|
import difflib
|
||||||
import struct
|
import struct
|
||||||
@ -7,60 +8,40 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def print_usage():
|
parser = argparse.ArgumentParser(allow_abbrev=False,
|
||||||
print('Usage: %s [options] <original-binary> <recompiled-binary> <recompiled-pdb> <decomp-dir>\n' % sys.argv[0])
|
description='Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.')
|
||||||
print('\t-v, --verbose <offset>\t\t\tPrint assembly diff for specific function (original file\'s offset)')
|
parser.add_argument('original', metavar='original-binary', help='The original binary')
|
||||||
print('\t-h, --html <output-file>\t\t\tGenerate searchable HTML summary of status and diffs')
|
parser.add_argument('recompiled', metavar='recompiled-binary', help='The recompiled binary')
|
||||||
sys.exit(1)
|
parser.add_argument('pdb', metavar='recompiled-pdb', help='The PDB of the recompiled binary')
|
||||||
|
parser.add_argument('decomp_dir', metavar='decomp-dir', help='The decompiled source tree')
|
||||||
|
parser.add_argument('--verbose', '-v', metavar='offset', help='Print assembly diff for specific function (original file\'s offset)')
|
||||||
|
parser.add_argument('--html', '-H', metavar='output-file', help='Generate searchable HTML summary of status and diffs')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
positional_args = []
|
|
||||||
verbose = None
|
verbose = None
|
||||||
skip = False
|
if args.verbose:
|
||||||
html = None
|
try:
|
||||||
|
verbose = int(args.verbose, 16)
|
||||||
|
except ValueError:
|
||||||
|
parser.error('invalid verbose argument')
|
||||||
|
html = args.html
|
||||||
|
|
||||||
for i, arg in enumerate(sys.argv):
|
original = args.original
|
||||||
if skip:
|
|
||||||
skip = False
|
|
||||||
continue
|
|
||||||
|
|
||||||
if arg.startswith('-'):
|
|
||||||
# A flag rather than a positional arg
|
|
||||||
flag = arg[1:]
|
|
||||||
|
|
||||||
if flag == 'v' or flag == '-verbose':
|
|
||||||
verbose = int(sys.argv[i + 1], 16)
|
|
||||||
skip = True
|
|
||||||
elif flag == 'h' or flag == '-html':
|
|
||||||
html = sys.argv[i + 1]
|
|
||||||
skip = True
|
|
||||||
else:
|
|
||||||
print('Unknown flag: %s' % arg)
|
|
||||||
print_usage()
|
|
||||||
else:
|
|
||||||
positional_args.append(arg)
|
|
||||||
|
|
||||||
if len(positional_args) != 5:
|
|
||||||
print_usage()
|
|
||||||
|
|
||||||
original = positional_args[1]
|
|
||||||
if not os.path.isfile(original):
|
if not os.path.isfile(original):
|
||||||
print('Invalid input: Original binary does not exist')
|
parser.error('Original binary does not exist')
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
recomp = positional_args[2]
|
recomp = args.recompiled
|
||||||
if not os.path.isfile(recomp):
|
if not os.path.isfile(recomp):
|
||||||
print('Invalid input: Recompiled binary does not exist')
|
parser.error('Recompiled binary does not exist')
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
syms = positional_args[3]
|
syms = args.pdb
|
||||||
if not os.path.isfile(syms):
|
if not os.path.isfile(syms):
|
||||||
print('Invalid input: Symbols PDB does not exist')
|
parser.error('Symbols PDB does not exist')
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
source = positional_args[4]
|
source = args.decomp_dir
|
||||||
if not os.path.isdir(source):
|
if not os.path.isdir(source):
|
||||||
print('Invalid input: Source directory does not exist')
|
parser.error('Source directory does not exist')
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Declare a class that can automatically convert virtual executable addresses
|
# Declare a class that can automatically convert virtual executable addresses
|
||||||
# to file addresses
|
# to file addresses
|
||||||
@ -67,6 +67,12 @@
|
|||||||
#sortind {
|
#sortind {
|
||||||
margin: 0 0.5em;
|
margin: 0 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
font-size: 10pt;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0.5em 0 1em 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
var data = [/* INSERT DATA HERE */];
|
var data = [/* INSERT DATA HERE */];
|
||||||
@ -115,18 +121,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(text) {
|
const filterOptions = { text: '', hidePerfect: false };
|
||||||
|
|
||||||
|
function filter() {
|
||||||
closeAllDiffs();
|
closeAllDiffs();
|
||||||
|
|
||||||
var ltext = text.toLowerCase();
|
var ltext = filterOptions.text.toLowerCase();
|
||||||
|
|
||||||
const collection = document.getElementsByClassName("funcrow");
|
const collection = document.getElementsByClassName("funcrow");
|
||||||
var searchCount = 0;
|
var searchCount = 0;
|
||||||
for (var ele of collection) {
|
for (var ele of collection) {
|
||||||
var eledata = data[ele.dataset.index];
|
var eledata = data[ele.dataset.index];
|
||||||
if (text == ''
|
|
||||||
|
const textOk = (ltext == ''
|
||||||
|| eledata.address.toLowerCase().includes(ltext)
|
|| eledata.address.toLowerCase().includes(ltext)
|
||||||
|| eledata.name.toLowerCase().includes(ltext)) {
|
|| eledata.name.toLowerCase().includes(ltext));
|
||||||
|
|
||||||
|
const perfOk = (!filterOptions.hidePerfect || (eledata.matching < 1));
|
||||||
|
|
||||||
|
if (textOk && perfOk) {
|
||||||
ele.style.display = '';
|
ele.style.display = '';
|
||||||
searchCount++;
|
searchCount++;
|
||||||
} else {
|
} else {
|
||||||
@ -219,9 +232,16 @@
|
|||||||
|
|
||||||
var search = document.getElementById('search');
|
var search = document.getElementById('search');
|
||||||
search.addEventListener('input', function (evt) {
|
search.addEventListener('input', function (evt) {
|
||||||
filter(search.value);
|
filterOptions.text = search.value;
|
||||||
|
filter();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const cbHidePerfect = document.getElementById('cbHidePerfect');
|
||||||
|
cbHidePerfect.addEventListener('change', evt => {
|
||||||
|
filterOptions.hidePerfect = evt.target.checked;
|
||||||
|
filter();
|
||||||
|
})
|
||||||
|
|
||||||
sortByColumn(0);
|
sortByColumn(0);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -230,8 +250,10 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<h1>Decompilation Status</h1>
|
<h1>Decompilation Status</h1>
|
||||||
<input id="search" type="search" placeholder="Search for offset or function name...">
|
<input id="search" type="search" placeholder="Search for offset or function name...">
|
||||||
<br>
|
<div class="filters">
|
||||||
<br>
|
<label for="cbHidePerfect">Hide 100% match</label>
|
||||||
|
<input type="checkbox" id="cbHidePerfect" />
|
||||||
|
</div>
|
||||||
<table id="listing">
|
<table id="listing">
|
||||||
<tr id='listingheader'><th style='width: 20%'>Address</th><th style="width:60%">Name</th><th style='width: 20%'>Matching</th></tr>
|
<tr id='listingheader'><th style='width: 20%'>Address</th><th style="width:60%">Name</th><th style='width: 20%'>Matching</th></tr>
|
||||||
</table>
|
</table>
|
||||||
Loading…
Reference in New Issue
Block a user