Merge remote-tracking branch 'upstream/master' into impl/legosoundmanager

This commit is contained in:
Misha 2023-12-24 14:58:14 -05:00
commit b49307475c
No known key found for this signature in database
GPG Key ID: 8441D12AEF33FED8
39 changed files with 839 additions and 151 deletions

36
.github/workflows/unittest.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Unit Tests
on: [push, pull_request]
jobs:
pytest-win:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Install python libraries
shell: bash
run: |
pip install pytest -r tools/requirements.txt
- name: Run python unit tests (Windows)
shell: bash
run: |
pytest tools/isledecomp
pytest-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install python libraries
shell: bash
run: |
pip install pytest -r tools/requirements.txt
- name: Run python unit tests (Ubuntu)
shell: bash
run: |
pytest tools/isledecomp

View File

@ -1,7 +1,14 @@
#include "jukebox.h"
// STUB: LEGO1 0x1005d660
#include "mxnotificationmanager.h"
#include "mxomni.h"
DECOMP_SIZE_ASSERT(JukeBox, 0x104)
// FUNCTION: LEGO1 0x1005d660
JukeBox::JukeBox()
{
// TODO
m_unk0x100 = 0;
m_unk0xfc = 0;
NotificationManager()->Register(this);
}

View File

@ -1,6 +1,7 @@
#ifndef JUKEBOX_H
#define JUKEBOX_H
#include "decomp.h"
#include "legoworld.h"
// VTABLE: LEGO1 0x100d8958
@ -21,6 +22,11 @@ class JukeBox : public LegoWorld {
{
return !strcmp(p_name, JukeBox::ClassName()) || LegoWorld::IsA(p_name);
}
private:
undefined m_unk0xf8[4]; // 0xf8
undefined4 m_unk0xfc; // 0xfc
undefined2 m_unk0x100; // 0x100
};
#endif // JUKEBOX_H

View File

@ -33,7 +33,7 @@ class MxCore {
inline MxU32 GetId() { return m_id; }
private:
MxU32 m_id;
MxU32 m_id; // 0x04
};
#endif // MXCORE_H

View File

