mirror of
https://github.com/isledecomp/isle.git
synced 2026-01-24 08:41:16 +00:00
Merge branch 'master' into mxstillpresente
This commit is contained in:
commit
90d7605216
@ -375,15 +375,16 @@ MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palett
|
|||||||
|
|
||||||
if (p_palette) {
|
if (p_palette) {
|
||||||
if (p_palette->GetEntries(entries))
|
if (p_palette->GetEntries(entries))
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MxPalette local_pal;
|
MxPalette local_pal;
|
||||||
if (local_pal.GetEntries(entries))
|
if (local_pal.GetEntries(entries))
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MxS32 i = 0; i < 256; i++) {
|
MxS32 i;
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
p_rgbquad[i].rgbRed = entries[i].peRed;
|
p_rgbquad[i].rgbRed = entries[i].peRed;
|
||||||
p_rgbquad[i].rgbGreen = entries[i].peGreen;
|
p_rgbquad[i].rgbGreen = entries[i].peGreen;
|
||||||
p_rgbquad[i].rgbBlue = entries[i].peBlue;
|
p_rgbquad[i].rgbBlue = entries[i].peBlue;
|
||||||
@ -391,5 +392,7 @@ MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palett
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = SUCCESS;
|
ret = SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,50 @@ MxCompositePresenter::MxCompositePresenter()
|
|||||||
NotificationManager()->Register(this);
|
NotificationManager()->Register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b61a0
|
||||||
|
// list<MxPresenter *,allocator<MxPresenter *> >::~list<MxPresenter *,allocator<MxPresenter *> >
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100b6210
|
||||||
|
// MxCompositePresenter::ClassName
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100b6220
|
||||||
|
// MxCompositePresenter::IsA
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100b62d0
|
||||||
|
// MxCompositePresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100b62f0
|
||||||
|
// MxCompositePresenterList::~MxCompositePresenterList
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b6340
|
||||||
|
// List<MxPresenter *>::~List<MxPresenter *>
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b6390
|
// FUNCTION: LEGO1 0x100b6390
|
||||||
MxCompositePresenter::~MxCompositePresenter()
|
MxCompositePresenter::~MxCompositePresenter()
|
||||||
{
|
{
|
||||||
NotificationManager()->Unregister(this);
|
NotificationManager()->Unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b6410
|
||||||
|
MxResult MxCompositePresenter::StartAction(MxStreamController*, MxDSAction*)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b65e0
|
||||||
|
void MxCompositePresenter::EndAction()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b6760
|
||||||
|
MxLong MxCompositePresenter::Notify(MxParam& p)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x100b67f0
|
// STUB: LEGO1 0x100b67f0
|
||||||
void MxCompositePresenter::VTable0x58()
|
void MxCompositePresenter::VTable0x58()
|
||||||
{
|
{
|
||||||
@ -37,8 +75,40 @@ void MxCompositePresenter::VTable0x5c()
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x100b6b40
|
// FUNCTION: LEGO1 0x100b6b40
|
||||||
void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter)
|
void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter)
|
||||||
|
{
|
||||||
|
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {
|
||||||
|
if (*it == p_presenter) {
|
||||||
|
if (++it == m_list.end()) {
|
||||||
|
if (m_compositePresenter)
|
||||||
|
m_compositePresenter->VTable0x60(this);
|
||||||
|
}
|
||||||
|
else if (m_action->IsA("MxDSSerialAction")) {
|
||||||
|
MxPresenter* presenter = *it;
|
||||||
|
if (presenter->GetCurrentTickleState() == TickleState_Idle)
|
||||||
|
presenter->SetTickleState(TickleState_Ready);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b6bc0
|
||||||
|
void MxCompositePresenter::SetTickleState(TickleState p_tickleState)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b6c30
|
||||||
|
void MxCompositePresenter::Enable(MxBool p_enable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x100b6c80
|
||||||
|
MxBool MxCompositePresenter::HasTickleStatePassed(TickleState p_tickleState)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
#ifndef MXCOMPOSITEPRESENTER_H
|
#ifndef MXCOMPOSITEPRESENTER_H
|
||||||
#define MXCOMPOSITEPRESENTER_H
|
#define MXCOMPOSITEPRESENTER_H
|
||||||
|
|
||||||
|
#include "compat.h" // STL
|
||||||
#include "mxpresenter.h"
|
#include "mxpresenter.h"
|
||||||
#include "mxunklist.h"
|
|
||||||
|
class MxCompositePresenterList : public list<MxPresenter*> {};
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc618
|
// VTABLE: LEGO1 0x100dc618
|
||||||
// SIZE 0x4c
|
// SIZE 0x4c
|
||||||
@ -11,26 +13,31 @@ class MxCompositePresenter : public MxPresenter {
|
|||||||
MxCompositePresenter();
|
MxCompositePresenter();
|
||||||
virtual ~MxCompositePresenter() override; // vtable+0x0
|
virtual ~MxCompositePresenter() override; // vtable+0x0
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b6210
|
virtual MxLong Notify(MxParam& p) override; // vtable+0x04
|
||||||
|
|
||||||
inline virtual const char* ClassName() const override // vtable+0x0c
|
inline virtual const char* ClassName() const override // vtable+0x0c
|
||||||
{
|
{
|
||||||
// GLOBAL: LEGO1 0x100f0774
|
// GLOBAL: LEGO1 0x100f0774
|
||||||
return "MxCompositePresenter";
|
return "MxCompositePresenter";
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b6220
|
|
||||||
inline virtual MxBool IsA(const char* name) const override // vtable+0x10
|
inline virtual MxBool IsA(const char* name) const override // vtable+0x10
|
||||||
{
|
{
|
||||||
return !strcmp(name, MxCompositePresenter::ClassName()) || MxPresenter::IsA(name);
|
return !strcmp(name, MxCompositePresenter::ClassName()) || MxPresenter::IsA(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void VTable0x58();
|
virtual MxResult StartAction(MxStreamController*, MxDSAction*) override; // vtable+0x3c
|
||||||
virtual void VTable0x5c();
|
virtual void EndAction() override; // vtable+0x40
|
||||||
virtual void VTable0x60(MxPresenter* p_presenter);
|
virtual void SetTickleState(TickleState p_tickleState) override; // vtable+0x44
|
||||||
virtual MxBool VTable0x64(undefined4 p_unknown);
|
virtual MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48
|
||||||
|
virtual void Enable(MxBool p_enable) override; // vtable+0x54
|
||||||
|
virtual void VTable0x58(); // vtable+0x58
|
||||||
|
virtual void VTable0x5c(); // vtable+0x5c
|
||||||
|
virtual void VTable0x60(MxPresenter* p_presenter); // vtable+0x60
|
||||||
|
virtual MxBool VTable0x64(undefined4 p_unknown); // vtable+0x64
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MxUnkList m_list;
|
MxCompositePresenterList m_list; // 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MXCOMPOSITEPRESENTER_H
|
#endif // MXCOMPOSITEPRESENTER_H
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
#ifndef MXUNKLIST_H
|
|
||||||
#define MXUNKLIST_H
|
|
||||||
|
|
||||||
#include "decomp.h"
|
|
||||||
#include "mxtypes.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is an as-of-yet unknown list-like data structure.
|
|
||||||
* The class hierarchy/structure isn't quite correct yet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct MxUnkListNode {
|
|
||||||
MxUnkListNode* m_unk00;
|
|
||||||
MxUnkListNode* m_unk04;
|
|
||||||
undefined4 m_unk08;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MxUnkList {
|
|
||||||
public:
|
|
||||||
inline MxUnkList()
|
|
||||||
{
|
|
||||||
undefined unk;
|
|
||||||
this->m_unk00 = unk;
|
|
||||||
|
|
||||||
MxUnkListNode* node = new MxUnkListNode();
|
|
||||||
node->m_unk00 = node;
|
|
||||||
node->m_unk04 = node;
|
|
||||||
|
|
||||||
this->m_head = node;
|
|
||||||
this->m_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
undefined m_unk00;
|
|
||||||
MxUnkListNode* m_head;
|
|
||||||
MxU32 m_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MXUNKLIST_H
|
|
||||||
@ -1,47 +1,200 @@
|
|||||||
import struct
|
import struct
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
|
class MZHeaderNotFoundError(Exception):
|
||||||
|
"""MZ magic string not found at the start of the binary."""
|
||||||
|
|
||||||
|
|
||||||
|
class PEHeaderNotFoundError(Exception):
|
||||||
|
"""PE magic string not found at the offset given in 0x3c."""
|
||||||
|
|
||||||
|
|
||||||
|
class SectionNotFoundError(KeyError):
|
||||||
|
"""The specified section was not found in the file."""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidVirtualAddressError(IndexError):
|
||||||
|
"""The given virtual address is too high or low
|
||||||
|
to point to something in the binary file."""
|
||||||
|
|
||||||
|
|
||||||
|
PEHeader = namedtuple(
|
||||||
|
"PEHeader",
|
||||||
|
[
|
||||||
|
"Signature",
|
||||||
|
"Machine",
|
||||||
|
"NumberOfSections",
|
||||||
|
"TimeDateStamp",
|
||||||
|
"PointerToSymbolTable", # deprecated
|
||||||
|
"NumberOfSymbols", # deprecated
|
||||||
|
"SizeOfOptionalHeader",
|
||||||
|
"Characteristics",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ImageSectionHeader = namedtuple(
|
||||||
|
"ImageSectionHeader",
|
||||||
|
[
|
||||||
|
"Name",
|
||||||
|
"Misc",
|
||||||
|
"VirtualAddress",
|
||||||
|
"SizeOfRawData",
|
||||||
|
"PointerToRawData",
|
||||||
|
"PointerToRelocations",
|
||||||
|
"PointerToLineNumbers",
|
||||||
|
"NumberOfRelocations",
|
||||||
|
"NumberOfLineNumbers",
|
||||||
|
"Characteristics",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def section_name_match(section, name):
|
||||||
|
return section.Name == struct.pack("8s", name.encode("ascii"))
|
||||||
|
|
||||||
|
|
||||||
|
def section_contains_vaddr(section, imagebase, vaddr) -> bool:
|
||||||
|
debased = vaddr - imagebase
|
||||||
|
ofs = debased - section.VirtualAddress
|
||||||
|
return 0 <= ofs < section.SizeOfRawData
|
||||||
|
|
||||||
|
|
||||||
# Declare a class that can automatically convert virtual executable addresses
|
|
||||||
# to file addresses
|
|
||||||
class Bin:
|
class Bin:
|
||||||
def __init__(self, filename, logger):
|
"""Parses a PE format EXE and allows reading data from a virtual address.
|
||||||
|
Reference: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"""
|
||||||
|
|
||||||
|
def __init__(self, filename, logger=None):
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.logger.debug('Parsing headers of "%s"... ', filename)
|
self._debuglog(f'Parsing headers of "{filename}"... ')
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.file = None
|
self.file = None
|
||||||
self.imagebase = None
|
self.imagebase = None
|
||||||
self.textvirt = None
|
self.sections = []
|
||||||
self.textraw = None
|
self.last_section = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.logger.debug(f"Bin {self.filename} Enter")
|
self._debuglog(f"Bin {self.filename} Enter")
|
||||||
self.file = open(self.filename, "rb")
|
self.file = open(self.filename, "rb")
|
||||||
|
|
||||||
# HACK: Strictly, we should be parsing the header, but we know where
|
(mz_str,) = struct.unpack("2s", self.file.read(2))
|
||||||
# everything is in these two files so we just jump straight there
|
if mz_str != b"MZ":
|
||||||
|
raise MZHeaderNotFoundError
|
||||||
|
|
||||||
# Read ImageBase
|
# Skip to PE header offset in MZ header.
|
||||||
self.file.seek(0xB4)
|
self.file.seek(0x3C)
|
||||||
(self.imagebase,) = struct.unpack("<i", self.file.read(4))
|
(pe_header_start,) = struct.unpack("<I", self.file.read(4))
|
||||||
|
|
||||||
# Read .text VirtualAddress
|
# PE header offset is absolute, so seek there
|
||||||
self.file.seek(0x184)
|
self.file.seek(pe_header_start)
|
||||||
(self.textvirt,) = struct.unpack("<i", self.file.read(4))
|
pe_hdr = PEHeader(*struct.unpack("<2s2x2H3I2H", self.file.read(0x18)))
|
||||||
|
|
||||||
# Read .text PointerToRawData
|
if pe_hdr.Signature != b"PE":
|
||||||
self.file.seek(0x18C)
|
raise PEHeaderNotFoundError
|
||||||
(self.textraw,) = struct.unpack("<i", self.file.read(4))
|
|
||||||
self.logger.debug("... Parsing finished")
|
optional_hdr = self.file.read(pe_hdr.SizeOfOptionalHeader)
|
||||||
|
(self.imagebase,) = struct.unpack("<i", optional_hdr[0x1C:0x20])
|
||||||
|
|
||||||
|
self.sections = [
|
||||||
|
ImageSectionHeader(*struct.unpack("<8s6I2HI", self.file.read(0x28)))
|
||||||
|
for i in range(pe_hdr.NumberOfSections)
|
||||||
|
]
|
||||||
|
|
||||||
|
text_section = self._get_section_by_name(".text")
|
||||||
|
self.last_section = text_section
|
||||||
|
|
||||||
|
self._debuglog("... Parsing finished")
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||||
self.logger.debug(f"Bin {self.filename} Exit")
|
self._debuglog(f"Bin {self.filename} Exit")
|
||||||
if self.file:
|
if self.file:
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
|
||||||
def get_addr(self, virt):
|
def _debuglog(self, msg):
|
||||||
return virt - self.imagebase - self.textvirt + self.textraw
|
"""Write to the logger, if present"""
|
||||||
|
if self.logger is not None:
|
||||||
|
self.logger.debug(msg)
|
||||||
|
|
||||||
|
def _set_section_for_vaddr(self, vaddr):
|
||||||
|
if self.last_section is not None and section_contains_vaddr(
|
||||||
|
self.last_section, self.imagebase, vaddr
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
# TODO: assumes no potential for section overlap. reasonable?
|
||||||
|
self.last_section = next(
|
||||||
|
filter(
|
||||||
|
lambda section: section_contains_vaddr(section, self.imagebase, vaddr),
|
||||||
|
self.sections,
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.last_section is None:
|
||||||
|
raise InvalidVirtualAddressError
|
||||||
|
|
||||||
|
def _get_section_by_name(self, name):
|
||||||
|
section = next(
|
||||||
|
filter(lambda section: section_name_match(section, name), self.sections),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if section is None:
|
||||||
|
raise SectionNotFoundError
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
def get_section_offset_by_index(self, index) -> int:
|
||||||
|
"""The symbols output from cvdump gives addresses in this format: AAAA.BBBBBBBB
|
||||||
|
where A is the index (1-based) into the section table and B is the local offset.
|
||||||
|
This will return the virtual address for the start of the section at the given index
|
||||||
|
so you can get the virtual address for whatever symbol you are looking at.
|
||||||
|
"""
|
||||||
|
|
||||||
|
section = self.sections[index - 1]
|
||||||
|
return self.imagebase + section.VirtualAddress
|
||||||
|
|
||||||
|
def get_section_offset_by_name(self, name) -> int:
|
||||||
|
"""Same as above, but use the section name as the lookup"""
|
||||||
|
|
||||||
|
section = self._get_section_by_name(name)
|
||||||
|
return self.imagebase + section.VirtualAddress
|
||||||
|
|
||||||
|
def get_raw_addr(self, vaddr) -> int:
|
||||||
|
"""Returns the raw offset in the PE binary for the given virtual address."""
|
||||||
|
self._set_section_for_vaddr(vaddr)
|
||||||
|
return (
|
||||||
|
vaddr
|
||||||
|
- self.imagebase
|
||||||
|
- self.last_section.VirtualAddress
|
||||||
|
+ self.last_section.PointerToRawData
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_valid_vaddr(self, vaddr) -> bool:
|
||||||
|
"""Does this virtual address point to anything in the exe?"""
|
||||||
|
section = next(
|
||||||
|
filter(
|
||||||
|
lambda section: section_contains_vaddr(section, self.imagebase, vaddr),
|
||||||
|
self.sections,
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
return section is not None
|
||||||
|
|
||||||
def read(self, offset, size):
|
def read(self, offset, size):
|
||||||
self.file.seek(self.get_addr(offset))
|
self._set_section_for_vaddr(offset)
|
||||||
return self.file.read(size)
|
|
||||||
|
raw_addr = self.get_raw_addr(offset)
|
||||||
|
self.file.seek(raw_addr)
|
||||||
|
|
||||||
|
# Clamp the read within the extent of the current section.
|
||||||
|
# Reading off the end will most likely misrepresent the virtual addressing.
|
||||||
|
_size = min(
|
||||||
|
size,
|
||||||
|
self.last_section.PointerToRawData
|
||||||
|
+ self.last_section.SizeOfRawData
|
||||||
|
- raw_addr,
|
||||||
|
)
|
||||||
|
return self.file.read(_size)
|
||||||
|
|||||||
@ -40,11 +40,12 @@ def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None
|
|||||||
current_section = line[4:]
|
current_section = line[4:]
|
||||||
|
|
||||||
if current_section == "SYMBOLS" and "S_GPROC32" in line:
|
if current_section == "SYMBOLS" and "S_GPROC32" in line:
|
||||||
|
sym_section = int(line[21:25], 16)
|
||||||
sym_addr = int(line[26:34], 16)
|
sym_addr = int(line[26:34], 16)
|
||||||
|
|
||||||
info = RecompiledInfo()
|
info = RecompiledInfo()
|
||||||
info.addr = (
|
info.addr = sym_addr + sym_recompfile.get_section_offset_by_index(
|
||||||
sym_addr + sym_recompfile.imagebase + sym_recompfile.textvirt
|
sym_section
|
||||||
)
|
)
|
||||||
|
|
||||||
use_dbg_offs = False
|
use_dbg_offs = False
|
||||||
|
|||||||
@ -86,7 +86,7 @@ def filter_out_ptr(ptype, op_str):
|
|||||||
for i, word in enumerate(words):
|
for i, word in enumerate(words):
|
||||||
try:
|
try:
|
||||||
inttest = int(word, 16)
|
inttest = int(word, 16)
|
||||||
if inttest >= file.imagebase + file.textvirt:
|
if inttest >= file.get_section_offset_by_index(1):
|
||||||
words[i] = placeholder_generator.get(inttest)
|
words[i] = placeholder_generator.get(inttest)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user