Implement chunk parsing (#362)

* partial parsechunk implementation

* fix format

* param name fix

* rename functions

* match MxStreamController::RemoveSubscriber

* implement rest of MxDSBuffer

* Fixes and better matches

* Matche ParseChunk 100%

* Match MxDiskStreamProvider::VTable0x20

* Match MxDSBuffer::CalcBytesRemaining

* Minor stuff

* Minor improvements

* Refactor functions

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
Misha 2023-12-26 16:27:54 -05:00 committed by GitHub
parent 17522b98d4
commit e824e321e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 265 additions and 22 deletions

View file

@ -77,10 +77,47 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
return result;
}
// STUB: LEGO1 0x100d15e0
// FUNCTION: LEGO1 0x100d15e0
void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action)
{
// TODO
MxDSStreamingAction* action;
if (p_action->GetObjectId() == -1) {
m_unk0x35 = FALSE;
do {
action = NULL;
{
MxAutoLocker lock(&m_criticalSection);
m_list.PopFrontStreamingAction(action);
}
if (!action)
return;
if (action->GetUnknowna0()->GetWriteOffset() < 0x20000)
g_unk0x10102878--;
((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action);
} while (action);
}
else {
do {
{
MxAutoLocker lock(&m_criticalSection);
action = (MxDSStreamingAction*) m_list.Find(p_action, TRUE);
}
if (!action)
return;
if (action->GetUnknowna0()->GetWriteOffset() < 0x20000)
g_unk0x10102878--;
((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action);
} while (action);
}
}
// FUNCTION: LEGO1 0x100d1750

View file

@ -30,11 +30,45 @@ MxDSBuffer::MxDSBuffer()
MxDSBuffer::~MxDSBuffer()
{
if (m_pBuffer != NULL) {
if (m_mode == MxDSBufferType_Chunk) {
// TODO
}
else if (m_mode == MxDSBufferType_Allocate || m_mode == MxDSBufferType_Unknown) {
switch (m_mode) {
case MxDSBufferType_Allocate:
case MxDSBufferType_Unknown:
delete[] m_pBuffer;
break;
case MxDSBufferType_Chunk: {
MxU32 offset = m_writeOffset / 1024;
MxStreamer* streamer = Streamer();
switch (offset) {
case 0x40: {
MxU32 a =
(m_pBuffer - streamer->GetSubclass1().GetBuffer()) / (streamer->GetSubclass1().GetSize() << 10);
MxU32 bit = 1 << ((MxU8) a & 0x1f);
MxU32 index = (a & ~0x18u) >> 3;
if ((*(MxU32*) (&streamer->GetSubclass1().GetUnk08Ref()[index])) & bit) {
MxU32* ptr = (MxU32*) (&streamer->GetSubclass1().GetUnk08Ref()[index]);
*ptr = *ptr ^ bit;
}
break;
}
case 0x80: {
MxU32 a =
(m_pBuffer - streamer->GetSubclass1().GetBuffer()) / (streamer->GetSubclass1().GetSize() << 10);
MxU32 bit = 1 << ((MxU8) a & 0x1f);
MxU32 index = (a & ~0x18u) >> 3;
if ((*(MxU32*) (&streamer->GetSubclass2().GetUnk08Ref()[index])) & bit) {
MxU32* ptr = (MxU32*) (&streamer->GetSubclass2().GetUnk08Ref()[index]);
*ptr = *ptr ^ bit;
}
break;
}
}
}
}
}
@ -246,7 +280,7 @@ MxResult MxDSBuffer::StartPresenterFromAction(
return SUCCESS;
}
// STUB: LEGO1 0x100c6a50
// FUNCTION: LEGO1 0x100c6a50
MxResult MxDSBuffer::ParseChunk(
MxStreamController* p_controller,
MxU32* p_data,
@ -255,8 +289,83 @@ MxResult MxDSBuffer::ParseChunk(
MxStreamChunk* p_header
)
{
// TODO
return FAILURE;
MxResult result = SUCCESS;
if (m_unk0x30->GetFlags() & MxDSAction::Flag_Bit3 && m_unk0x30->GetUnknowna8() && p_header->GetTime() < 0) {
delete p_header;
return SUCCESS;
}
p_header->SetTime(p_header->GetTime() + m_unk0x30->GetUnknowna8());
if (p_header->GetFlags() & MxDSChunk::Flag_Bit5) {
MxU32 length = p_header->GetLength() + MxDSChunk::ReturnE() + 8;
MxDSBuffer* buffer = new MxDSBuffer();
if (buffer && buffer->AllocateBuffer(length, MxDSBufferType_Allocate) == SUCCESS &&
buffer->CalcBytesRemaining((MxU8*) p_data) == SUCCESS) {
*p_streamingAction = new MxDSStreamingAction((MxDSStreamingAction&) *p_action);
;
if (*p_streamingAction) {
MxU16* flags = MxStreamChunk::IntoFlags(buffer->GetBuffer());
*flags = p_header->GetFlags() & ~MxDSChunk::Flag_Bit5;
delete p_header;
(*p_streamingAction)->SetUnknowna0(buffer);
goto done;
}
}
if (buffer)
delete buffer;
delete p_header;
return FAILURE;
}
else {
if (p_header->GetFlags() & MxDSChunk::Flag_Bit2) {
if (m_unk0x30->HasId(p_header->GetObjectId())) {
if (m_unk0x30->GetFlags() & MxDSAction::Flag_Bit3 &&
(m_unk0x30->GetLoopCount() > 1 || m_unk0x30->GetDuration() == -1)) {
if (p_action->GetObjectId() == p_header->GetObjectId()) {
MxU32 val = p_controller->GetProvider()->GetBufferForDWords()[m_unk0x30->GetObjectId()];
m_unk0x30->SetUnknown94(val);
m_unk0x30->SetBufferOffset(m_writeOffset * (val / m_writeOffset));
MxNextActionDataStart* data =
p_controller->FindNextActionDataStartFromStreamingAction(m_unk0x30);
if (data)
data->SetData(m_unk0x30->GetBufferOffset());
m_unk0x30->FUN_100cd2d0();
}
delete p_header;
p_header = NULL;
}
else {
if (p_action->GetObjectId() == p_header->GetObjectId() &&
p_controller->VTable0x30(p_action) == SUCCESS) {
p_controller->GetProvider()->VTable0x20(p_action);
result = 1;
}
}
}
}
if (p_header) {
if (p_header->SendChunk(p_controller->GetSubscriberList(), TRUE, p_action->GetUnknown24()) != SUCCESS) {
delete p_header;
}
}
}
done:
return result;
}
// FUNCTION: LEGO1 0x100c6d00
@ -343,11 +452,36 @@ void MxDSBuffer::AddRef(MxDSChunk* p_chunk)
}
}
// STUB: LEGO1 0x100c6ef0
// FUNCTION: LEGO1 0x100c6ef0
MxResult MxDSBuffer::CalcBytesRemaining(MxU8* p_data)
{
// TODO
return FAILURE;
MxResult result = FAILURE;
if (m_mode == MxDSBufferType_Allocate && m_bytesRemaining != 0) {
MxU32 bytesRead;
MxU8* ptr;
if (m_writeOffset == m_bytesRemaining) {
bytesRead = *(MxU32*) (p_data + 4) + 8;
ptr = p_data;
}
else {
ptr = &p_data[MxStreamChunk::ReturnE() + 8];
bytesRead = (*(MxU32*) (p_data + 4)) - MxStreamChunk::ReturnE();
}
if (bytesRead <= m_bytesRemaining) {
memcpy(m_pBuffer + m_writeOffset - m_bytesRemaining, ptr, bytesRead);
if (m_writeOffset == m_bytesRemaining)
*(MxU32*) (m_pBuffer + 4) = *MxStreamChunk::IntoPlus0x12(m_pBuffer) + MxStreamChunk::ReturnE();
m_bytesRemaining -= bytesRead;
result = SUCCESS;
}
}
return result;
}
// FUNCTION: LEGO1 0x100c6f80

View file

@ -19,3 +19,9 @@ MxDSChunk::~MxDSChunk()
delete[] m_data;
}
}
// FUNCTION: LEGO1 0x100be1e0
MxU32 MxDSChunk::ReturnE()
{
return 0xe;
}

View file

@ -13,6 +13,8 @@ class MxDSChunk : public MxCore {
Flag_Bit1 = 0x01,
Flag_Bit2 = 0x02,
Flag_Bit3 = 0x04,
Flag_Bit4 = 0x08,
Flag_Bit5 = 0x10,
Flag_Bit8 = 0x80,
Flag_Bit16 = 0x8000
};
@ -33,6 +35,8 @@ class MxDSChunk : public MxCore {
return !strcmp(p_name, MxDSChunk::ClassName()) || MxCore::IsA(p_name);
}
static MxU32 ReturnE();
inline void SetFlags(MxU16 p_flags) { m_flags = p_flags; }
inline void SetObjectId(undefined4 p_objectid) { m_objectId = p_objectid; }
inline void SetTime(MxLong p_time) { m_time = p_time; }

View file

@ -35,6 +35,7 @@ class MxDSStreamingAction : public MxDSAction {
inline MxS32 GetUnknown9c() { return m_unk0x9c; }
inline MxDSBuffer* GetUnknowna0() { return m_unk0xa0; }
inline MxDSBuffer* GetUnknowna4() { return m_unk0xa4; }
inline MxLong GetUnknowna8() { return m_unk0xa8; }
inline MxDSAction* GetInternalAction() { return m_internalAction; }
inline MxU32 GetBufferOffset() { return m_bufferOffset; }
inline void SetUnknown94(MxU32 p_unk0x94) { m_unk0x94 = p_unk0x94; }

View file

@ -17,7 +17,7 @@ MxDSSubscriber::MxDSSubscriber()
MxDSSubscriber::~MxDSSubscriber()
{
if (m_controller)
m_controller->FUN_100c1620(this);
m_controller->RemoveSubscriber(this);
DeleteChunks();
@ -48,7 +48,7 @@ MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_object
if (!m_unk0x3c)
return FAILURE;
m_controller->FUN_100c15d0(this);
m_controller->AddSubscriber(this);
return SUCCESS;
}

View file

@ -2,6 +2,7 @@
#include "legoutil.h"
#include "mxdsbuffer.h"
#include "mxstreamlist.h"
// FUNCTION: LEGO1 0x100c2fe0
MxStreamChunk::~MxStreamChunk()
@ -48,8 +49,51 @@ MxU32 MxStreamChunk::ReadChunkHeader(MxU8* p_chunkData)
return headersize;
}
// FUNCTION: LEGO1 0x100c30e0
MxResult MxStreamChunk::SendChunk(MxStreamListMxDSSubscriber& p_subscriberList, MxBool p_append, MxS16 p_obj24val)
{
for (MxStreamListMxDSSubscriber::iterator it = p_subscriberList.begin(); it != p_subscriberList.end(); it++) {
if ((*it)->GetObjectId() == m_objectId && (*it)->GetUnknown48() == p_obj24val) {
if (m_flags & MxDSChunk::Flag_Bit2 && m_buffer) {
m_buffer->ReleaseRef(this);
m_buffer = NULL;
}
(*it)->AddChunk(this, p_append);
return SUCCESS;
}
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100c3170
void MxStreamChunk::SetBuffer(MxDSBuffer* p_buffer)
{
m_buffer = p_buffer;
}
// FUNCTION: LEGO1 0x100c3180
MxU16* MxStreamChunk::IntoFlags(MxU8* p_buffer)
{
return (MxU16*) (p_buffer + 8);
}
// FUNCTION: LEGO1 0x100c3190
MxU32* MxStreamChunk::IntoPlus0xa(MxU8* p_buffer)
{
return (MxU32*) (p_buffer + 0xa);
}
// FUNCTION: LEGO1 0x100c31a0
MxU32* MxStreamChunk::IntoPlus0xe(MxU8* p_buffer)
{
return (MxU32*) (p_buffer + 0xe);
}
// FUNCTION: LEGO1 0x100c31b0
MxU32* MxStreamChunk::IntoPlus0x12(MxU8* p_buffer)
{
return (MxU32*) (p_buffer + 0x12);
}

View file

@ -2,8 +2,10 @@
#define MXSTREAMCHUNK_H
#include "mxdschunk.h"
#include "mxdsobject.h"
class MxDSBuffer;
class MxStreamListMxDSSubscriber;
// VTABLE: LEGO1 0x100dc2a8
// SIZE 0x20
@ -29,8 +31,14 @@ class MxStreamChunk : public MxDSChunk {
MxResult ReadChunk(MxDSBuffer* p_buffer, MxU8* p_chunkData);
MxU32 ReadChunkHeader(MxU8* p_chunkData);
MxResult SendChunk(MxStreamListMxDSSubscriber& p_subscriberList, MxBool p_append, MxS16 p_obj24val);
void SetBuffer(MxDSBuffer* p_buffer);
static MxU16* IntoFlags(MxU8* p_buffer);
static MxU32* IntoPlus0x12(MxU8* p_buffer);
static MxU32* IntoPlus0xa(MxU8* p_buffer);
static MxU32* IntoPlus0xe(MxU8* p_buffer);
private:
MxDSBuffer* m_buffer; // 0x1c
};

View file

@ -78,16 +78,16 @@ MxResult MxStreamController::Open(const char* p_filename)
return SUCCESS;
}
// STUB: LEGO1 0x100c15d0
void MxStreamController::FUN_100c15d0(MxDSSubscriber* p_subscriber)
// FUNCTION: LEGO1 0x100c15d0
void MxStreamController::AddSubscriber(MxDSSubscriber* p_subscriber)
{
// TODO
m_subscriberList.push_back(p_subscriber);
}
// STUB: LEGO1 0x100c1620
void MxStreamController::FUN_100c1620(MxDSSubscriber* p_subscriber)
// FUNCTION: LEGO1 0x100c1620
void MxStreamController::RemoveSubscriber(MxDSSubscriber* p_subscriber)
{
// TODO
m_subscriberList.remove(p_subscriber);
}
// FUNCTION: LEGO1 0x100c1690
@ -259,6 +259,12 @@ MxResult MxStreamController::FUN_100c1f00(MxDSAction* p_action)
return FAILURE;
}
// STUB: LEGO1 0x100c20b0
MxNextActionDataStart* MxStreamController::FindNextActionDataStartFromStreamingAction(MxDSStreamingAction* p_action)
{
return NULL;
}
// STUB: LEGO1 0x100c20d0
MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj)
{

View file

@ -43,18 +43,21 @@ class MxStreamController : public MxCore {
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);
void AddSubscriber(MxDSSubscriber* p_subscriber);
void RemoveSubscriber(MxDSSubscriber* p_subscriber);
MxResult FUN_100c1800(MxDSAction* p_action, MxU32 p_val);
MxResult FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset);
MxPresenter* FUN_100c1e70(MxDSAction& p_action);
MxResult FUN_100c1f00(MxDSAction* p_action);
MxBool FUN_100c20d0(MxDSObject& p_obj);
MxResult InsertActionToList54(MxDSAction* p_action);
MxNextActionDataStart* FindNextActionDataStartFromStreamingAction(MxDSStreamingAction* p_action);
inline MxAtomId& GetAtom() { return m_atom; };
inline MxStreamProvider* GetProvider() { return m_provider; };
inline MxStreamListMxDSAction& GetUnk0x3c() { return m_unk0x3c; };
inline MxStreamListMxDSAction& GetUnk0x54() { return m_unk0x54; };
inline MxStreamListMxDSSubscriber& GetSubscriberList() { return m_subscriberList; };
protected:
MxCriticalSection m_criticalSection; // 0x8