@ -58,18 +58,134 @@ MxResult MxDiskStreamController::VTable0x34(undefined4)
return FAILURE;
}
// STUB: LEGO1 0x100c7ac0
MxResult MxDiskStreamController::VTable0x28()
// FUNCTION: LEGO1 0x100c7980
void MxDiskStreamController::FUN_100c7980()
{
// TODO
return FAILURE;
MxDSBuffer* buffer;
MxDSStreamingAction* action = NULL;
{
MxAutoLocker lock(&this->m_criticalSection);
if (m_unk0x3c.size() && m_unk0x8c < m_provider->GetStreamBuffersNum()) {
buffer = new MxDSBuffer();
if (buffer->AllocateBuffer(m_provider->GetFileSize(), MxDSBufferType_Chunk) != SUCCESS) {
if (buffer)
delete buffer;
return;
}
action = VTable0x28();
if (!action) {
if (buffer)
delete buffer;
return;
}
action->SetUnknowna0(buffer);
m_unk0x8c++;
}
}
if (action) {
((MxDiskStreamProvider*) m_provider)->FUN_100d1780(action);
}
}
// STUB: LEGO1 0x100c7c00
// FUNCTION: LEGO1 0x100c7ac0
MxDSStreamingAction* MxDiskStreamController::VTable0x28()
{
MxAutoLocker lock(&this->m_criticalSection);
MxDSAction* oldAction;
MxDSStreamingAction* result = NULL;
MxU32 filesize = m_provider->GetFileSize();
if (m_unk0x3c.PopFront(oldAction)) {
result = new MxDSStreamingAction((MxDSStreamingAction&) *oldAction);
if (result) {
MxU32 offset = result->GetBufferOffset() + filesize;
((MxDSStreamingAction*) oldAction)->SetUnknown94(offset);
((MxDSStreamingAction*) oldAction)->SetBufferOffset(offset);
m_unk0x3c.push_back(oldAction);
}
}
return result;
}
// FUNCTION: LEGO1 0x100c7c00
MxResult MxDiskStreamController::VTable0x30(MxDSAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
MxResult result = MxStreamController::VTable0x30(p_action);
MxDSStreamingAction* item;
while (TRUE) {
item = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE);
if (item == NULL) {
break;
}
FUN_100c7cb0(item);
}
while (TRUE) {
item = (MxDSStreamingAction*) m_list0x64.Find(p_action, TRUE);
if (item == NULL) {
break;
}
FUN_100c7cb0(item);
}
return result;
}
// FUNCTION: LEGO1 0x100c7cb0
void MxDiskStreamController::FUN_100c7cb0(MxDSStreamingAction* p_action)
{
if (p_action->GetUnknowna0()) {
FUN_100c7ce0(p_action->GetUnknowna0());
}
p_action->SetUnknowna0(NULL);
delete p_action;
}
// FUNCTION: LEGO1 0x100c7ce0
void MxDiskStreamController::FUN_100c7ce0(MxDSBuffer* p_buffer)
{
switch (p_buffer->GetMode()) {
case MxDSBufferType_Chunk:
m_unk0x8c--;
case MxDSBufferType_Allocate:
case MxDSBufferType_Unknown:
delete p_buffer;
break;
}
}
// FUNCTION: LEGO1 0x100c7d10
MxResult MxDiskStreamController::FUN_100c7d10()
{
MxAutoLocker lock(&this->m_criticalSection);
MxDSStreamingAction* action = FUN_100c7db0();
if (!action)
return FAILURE;
if (FUN_100c8360(action) != SUCCESS) {
VTable0x24(action);
FUN_100c7cb0(action);
return FAILURE;
}
return SUCCESS;
}
// STUB: LEGO1 0x100c7db0
MxDSStreamingAction* MxDiskStreamController::FUN_100c7db0()
{
// TODO
return FAILURE;
return NULL;
}
// FUNCTION: LEGO1 0x100c7f40
@ -115,6 +231,37 @@ MxResult MxDiskStreamController::VTable0x24(MxDSAction* p_action)
return FAILURE;
}
// FUNCTION: LEGO1 0x100c8360
MxResult MxDiskStreamController::FUN_100c8360(MxDSStreamingAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
MxDSBuffer* buffer = p_action->GetUnknowna0();
MxDSStreamingAction* action2 = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE);
buffer->FUN_100c6f80(p_action->GetUnknown94() - p_action->GetBufferOffset());
buffer->FUN_100c67b0(this, p_action, &action2);
if (buffer->GetRefCount()) {
p_action->SetUnknowna0(NULL);
InsertToList74(buffer);
}
if (action2) {
if (action2->GetUnknowna0() == NULL) {
FUN_100c7cb0(action2);
}
else {
if (action2->GetObjectId() == -1) {
action2->SetObjectId(p_action->GetObjectId());
}
m_list0x90.push_back(action2);
}
}
FUN_100c7cb0(p_action);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c84a0
void MxDiskStreamController::InsertToList74(MxDSBuffer* p_buffer)
{
@ -122,9 +269,39 @@ void MxDiskStreamController::InsertToList74(MxDSBuffer* p_buffer)
m_list0x74.push_back(p_buffer);
}
// STUB: LEGO1 0x100c8640
MxResult MxDiskStreamController::Tickle()
// STUB: LEGO1 0x100c8540
void MxDiskStreamController::FUN_100c8540()
{
// TODO
}
// FUNCTION: LEGO1 0x100c8640
MxResult MxDiskStreamController::Tickle()
{
if (m_unk0xc4) {
FUN_100c7d10();
}
FUN_100c8540();
FUN_100c8720();
if (m_unk0x70) {
FUN_100c7980();
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c8720
void MxDiskStreamController::FUN_100c8720()
{
MxAutoLocker lock(&this->m_critical9c);
MxDSStreamingAction* action;
while (m_list0xb8.size() != 0) {
action = (MxDSStreamingAction*) m_list0xb8.front();
m_list0xb8.pop_front();
FUN_100c7cb0(action);
}
}

View File

@ -22,7 +22,7 @@ class MxDiskStreamController : public MxStreamController {
virtual MxResult VTable0x18(undefined4, undefined4) override; // vtable+0x18
virtual MxResult VTable0x20(MxDSAction* p_action) override; // vtable+0x20
virtual MxResult VTable0x24(MxDSAction* p_action) override; // vtable+0x24
virtual MxResult VTable0x28() override; // vtable+0x28
virtual MxDSStreamingAction* VTable0x28() override; // vtable+0x28
virtual MxResult VTable0x30(MxDSAction* p_action) override; // vtable+0x30
virtual MxResult VTable0x34(undefined4); // vtable+0x34
@ -50,8 +50,16 @@ class MxDiskStreamController : public MxStreamController {
MxStreamListMxDSAction m_list0xb8; // 0xb8
undefined m_unk0xc4; // 0xc4
void FUN_100c7cb0(MxDSStreamingAction* p_action);
void FUN_100c7ce0(MxDSBuffer* p_buffer);
MxResult FUN_100c7d10();
void FUN_100c7980();
MxDSStreamingAction* FUN_100c7db0();
void FUN_100c7f40(MxDSStreamingAction* p_streamingaction);
MxResult FUN_100c8360(MxDSStreamingAction* p_action);
void InsertToList74(MxDSBuffer* p_buffer);
void FUN_100c8540();
void FUN_100c8720();
};
// TEMPLATE: LEGO1 0x100c7330

View File

@ -1,5 +1,6 @@
#include "mxdiskstreamprovider.h"
#include "mxdsbuffer.h"
#include "mxomni.h"
#include "mxstreamcontroller.h"
#include "mxstring.h"
@ -58,10 +59,9 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
}
m_remainingWork = 1;
MxResult success = m_busySemaphore.Init(0, 100);
m_thread.StartWithTarget(this);
m_busySemaphore.Init(0, 100);
if (success == SUCCESS && p_resource != NULL) {
if (m_thread.StartWithTarget(this) == SUCCESS && p_resource != NULL) {
result = SUCCESS;
}
}
@ -71,7 +71,7 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
}
// STUB: LEGO1 0x100d15e0
void MxDiskStreamProvider::VTable0x20(undefined4)
void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action)
{
// TODO
}
@ -87,6 +87,13 @@ MxResult MxDiskStreamProvider::WaitForWorkToComplete()
return SUCCESS;
}
// STUB: LEGO1 0x100d1780
MxResult MxDiskStreamProvider::FUN_100d1780(MxDSStreamingAction* p_action)
{
// TODO
return FAILURE;
}
// STUB: LEGO1 0x100d18f0
void MxDiskStreamProvider::PerformWork()
{
@ -100,7 +107,7 @@ MxU32 MxDiskStreamProvider::GetFileSize()
}
// FUNCTION: LEGO1 0x100d1ea0
MxU32 MxDiskStreamProvider::GetStreamBuffersNum()
MxS32 MxDiskStreamProvider::GetStreamBuffersNum()
{
return m_pFile->GetStreamBuffersNum();
}

View File

@ -10,6 +10,7 @@
#include "mxthread.h"
class MxDiskStreamProvider;
class MxDSStreamingAction;
// VTABLE: LEGO1 0x100dd130
class MxDiskStreamProviderThread : public MxThread {
@ -43,13 +44,13 @@ class MxDiskStreamProvider : public MxStreamProvider {
}
MxResult WaitForWorkToComplete();
MxResult FUN_100d1780(MxDSStreamingAction* p_action);
void PerformWork();
virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14
virtual MxU32 GetFileSize() override; // vtable+0x18
virtual MxU32 GetStreamBuffersNum() override; // vtable+0x1c
virtual void VTable0x20(undefined4) override; // vtable+0x20
virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c
virtual void VTable0x20(MxDSAction* p_action) override; // vtable+0x20
virtual MxU32 GetLengthInDWords() override; // vtable+0x24
virtual MxU32* GetBufferForDWords() override; // vtable+0x28

View File

@ -123,7 +123,11 @@ MxResult MxDSBuffer::SetBufferPointer(MxU32* p_buffer, MxU32 p_size)
}
// STUB: LEGO1 0x100c67b0
MxResult MxDSBuffer::FUN_100c67b0(MxStreamController* p_controller, MxDSAction* p_action, undefined4*)
MxResult MxDSBuffer::FUN_100c67b0(
MxStreamController* p_controller,
MxDSAction* p_action,
MxDSStreamingAction** p_streamingAction
)
{
// TODO STUB
return FAILURE;

View File

@ -33,7 +33,11 @@ class MxDSBuffer : public MxCore {
MxResult AllocateBuffer(MxU32 p_bufferSize, MxDSBufferType p_mode);
MxResult SetBufferPointer(MxU32* p_buffer, MxU32 p_size);
MxResult FUN_100c67b0(MxStreamController* p_controller, MxDSAction* p_action, undefined4*);
MxResult FUN_100c67b0(
MxStreamController* p_controller,
MxDSAction* p_action,
MxDSStreamingAction** p_streamingAction
);
MxResult CreateObject(
MxStreamController* p_controller,
MxU32* p_data,
@ -55,6 +59,8 @@ class MxDSBuffer : public MxCore {
inline MxU8* GetBuffer() { return m_pBuffer; }
inline MxU32 GetWriteOffset() { return m_writeOffset; }
inline MxU16 GetRefCount() { return m_refcount; }
inline MxDSBufferType GetMode() { return m_mode; }
private:
MxU8* m_pBuffer; // 0x08

View File

@ -33,6 +33,7 @@ class MxDSMediaAction : public MxDSAction {
void CopyMediaSrcPath(const char* p_mediaSrcPath);
inline MxS32 GetFramesPerSecond() const { return this->m_framesPerSecond; }
inline MxS32 GetMediaFormat() const { return this->m_mediaFormat; }
inline MxS32 GetPaletteManagement() const { return this->m_paletteManagement; }
inline MxLong GetSustainTime() const { return this->m_sustainTime; }

View File

@ -35,7 +35,10 @@ class MxDSStreamingAction : public MxDSAction {
inline MxDSBuffer* GetUnknowna0() { return m_unk0xa0; }
inline MxDSBuffer* GetUnknowna4() { return m_unk0xa4; }
inline MxDSAction* GetInternalAction() { return m_internalAction; }
inline MxU32 GetBufferOffset() { return m_bufferOffset; }
inline void SetUnknown94(MxU32 p_unk0x94) { m_unk0x94 = p_unk0x94; }
inline void SetUnknowna0(MxDSBuffer* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; }
inline void SetBufferOffset(MxU32 p_bufferOffset) { m_bufferOffset = p_bufferOffset; }
private:
MxU32 m_unk0x94;

View File

@ -1,42 +1,125 @@
#include "mxdssubscriber.h"
#include "mxstreamcontroller.h"
DECOMP_SIZE_ASSERT(MxDSSubscriber, 0x4c);
// STUB: LEGO1 0x100b7bb0
// FUNCTION: LEGO1 0x100b7bb0
MxDSSubscriber::MxDSSubscriber()
{
// TODO
m_unk0x48 = -1;
m_objectId = -1;
m_unk0x20 = NULL;
m_unk0x3c = NULL;
}
// STUB: LEGO1 0x100b7e00
// FUNCTION: LEGO1 0x100b7e00
MxDSSubscriber::~MxDSSubscriber()
{
// TODO
if (m_controller)
m_controller->FUN_100c1620(this);
DeleteChunks();
if (m_unk0x20)
delete m_unk0x20;
m_unk0x20 = NULL;
if (m_unk0x3c)
delete m_unk0x3c;
m_unk0x3c = NULL;
}
// STUB: LEGO1 0x100b7ed0
MxResult MxDSSubscriber::FUN_100b7ed0(MxStreamController*, MxU32, MxS16)
// FUNCTION: LEGO1 0x100b7ed0
MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48)
{
// TODO
m_objectId = p_objectId;
m_unk0x48 = p_unk0x48;
if (!p_controller)
return FAILURE;
m_controller = p_controller;
m_unk0x20 = new MxStreamChunkListCursor(&m_unk0x08);
if (!m_unk0x20)
return FAILURE;
m_unk0x3c = new MxStreamChunkListCursor(&m_unk0x24);
if (!m_unk0x3c)
return FAILURE;
m_controller->FUN_100c15d0(this);
return SUCCESS;
}
// STUB: LEGO1 0x100b8250
// FUNCTION: LEGO1 0x100b8030
void MxDSSubscriber::DeleteChunks()
{
if (m_controller) {
MxStreamChunk* chunk = NULL;
while (m_unk0x20->First(chunk)) {
m_unk0x20->Detach();
delete chunk;
}
while (m_unk0x3c->First(chunk)) {
m_unk0x3c->Detach();
delete chunk;
}
}
}
// FUNCTION: LEGO1 0x100b8150
MxResult MxDSSubscriber::AddChunk(MxStreamChunk* p_chunk, MxBool p_append)
{
if (m_unk0x20) {
if (p_append)
m_unk0x08.Append(p_chunk);
else
m_unk0x08.Prepend(p_chunk);
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100b8250
MxStreamChunk* MxDSSubscriber::FUN_100b8250()
{
// TODO
return NULL;
MxStreamChunk* chunk = NULL;
if (m_unk0x20)
m_unk0x20->First(chunk);
if (chunk) {
m_unk0x20->Detach();
m_unk0x24.Append(chunk);
}
return chunk;
}
// STUB: LEGO1 0x100b8360
// FUNCTION: LEGO1 0x100b8360
MxStreamChunk* MxDSSubscriber::FUN_100b8360()
{
// TODO
return NULL;
MxStreamChunk* chunk = NULL;
if (m_unk0x20)
m_unk0x20->First(chunk);
return chunk;
}
// STUB: LEGO1 0x100b8390
void MxDSSubscriber::FUN_100b8390(MxStreamChunk*)
// FUNCTION: LEGO1 0x100b8390
void MxDSSubscriber::FUN_100b8390(MxStreamChunk* p_chunk)
{
// TODO
if (p_chunk) {
if (m_unk0x3c->Find(p_chunk)) {
m_unk0x3c->Detach();
if (p_chunk)
delete p_chunk;
}
else if ((p_chunk->GetFlags() & MxStreamChunk::Flag_Bit1) != 0 && p_chunk)
delete p_chunk;
}
}

View File

@ -5,6 +5,7 @@
#include "mxcore.h"
#include "mxdschunk.h"
#include "mxstreamchunk.h"
#include "mxstreamchunklist.h"
class MxStreamController;
@ -28,13 +29,27 @@ class MxDSSubscriber : public MxCore {
return !strcmp(p_name, MxDSSubscriber::ClassName()) || MxCore::IsA(p_name);
}
MxResult FUN_100b7ed0(MxStreamController*, MxU32, MxS16);
MxResult Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48);
void DeleteChunks();
MxResult AddChunk(MxStreamChunk* p_chunk, MxBool p_append);
MxStreamChunk* FUN_100b8250();
MxStreamChunk* FUN_100b8360();
void FUN_100b8390(MxStreamChunk*);
void FUN_100b8390(MxStreamChunk* p_chunk);
private:
undefined m_pad[0x44]; // 0x8
MxStreamChunkList m_unk0x08; // 0x08
MxStreamChunkListCursor* m_unk0x20; // 0x20
MxStreamChunkList m_unk0x24; // 0x24
MxStreamChunkListCursor* m_unk0x3c; // 0x3c
MxStreamController* m_controller; // 0x40
MxU32 m_objectId; // 0x44
MxS16 m_unk0x48; // 0x48
};
// SYNTHETIC: LEGO1 0x100b7de0
// MxDSSubscriber::`scalar deleting destructor'
// TEMPLATE: LEGO1 0x100b7d00
// MxStreamChunkList::~MxStreamChunkList
#endif // MXDSSUBSCRIBER_H

View File

@ -12,8 +12,8 @@ DECOMP_SIZE_ASSERT(MxFlcPresenter, 0x68);
MxFlcPresenter::MxFlcPresenter()
{
this->m_flicHeader = NULL;
this->m_flags &= 0xfd;
this->m_flags &= 0xfb;
this->m_flags &= ~Flag_Bit2;
this->m_flags &= ~Flag_Bit3;
}
// FUNCTION: LEGO1 0x100b3420

View File

@ -54,6 +54,7 @@ class MxList : protected MxCollection<T> {
virtual ~MxList() override;
void Append(T p_obj) { InsertEntry(p_obj, this->m_last, NULL); };
void Prepend(T p_obj) { InsertEntry(p_obj, NULL, this->m_first); };
void DeleteAll(MxBool p_destroy = TRUE);
MxU32 GetCount() { return this->m_count; }
@ -92,6 +93,8 @@ class MxListCursor : public MxCore {
void Destroy();
MxBool Next(T& p_obj);
MxBool Current(T& p_obj);
MxBool First(T& p_obj);
MxBool Last(T& p_obj);
MxBool Advance();
MxBool HasMatch() { return m_match != NULL; }
void SetValue(T p_obj);
@ -193,8 +196,10 @@ inline MxBool MxListCursor<T>::Find(T p_obj)
template <class T>
inline void MxListCursor<T>::Detach()
{
m_list->DeleteEntry(m_match);
m_match = NULL;
if (m_match) {
m_list->DeleteEntry(m_match);
m_match = NULL;
}
}
template <class T>
@ -202,7 +207,8 @@ inline void MxListCursor<T>::Destroy()
{
if (m_match) {
m_list->m_customDestructor(m_match->GetValue());
Detach();
m_list->DeleteEntry(m_match);
m_match = NULL;
}
}
@ -229,6 +235,26 @@ inline MxBool MxListCursor<T>::Current(T& p_obj)
return m_match != NULL;
}
template <class T>
inline MxBool MxListCursor<T>::First(T& p_obj)
{
m_match = m_list->m_first;
if (m_match)
p_obj = m_match->GetValue();
return m_match != NULL;
}
template <class T>
inline MxBool MxListCursor<T>::Last(T& p_obj)
{
m_match = m_list->m_last;
if (m_match)
p_obj = m_match->GetValue();
return m_match != NULL;
}
template <class T>
inline MxBool MxListCursor<T>::Advance()
{

View File

@ -20,8 +20,8 @@ MxLoopingFlcPresenter::~MxLoopingFlcPresenter()
void MxLoopingFlcPresenter::Init()
{
this->m_unk0x68 = 0;
this->m_flags &= 0xfd;
this->m_flags &= 0xfb;
this->m_flags &= ~Flag_Bit2;
this->m_flags &= ~Flag_Bit3;
}
// STUB: LEGO1 0x100b4432

View File

@ -1,6 +1,7 @@
#include "mxloopingsmkpresenter.h"
#include "decomp.h"
#include "mxautolocker.h"
#include "mxdsmediaaction.h"
DECOMP_SIZE_ASSERT(MxLoopingSmkPresenter, 0x724);
@ -19,12 +20,112 @@ MxLoopingSmkPresenter::~MxLoopingSmkPresenter()
// FUNCTION: LEGO1 0x100b49b0
void MxLoopingSmkPresenter::Init()
{
this->m_unk0x720 = 0;
this->m_flags &= 0xfd;
this->m_flags &= 0xfb;
this->m_elapsedDuration = 0;
this->m_flags &= ~Flag_Bit2;
this->m_flags &= ~Flag_Bit3;
}
// STUB: LEGO1 0x100b49d0
// FUNCTION: LEGO1 0x100b49d0
void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor)
{
m_criticalSection.Enter();
Init();
m_criticalSection.Leave();
if (!p_fromDestructor)
MxSmkPresenter::Destroy();
}
// FUNCTION: LEGO1 0x100b4a00
void MxLoopingSmkPresenter::VTable0x88()
{
if (m_mxSmack.m_smackTag.Frames == m_currentFrame) {
m_currentFrame = 0;
// TODO: struct incorrect, Palette at wrong offset?
memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette));
}
}
// FUNCTION: LEGO1 0x100b4a30
void MxLoopingSmkPresenter::NextFrame()
{
MxStreamChunk* chunk = NextChunk();
if (chunk->GetFlags() & MxStreamChunk::Flag_Bit2) {
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_Repeating;
}
else {
LoadFrame(chunk);
AppendChunk(chunk);
m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond();
}
m_subscriber->FUN_100b8390(chunk);
}
// FUNCTION: LEGO1 0x100b4a90
void MxLoopingSmkPresenter::VTable0x8c()
{
if (m_action->GetDuration() < m_elapsedDuration) {
m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState;
m_currentTickleState = TickleState_unk5;
}
else {
MxStreamChunk* chunk;
m_cursor->Current(chunk);
LoadFrame(chunk);
m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond();
}
}
// FUNCTION: LEGO1 0x100b4b00
void MxLoopingSmkPresenter::RepeatingTickle()
{
for (MxS16 i = 0; i < m_unk0x5c; i++) {
if (!m_cursor->HasMatch()) {
MxStreamChunk* chunk;
MxStreamChunkListCursor cursor(m_chunks);
cursor.Last(chunk);
MxLong time = chunk->GetTime();
cursor.First(chunk);
time -= chunk->GetTime();
time += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond();
cursor.Reset();
while (cursor.Next(chunk))
chunk->SetTime(chunk->GetTime() + time);
m_cursor->Advance();
}
MxStreamChunk* chunk;
m_cursor->Current(chunk);
if (m_action->GetElapsedTime() < chunk->GetTime())
break;
VTable0x8c();
m_cursor->Next(chunk);
if (m_currentTickleState != TickleState_Repeating)
break;
}
}
// FUNCTION: LEGO1 0x100b4cd0
MxResult MxLoopingSmkPresenter::AddToManager()
{
MxAutoLocker lock(&m_criticalSection);
return MxSmkPresenter::AddToManager();
}
// FUNCTION: LEGO1 0x100b4d40
void MxLoopingSmkPresenter::Destroy()
{
Destroy(FALSE);
}

View File

@ -18,11 +18,21 @@ class MxLoopingSmkPresenter : public MxSmkPresenter {
return "MxLoopingSmkPresenter";
}
virtual void RepeatingTickle() override; // vtable+0x24
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38
virtual void NextFrame() override; // vtable+0x64
virtual void VTable0x88() override; // vtable+0x88
virtual void VTable0x8c(); // vtable+0x8c
private:
void Init();
void Destroy(MxBool p_fromDestructor);
undefined4 m_unk0x720;
MxLong m_elapsedDuration; // 0x720
};
// SYNTHETIC: LEGO1 0x100b4930
// MxLoopingSmkPresenter::`scalar deleting destructor'
#endif // MXLOOPINGSMKPRESENTER_H

View File

@ -124,7 +124,7 @@ MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAct
m_subscriber = new MxDSSubscriber;
if (!m_subscriber ||
m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS)
m_subscriber->Create(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS)
goto done;
}

View File

@ -40,8 +40,9 @@ MxResult MxRAMStreamController::Open(const char* p_filename)
MxResult MxRAMStreamController::VTable0x20(MxDSAction* p_action)
{
MxAutoLocker locker(&m_criticalSection);
MxS16 unk0x24 = 0;
MxS32 unk0x24 = 0;
MxResult result = FAILURE;
if (p_action->GetUnknown24() == -1) {
p_action->SetUnknown24(-3);
MxDSAction* action = m_unk0x54.Find(p_action, FALSE);
@ -84,12 +85,15 @@ MxResult MxRAMStreamController::DeserializeObject(MxDSStreamingAction& p_action)
{
MxAutoLocker locker(&m_criticalSection);
MxResult result;
undefined4 value = 0;
MxDSStreamingAction* value = NULL;
do {
m_buffer.FUN_100c6f80(p_action.GetUnknown94());
// Probably not MxResult, see below
result = m_buffer.FUN_100c67b0(this, &p_action, &value);
} while (m_unk0x3c.Find(&p_action, FALSE) != NULL);
return result;
return result == SUCCESS ? SUCCESS : FAILURE;
}
// STUB: LEGO1 0x100d0d80

View File

@ -23,7 +23,7 @@ MxU32 MxRAMStreamProvider::GetFileSize()
}
// FUNCTION: LEGO1 0x100d0940
MxU32 MxRAMStreamProvider::GetStreamBuffersNum()
MxS32 MxRAMStreamProvider::GetStreamBuffersNum()
{
return 1;
}

View File

@ -24,7 +24,7 @@ class MxRAMStreamProvider : public MxStreamProvider {
virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14
virtual MxU32 GetFileSize() override; // vtable+0x18
virtual MxU32 GetStreamBuffersNum() override; // vtable+0x1c
virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c
virtual MxU32 GetLengthInDWords() override; // vtable+0x24
virtual MxU32* GetBufferForDWords() override; // vtable+0x28

View File

@ -21,10 +21,10 @@ MxSmkPresenter::~MxSmkPresenter()
// FUNCTION: LEGO1 0x100b38d0
void MxSmkPresenter::Init()
{
m_unk0x71c = 0;
m_currentFrame = 0;
memset(&m_mxSmack, 0, sizeof(m_mxSmack));
m_flags &= 0xfd;
m_flags &= 0xfb;
m_flags &= ~Flag_Bit2;
m_flags &= ~Flag_Bit3;
}
// FUNCTION: LEGO1 0x100b3900
@ -65,8 +65,8 @@ void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk)
MxU8* bitmapData = m_bitmap->GetBitmapData();
MxU8* chunkData = p_chunk->GetData();
MxBool paletteChanged = m_mxSmack.m_frameTypes[m_unk0x71c] & 1;
m_unk0x71c++;
MxBool paletteChanged = m_mxSmack.m_frameTypes[m_currentFrame] & 1;
m_currentFrame++;
VTable0x88();
MxRectList list(TRUE);
@ -90,13 +90,13 @@ void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk)
void MxSmkPresenter::VTable0x88()
{
if ((m_mxSmack.m_smackTag.SmackerType & 1) != 0) {
MxU32 und = (m_unk0x71c % m_mxSmack.m_smackTag.Frames);
if (1 < m_unk0x71c && und == 1)
m_unk0x71c = 1;
MxU32 und = (m_currentFrame % m_mxSmack.m_smackTag.Frames);
if (1 < m_currentFrame && und == 1)
m_currentFrame = 1;
}
else {
if (m_mxSmack.m_smackTag.Frames == m_unk0x71c) {
m_unk0x71c = 0;
if (m_mxSmack.m_smackTag.Frames == m_currentFrame) {
m_currentFrame = 0;
// TODO: struct incorrect, Palette at wrong offset?
memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette));
}
@ -111,6 +111,12 @@ void MxSmkPresenter::RealizePalette()
delete palette;
}
// FUNCTION: LEGO1 0x100b42f0
MxResult MxSmkPresenter::AddToManager()
{
return MxVideoPresenter::AddToManager();
}
// FUNCTION: LEGO1 0x100b4300
void MxSmkPresenter::Destroy()
{

View File

@ -25,6 +25,7 @@ class MxSmkPresenter : public MxVideoPresenter {
return !strcmp(p_name, MxSmkPresenter::ClassName()) || MxVideoPresenter::IsA(p_name);
}
virtual MxResult AddToManager() override; // vtable+0x34
virtual void Destroy() override; // vtable+0x38
virtual void LoadHeader(MxStreamChunk* p_chunk) override; // vtable+0x5c
virtual void CreateBitmap() override; // vtable+0x60
@ -36,8 +37,9 @@ class MxSmkPresenter : public MxVideoPresenter {
void Init();
void Destroy(MxBool p_fromDestructor);
MxSmack m_mxSmack; // 0x64
undefined4 m_unk0x71c; // 0x71c
protected:
MxSmack m_mxSmack; // 0x64
MxU32 m_currentFrame; // 0x71c
};
#endif // MXSMKPRESENTER_H

View File

@ -2,6 +2,7 @@
#include "legoomni.h"
#include "mxautolocker.h"
#include "mxdsstreamingaction.h"
#include "mxnextactiondatastart.h"
#include "mxstreamchunk.h"
@ -21,23 +22,46 @@ MxResult MxStreamController::VTable0x1c(undefined4, undefined4)
}
// FUNCTION: LEGO1 0x100b9420
MxResult MxStreamController::VTable0x28()
MxDSStreamingAction* MxStreamController::VTable0x28()
{
return SUCCESS;
return NULL;
}
// FUNCTION: LEGO1 0x100c0b90
MxStreamController::MxStreamController()
{
m_provider = NULL;
m_unk0x2c = 0; // TODO: probably also NULL
m_unk0x2c = NULL;
m_action0x60 = NULL;
}
// STUB: LEGO1 0x100c1290
// FUNCTION: LEGO1 0x100c1290
MxStreamController::~MxStreamController()
{
// TODO
MxAutoLocker lock(&m_criticalSection);
MxDSSubscriber* subscriber;
while (m_subscriberList.PopFront(subscriber))
delete subscriber;
MxDSAction* action;
while (m_unk0x3c.PopFront(action))
delete action;
if (m_provider) {
MxStreamProvider* provider = m_provider;
m_provider = NULL;
provider->VTable0x20(&MxDSAction());
delete provider;
}
if (m_unk0x2c) {
delete m_unk0x2c;
m_unk0x2c = NULL;
}
while (m_unk0x54.PopFront(action))
delete action;
}
// FUNCTION: LEGO1 0x100c1520
@ -51,6 +75,18 @@ MxResult MxStreamController::Open(const char* p_filename)
return SUCCESS;
}
// STUB: LEGO1 0x100c15d0
void MxStreamController::FUN_100c15d0(MxDSSubscriber* p_subscriber)
{
// TODO
}
// STUB: LEGO1 0x100c1620
void MxStreamController::FUN_100c1620(MxDSSubscriber* p_subscriber)
{
// TODO
}
// FUNCTION: LEGO1 0x100c1690
MxResult MxStreamController::VTable0x20(MxDSAction* p_action)
{

View File

@ -7,16 +7,18 @@
#include "mxcriticalsection.h"
#include "mxdsaction.h"
#include "mxdsobject.h"
#include "mxdssubscriber.h"
#include "mxstl/stlcompat.h"
#include "mxstreamlist.h"
#include "mxstreamprovider.h"
class MxDSStreamingAction;
// VTABLE: LEGO1 0x100dc968
// SIZE 0x64
class MxStreamController : public MxCore {
public:
MxStreamController();
virtual ~MxStreamController() override; // vtable+0x0
// FUNCTION: LEGO1 0x100c0f10
@ -37,16 +39,18 @@ class MxStreamController : public MxCore {
virtual MxResult VTable0x1c(undefined4, undefined4); // vtable+0x1c
virtual MxResult VTable0x20(MxDSAction* p_action); // vtable+0x20
virtual MxResult VTable0x24(MxDSAction* p_action); // vtable+0x24
virtual MxResult VTable0x28(); // vtable+0x28
virtual MxDSStreamingAction* VTable0x28(); // vtable+0x28
virtual MxResult VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c
virtual MxResult VTable0x30(MxDSAction* p_action); // vtable+0x30
void FUN_100c15d0(MxDSSubscriber* p_subscriber);
void FUN_100c1620(MxDSSubscriber* p_subscriber);
MxResult FUN_100c1800(MxDSAction* p_action, MxU32 p_val);
MxBool FUN_100c20d0(MxDSObject& p_obj);
MxResult FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval);
MxPresenter* FUN_100c1e70(MxDSAction& p_action);
MxResult InsertActionToList54(MxDSAction* p_action);
MxResult FUN_100c1f00(MxDSAction* p_action);
MxBool FUN_100c20d0(MxDSObject& p_obj);
MxResult InsertActionToList54(MxDSAction* p_action);
inline MxAtomId& GetAtom() { return m_atom; };
inline MxStreamListMxDSAction& GetUnk0x54() { return m_unk0x54; };
@ -55,7 +59,7 @@ class MxStreamController : public MxCore {
MxCriticalSection m_criticalSection; // 0x8
MxAtomId m_atom; // 0x24
MxStreamProvider* m_provider; // 0x28
undefined4 m_unk0x2c; // 0x2c
undefined4* m_unk0x2c; // 0x2c
MxStreamListMxDSSubscriber m_subscriberList; // 0x30
MxStreamListMxDSAction m_unk0x3c; // 0x3c
MxStreamListMxNextActionDataStart m_nextActionList; // 0x48

View File

@ -46,7 +46,6 @@ MxStreamer::~MxStreamer()
// FUNCTION: LEGO1 0x100b92c0
MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType)
{
// TODO
MxStreamController* stream = NULL;
if (!GetOpenStream(p_name)) {
@ -59,7 +58,7 @@ MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType)
break;
}
if (!stream || stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS) {
if (stream && (stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS)) {
delete stream;
stream = NULL;
}

View File

@ -7,7 +7,18 @@
#include "mxstl/stlcompat.h"
template <class T>
class MxStreamList : public list<T> {};
class MxStreamList : public list<T> {
public:
MxBool PopFront(T& p_obj)
{
if (empty())
return FALSE;
p_obj = front();
pop_front();
return TRUE;
}
};
// SIZE 0xc
class MxStreamListMxDSAction : public MxStreamList<MxDSAction*> {

View File

@ -12,6 +12,6 @@ MxResult MxStreamProvider::SetResourceToGet(MxStreamController* p_resource)
}
// FUNCTION: LEGO1 0x100d07d0
void MxStreamProvider::VTable0x20(undefined4)
void MxStreamProvider::VTable0x20(MxDSAction* p_action)
{
}

View File

@ -6,6 +6,7 @@
#include "mxdsfile.h"
class MxStreamController;
class MxDSAction;
// VTABLE: LEGO1 0x100dd100
// SIZE 0x10
@ -27,8 +28,8 @@ class MxStreamProvider : public MxCore {
virtual MxResult SetResourceToGet(MxStreamController* p_resource); // vtable+0x14
virtual MxU32 GetFileSize() = 0; // vtable+0x18
virtual MxU32 GetStreamBuffersNum() = 0; // vtable+0x1c
virtual void VTable0x20(undefined4); // vtable+0x20
virtual MxS32 GetStreamBuffersNum() = 0; // vtable+0x1c
virtual void VTable0x20(MxDSAction* p_action); // vtable+0x20
virtual MxU32 GetLengthInDWords() = 0; // vtable+0x24
virtual MxU32* GetBufferForDWords() = 0; // vtable+0x28

View File

@ -29,30 +29,29 @@ MxTickleManager::~MxTickleManager()
}
}
// TODO: Match.
// FUNCTION: LEGO1 0x100bdde0
MxResult MxTickleManager::Tickle()
{
MxTime time = Timer()->GetTime();
MxTickleClientPtrList::iterator it = m_clients.begin();
while (it != m_clients.end()) {
for (MxTickleClientPtrList::iterator it = m_clients.begin(); it != m_clients.end();) {
MxTickleClient* client = *it;
if ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0) {
if (client->GetLastUpdateTime() >= time)
// TODO: Match.
if ((MxU8) client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) {
m_clients.erase(it++);
delete client;
}
else {
it++;
if (client->GetLastUpdateTime() > time)
client->SetLastUpdateTime(-client->GetTickleInterval());
if ((client->GetTickleInterval() + client->GetLastUpdateTime()) < time) {
client->GetClient()->Tickle();
client->SetLastUpdateTime(time);
}
it++;
}
else {
m_clients.erase(it++);
delete client;
}
}

View File

@ -188,16 +188,16 @@ void MxVideoPresenter::Init()
m_unk0x5c = 1;
m_unk0x58 = NULL;
m_unk0x60 = -1;
m_flags = m_flags & 0xfe;
m_flags &= ~Flag_Bit1;
if (MVideoManager() != NULL) {
MVideoManager();
m_flags = m_flags | 2;
m_flags = m_flags & 0xfb;
m_flags |= Flag_Bit2;
m_flags &= ~Flag_Bit3;
}
m_flags = m_flags & 0xf7;
m_flags = m_flags & 0xef;
m_flags &= ~Flag_Bit4;
m_flags &= ~Flag_Bit5;
}
// FUNCTION: LEGO1 0x100b27b0
@ -209,8 +209,8 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
if (m_unk0x58) {
m_unk0x58->Release();
m_unk0x58 = NULL;
m_flags = m_flags & 0xfd;
m_flags = m_flags & 0xfb;
m_flags &= ~Flag_Bit2;
m_flags &= ~Flag_Bit3;
}
if (MVideoManager() && (m_alpha || m_bitmap)) {

View File

@ -1,43 +1,83 @@
import os
import subprocess
import sys
import pathlib
from typing import Iterator
class WinePathConverter:
def __init__(self, unix_cwd):
self.unix_cwd = unix_cwd
self.win_cwd = self._call_winepath_unix2win(self.unix_cwd)
def winepath_win_to_unix(path: str) -> str:
return subprocess.check_output(["winepath", path], text=True).strip()
def get_wine_path(self, unix_fn: str) -> str:
if unix_fn.startswith("./"):
return self.win_cwd + "\\" + unix_fn[2:].replace("/", "\\")
if unix_fn.startswith(self.unix_cwd):
return (
self.win_cwd
+ "\\"
+ unix_fn.removeprefix(self.unix_cwd).replace("/", "\\").lstrip("\\")
def winepath_unix_to_win(path: str) -> str:
return subprocess.check_output(["winepath", "-w", path], text=True).strip()
class PathResolver:
"""Intended to resolve Windows/Wine paths used in the PDB (cvdump) output
into a "canonical" format to be matched against code file paths from os.walk.
MSVC may include files from the parent dir using `..`. We eliminate those and create
an absolute path so that information about the same file under different names
will be combined into the same record. (i.e. line_no/addr pairs from LINES section.)
"""
def __init__(self, basedir) -> None:
"""basedir is the root path of the code directory in the format for your OS.
We will convert it to a PureWindowsPath to be platform-independent
and match that to the paths from the PDB."""
# Memoize the converted paths. We will need to do this for each path
# in the PDB, for each function in that file. (i.e. lots of repeated work)
self._memo = {}
# Convert basedir to an absolute path if it is not already.
# If it is not absolute, we cannot do the path swap on unix.
self._realdir = pathlib.Path(basedir).resolve()
self._is_unix = os.name != "nt"
if self._is_unix:
self._basedir = pathlib.PureWindowsPath(
winepath_unix_to_win(str(self._realdir))
)
return self._call_winepath_unix2win(unix_fn)
else:
self._basedir = self._realdir
def get_unix_path(self, win_fn: str) -> str:
if win_fn.startswith(".\\") or win_fn.startswith("./"):
return self.unix_cwd + "/" + win_fn[2:].replace("\\", "/")
if win_fn.startswith(self.win_cwd):
return (
self.unix_cwd
+ "/"
+ win_fn.removeprefix(self.win_cwd).replace("\\", "/")
)
return self._call_winepath_win2unix(win_fn)
def _memo_wrapper(self, path_str: str) -> str:
"""Wrapper so we can memoize from the public caller method"""
path = pathlib.PureWindowsPath(path_str)
if not path.is_absolute():
# pathlib syntactic sugar for path concat
path = self._basedir / path
@staticmethod
def _call_winepath_unix2win(fn: str) -> str:
return subprocess.check_output(["winepath", "-w", fn], text=True).strip()
if self._is_unix:
# If the given path is relative to the basedir, deconstruct the path
# and swap in our unix path to avoid an expensive call to winepath.
try:
# Will raise ValueError if we are not relative to the base.
section = path.relative_to(self._basedir)
# Should combine to pathlib.PosixPath
mockpath = (self._realdir / section).resolve()
if mockpath.is_file():
return str(mockpath)
except ValueError:
pass
@staticmethod
def _call_winepath_win2unix(fn: str) -> str:
return subprocess.check_output(["winepath", fn], text=True).strip()
# We are not relative to the basedir, or our path swap attempt
# did not point at an actual file. Either way, we are forced
# to call winepath using our original path.
return winepath_win_to_unix(str(path))
# We must be on Windows. Convert back to WindowsPath.
# The resolve() call will eliminate intermediate backdir references.
return str(pathlib.Path(path).resolve())
def resolve_cvdump(self, path_str: str) -> str:
"""path_str is in Windows/Wine path format.
We will return a path in the format for the host OS."""
if path_str not in self._memo:
self._memo[path_str] = self._memo_wrapper(path_str)
return self._memo[path_str]
def is_file_cpp(filename: str) -> bool:

View File

@ -1,6 +1,7 @@
import os
import subprocess
from isledecomp.lib import lib_path_join
from isledecomp.dir import PathResolver, winepath_unix_to_win
class RecompiledInfo:
@ -16,14 +17,15 @@ class SymInfo:
lines = {}
names = {}
def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None):
def __init__(self, pdb, sym_recompfile, sym_logger, base_dir):
self.logger = sym_logger
path_resolver = PathResolver(base_dir)
call = [lib_path_join("cvdump.exe"), "-l", "-s"]
if sym_wine_path_converter:
if os.name != "nt":
# Run cvdump through wine and convert path to Windows-friendly wine path
call.insert(0, "wine")
call.append(sym_wine_path_converter.get_wine_path(pdb))
call.append(winepath_unix_to_win(pdb))
else:
call.append(pdb)
@ -70,10 +72,7 @@ def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None
and not line.startswith(" ")
):
sourcepath = line.split()[0]
if sym_wine_path_converter:
# Convert filename to Unix path for file compare
sourcepath = sym_wine_path_converter.get_unix_path(sourcepath)
sourcepath = path_resolver.resolve_cvdump(sourcepath)
if sourcepath not in self.lines:
self.lines[sourcepath] = {}

View File

@ -1,3 +1,4 @@
from typing import Optional
import pytest
from isledecomp.parser.parser import (
ReaderState as _rs,
@ -70,7 +71,7 @@
"state, marker_type, new_state, expected_error", state_change_marker_cases
)
def test_state_change_by_marker(
state: _rs, marker_type: str, new_state: _rs, expected_error: None | _pe
state: _rs, marker_type: str, new_state: _rs, expected_error: Optional[_pe]
):
p = DecompParser()
p.state = state

View File

@ -0,0 +1,32 @@
from os import name as os_name
import pytest
from isledecomp.dir import PathResolver
if os_name != "nt":
pytest.skip(reason="Skip Windows-only tests", allow_module_level=True)
@pytest.fixture(name="resolver")
def fixture_resolver_win():
yield PathResolver("C:\\isle")
def test_identity(resolver):
assert resolver.resolve_cvdump("C:\\isle\\test.h") == "C:\\isle\\test.h"
def test_outside_basedir(resolver):
assert resolver.resolve_cvdump("C:\\lego\\test.h") == "C:\\lego\\test.h"
def test_relative(resolver):
assert resolver.resolve_cvdump(".\\test.h") == "C:\\isle\\test.h"
assert resolver.resolve_cvdump("..\\test.h") == "C:\\test.h"
def test_intermediate_relative(resolver):
"""These paths may not register as `relative` paths, but we want to
produce a single absolute path for each."""
assert resolver.resolve_cvdump("C:\\isle\\test\\..\\test.h") == "C:\\isle\\test.h"
assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "C:\\isle\\test.h"

View File

@ -0,0 +1,69 @@
from os import name as os_name
from unittest.mock import patch
import pytest
from isledecomp.dir import PathResolver
if os_name == "nt":
pytest.skip(reason="Skip Posix-only tests", allow_module_level=True)
@pytest.fixture(name="resolver")
def fixture_resolver_posix():
# Skip the call to winepath by using a patch, although this is not strictly necessary.
with patch("isledecomp.dir.winepath_unix_to_win", return_value="Z:\\usr\\isle"):
yield PathResolver("/usr/isle")
@patch("isledecomp.dir.winepath_win_to_unix")
def test_identity(winepath_mock, resolver):
"""Test with an absolute Wine path where a path swap is possible."""
# In this and upcoming tests, patch is_file so we always assume there is
# a file at the given unix path. We want to test the conversion logic only.
with patch("pathlib.Path.is_file", return_value=True):
assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h"
winepath_mock.assert_not_called()
# Without the patch, this should call the winepath_mock, but we have
# memoized the value from the previous run.
assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h"
winepath_mock.assert_not_called()
@patch("isledecomp.dir.winepath_win_to_unix")
def test_file_does_not_exist(winepath_mock, resolver):
"""These test files (probably) don't exist, so we always assume
the path swap failed and defer to winepath."""
resolver.resolve_cvdump("Z:\\usr\\isle\\test.h")
winepath_mock.assert_called_once_with("Z:\\usr\\isle\\test.h")
@patch("isledecomp.dir.winepath_win_to_unix")
def test_outside_basedir(winepath_mock, resolver):
"""Test an absolute path where we cannot do a path swap."""
with patch("pathlib.Path.is_file", return_value=True):
resolver.resolve_cvdump("Z:\\lego\\test.h")
winepath_mock.assert_called_once_with("Z:\\lego\\test.h")
@patch("isledecomp.dir.winepath_win_to_unix")
def test_relative(winepath_mock, resolver):
"""Test relative paths inside and outside of the base dir."""
with patch("pathlib.Path.is_file", return_value=True):
assert resolver.resolve_cvdump("./test.h") == "/usr/isle/test.h"
# This works because we will resolve "/usr/isle/test/../test.h"
assert resolver.resolve_cvdump("../test.h") == "/usr/test.h"
winepath_mock.assert_not_called()
@patch("isledecomp.dir.winepath_win_to_unix")
def test_intermediate_relative(winepath_mock, resolver):
"""We can resolve intermediate backdirs if they are relative to the basedir."""
with patch("pathlib.Path.is_file", return_value=True):
assert (
resolver.resolve_cvdump("Z:\\usr\\isle\\test\\..\\test.h")
== "/usr/isle/test.h"
)
assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "/usr/isle/test.h"
winepath_mock.assert_not_called()

View File

@ -16,7 +16,6 @@
print_diff,
SymInfo,
walk_source_dir,
WinePathConverter,
)
from capstone import Cs, CS_ARCH_X86, CS_MODE_32
@ -295,13 +294,8 @@ def main():
svg = args.svg
wine_path_converter = None
if os.name != "nt":
wine_path_converter = WinePathConverter(source)
with Bin(original, logger) as origfile, Bin(recomp, logger) as recompfile:
syminfo = SymInfo(
syms, recompfile, logger, sym_wine_path_converter=wine_path_converter
)
syminfo = SymInfo(syms, recompfile, logger, source)
print()