Reorganize sources and files (#414)

* Reorganize sources

* Refactor

* Remove relative paths

* Renames

* Fix gitignore

* Remove stuff

* Try fixing format script

* Fix format

* Fix format

* Fix naming script

* Test format

* Fix format
This commit is contained in:
Christian Semmler
2024-01-08 04:58:49 -05:00
committed by GitHub
parent 6a85e62406
commit c47206617d
447 changed files with 347 additions and 346 deletions

View File

@@ -0,0 +1,443 @@
#include "mxdiskstreamcontroller.h"
#include "mxactionnotificationparam.h"
#include "mxautolocker.h"
#include "mxdiskstreamprovider.h"
#include "mxdsstreamingaction.h"
#include "mxomni.h"
#include "mxticklemanager.h"
DECOMP_SIZE_ASSERT(MxDiskStreamController, 0xc8);
// FUNCTION: LEGO1 0x100c7120
MxDiskStreamController::MxDiskStreamController()
{
m_unk0x8c = 0;
}
// FUNCTION: LEGO1 0x100c7530
MxDiskStreamController::~MxDiskStreamController()
{
MxAutoLocker lock(&this->m_criticalSection);
m_unk0xc4 = FALSE;
m_unk0x70 = FALSE;
if (m_provider) {
#ifdef COMPAT_MODE
{
MxDSAction action;
m_provider->VTable0x20(&action);
}
#else
m_provider->VTable0x20(&MxDSAction());
#endif
}
MxDSAction* action;
while (m_unk0x3c.PopFront(action))
delete action;
if (m_provider) {
delete m_provider;
m_provider = NULL;
}
FUN_100c8720();
while (m_list0x80.PopFront(action))
FUN_100c7cb0((MxDSStreamingAction*) action);
while (m_list0x64.PopFront(action))
FUN_100c7cb0((MxDSStreamingAction*) action);
while (!m_list0x74.empty()) {
MxDSBuffer* buffer = m_list0x74.front();
m_list0x74.pop_front();
FUN_100c7ce0(buffer);
}
TickleManager()->UnregisterClient(this);
}
// FUNCTION: LEGO1 0x100c7790
MxResult MxDiskStreamController::Open(const char* p_filename)
{
MxAutoLocker lock(&this->m_criticalSection);
MxResult result = MxStreamController::Open(p_filename);
if (result == SUCCESS) {
m_provider = new MxDiskStreamProvider();
if (m_provider == NULL) {
result = FAILURE;
}
else {
result = m_provider->SetResourceToGet(this);
if (result != SUCCESS) {
delete m_provider;
m_provider = NULL;
}
else {
TickleManager()->RegisterClient(this, 10);
}
}
}
return result;
}
// FUNCTION: LEGO1 0x100c7880
MxResult MxDiskStreamController::VTable0x18(undefined4, undefined4)
{
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c7890
MxResult MxDiskStreamController::FUN_100c7890(MxDSStreamingAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
if (p_action == NULL) {
return FAILURE;
}
m_list0x80.push_back(p_action);
FUN_100c7970();
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c7960
MxResult MxDiskStreamController::VTable0x34(undefined4)
{
return FAILURE;
}
// FUNCTION: LEGO1 0x100c7970
void MxDiskStreamController::FUN_100c7970()
{
// Empty
}
// FUNCTION: LEGO1 0x100c7980
void MxDiskStreamController::FUN_100c7980()
{
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);
}
}
// 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;
}
// FUNCTION: LEGO1 0x100c7db0
MxDSStreamingAction* MxDiskStreamController::FUN_100c7db0()
{
MxAutoLocker lock(&this->m_criticalSection);
for (MxStreamListMxNextActionDataStart::iterator it = m_nextActionList.begin(); it != m_nextActionList.end();
it++) {
MxNextActionDataStart* data = *it;
for (MxStreamListMxDSAction::iterator it2 = m_list0x64.begin(); it2 != m_list0x64.end(); it2++) {
MxDSStreamingAction* streamingAction = (MxDSStreamingAction*) *it2;
if (streamingAction->GetObjectId() == data->GetObjectId() &&
streamingAction->GetUnknown24() == data->GetUnknown24() &&
streamingAction->GetBufferOffset() == data->GetData()) {
m_nextActionList.erase(it);
data->SetData(m_provider->GetFileSize() + data->GetData());
m_nextActionList.push_back(data);
m_list0x64.erase(it2);
return streamingAction;
}
}
}
return NULL;
}
// FUNCTION: LEGO1 0x100c7f40
void MxDiskStreamController::FUN_100c7f40(MxDSStreamingAction* p_streamingaction)
{
MxAutoLocker lock(&this->m_criticalSection);
if (p_streamingaction) {
m_list0x64.push_back(p_streamingaction);
}
}
// FUNCTION: LEGO1 0x100c7ff0
MxResult MxDiskStreamController::VTable0x20(MxDSAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
MxDSStreamingAction* entry =
(MxDSStreamingAction*) m_list0x80.Find(p_action, FALSE); // TODO: is this a seperate class?
if (entry) {
MxDSStreamingAction* action = new MxDSStreamingAction(*p_action, 0);
action->SetUnknown28(entry->GetUnknown28());
action->SetUnknown84(entry->GetUnknown84());
action->SetOrigin(entry->GetOrigin());
action->SetUnknowna0(entry->GetUnknowna4());
FUN_100c7f40(action);
if (VTable0x2c(p_action, entry->GetUnknown94()) != SUCCESS)
return FAILURE;
}
else if (MxStreamController::VTable0x20(p_action) != SUCCESS)
return FAILURE;
m_unk0x70 = TRUE;
m_unk0xc4 = TRUE;
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c8160
MxResult MxDiskStreamController::VTable0x24(MxDSAction* p_action)
{
MxAutoLocker lock(&this->m_criticalSection);
if (m_unk0x54.Find(p_action, FALSE) == NULL) {
if (VTable0x30(p_action) == SUCCESS) {
#ifdef COMPAT_MODE
{
MxEndActionNotificationParam param(c_notificationEndAction, NULL, p_action, TRUE);
MxOmni::GetInstance()->NotifyCurrentEntity(&param);
}
#else
MxOmni::GetInstance()->NotifyCurrentEntity(
&MxEndActionNotificationParam(c_notificationEndAction, NULL, p_action, TRUE)
);
#endif
}
}
MxDSAction action;
if (m_provider) {
m_provider->VTable0x20(p_action);
}
do {
if (m_action0x60 != NULL) {
delete m_action0x60;
m_action0x60 = NULL;
}
action = *p_action;
MxStreamController::VTable0x24(&action);
} while (m_action0x60 != NULL);
if (m_unk0x3c.empty()) {
m_unk0x70 = FALSE;
m_unk0xc4 = FALSE;
}
return SUCCESS;
}
// 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)
{
MxAutoLocker lock(&this->m_criticalSection);
m_list0x74.push_back(p_buffer);
}
// FUNCTION: LEGO1 0x100c8540
void MxDiskStreamController::FUN_100c8540()
{
MxAutoLocker lock(&this->m_criticalSection);
for (list<MxDSBuffer*>::iterator it = m_list0x74.begin(); it != m_list0x74.end();) {
MxDSBuffer* buf = *it;
if (buf->GetRefCount() == 0) {
m_list0x74.erase(it++);
FUN_100c7ce0(buf);
}
else
it++;
}
if (m_nextActionList.empty()) {
while (!m_list0x64.empty()) {
MxDSStreamingAction* action = (MxDSStreamingAction*) m_list0x64.front();
m_list0x64.pop_front();
FUN_100c7cb0(action);
}
}
}
// FUNCTION: LEGO1 0x100c8640
MxResult MxDiskStreamController::Tickle()
{
if (m_unk0xc4) {
FUN_100c7d10();
}
FUN_100c8540();
FUN_100c8720();
if (m_unk0x70) {
FUN_100c7980();
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c8670
void MxDiskStreamController::FUN_100c8670(MxDSStreamingAction* p_streamingAction)
{
MxAutoLocker lock(&this->m_critical9c);
m_list0xb8.push_back(p_streamingAction);
}
// FUNCTION: LEGO1 0x100c8720
void MxDiskStreamController::FUN_100c8720()
{
MxAutoLocker lock(&this->m_critical9c);
MxDSStreamingAction* action;
while (!m_list0xb8.empty()) {
action = (MxDSStreamingAction*) m_list0xb8.front();
m_list0xb8.pop_front();
FUN_100c7cb0(action);
}
}

View File

@@ -0,0 +1,298 @@
#include "mxdiskstreamprovider.h"
#include "mxautolocker.h"
#include "mxdiskstreamcontroller.h"
#include "mxdsbuffer.h"
#include "mxdsstreamingaction.h"
#include "mxomni.h"
#include "mxstreamcontroller.h"
#include "mxstring.h"
#include "mxthread.h"
DECOMP_SIZE_ASSERT(MxDiskStreamProviderThread, 0x1c)
DECOMP_SIZE_ASSERT(MxDiskStreamProvider, 0x60);
// GLOBAL: LEGO1 0x10102878
MxU32 g_unk0x10102878 = 0;
// FUNCTION: LEGO1 0x100d0f30
MxResult MxDiskStreamProviderThread::Run()
{
if (m_target)
((MxDiskStreamProvider*) m_target)->WaitForWorkToComplete();
MxThread::Run();
// They should probably have writen "return MxThread::Run()" but they didn't.
return SUCCESS;
}
// FUNCTION: LEGO1 0x100d0f50
MxResult MxDiskStreamProviderThread::StartWithTarget(MxDiskStreamProvider* p_target)
{
m_target = p_target;
return Start(0x1000, 0);
}
// FUNCTION: LEGO1 0x100d0f70
MxDiskStreamProvider::MxDiskStreamProvider()
{
this->m_pFile = NULL;
this->m_remainingWork = FALSE;
this->m_unk0x35 = FALSE;
}
// FUNCTION: LEGO1 0x100d1240
MxDiskStreamProvider::~MxDiskStreamProvider()
{
MxDSStreamingAction* action;
m_unk0x35 = FALSE;
do {
action = NULL;
{
MxAutoLocker lock(&m_criticalSection);
m_list.PopFrontStreamingAction(action);
}
if (!action)
break;
if (action->GetUnknowna0()->GetWriteOffset() < 0x20000)
g_unk0x10102878--;
((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action);
} while (action);
if (m_remainingWork) {
m_remainingWork = FALSE;
m_busySemaphore.Release(1);
m_thread.Terminate();
}
if (m_pFile)
delete m_pFile;
m_pFile = NULL;
}
// FUNCTION: LEGO1 0x100d13d0
MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
{
MxResult result = FAILURE;
MxString path;
m_pLookup = p_resource;
path = (MxString(MxOmni::GetHD()) + p_resource->GetAtom().GetInternal() + ".si");
m_pFile = new MxDSFile(path.GetData(), 0);
if (m_pFile != NULL) {
if (m_pFile->Open(0) != 0) {
path = MxString(MxOmni::GetCD()) + p_resource->GetAtom().GetInternal() + ".si";
m_pFile->SetFileName(path.GetData());
if (m_pFile->Open(0) != 0)
goto done;
}
m_remainingWork = TRUE;
m_busySemaphore.Init(0, 100);
if (m_thread.StartWithTarget(this) == SUCCESS && p_resource != NULL) {
result = SUCCESS;
}
}
done:
return result;
}
// FUNCTION: LEGO1 0x100d15e0
void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action)
{
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
MxResult MxDiskStreamProvider::WaitForWorkToComplete()
{
while (m_remainingWork) {
m_busySemaphore.Wait(INFINITE);
if (m_unk0x35)
PerformWork();
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100d1780
MxResult MxDiskStreamProvider::FUN_100d1780(MxDSStreamingAction* p_action)
{
if (!m_remainingWork)
return FAILURE;
if (p_action->GetUnknown9c() > 0 && !p_action->GetUnknowna0()) {
MxDSBuffer* buffer = new MxDSBuffer();
if (!buffer)
return FAILURE;
if (buffer->AllocateBuffer(GetFileSize(), MxDSBufferType_Allocate) != SUCCESS) {
delete buffer;
return FAILURE;
}
p_action->SetUnknowna0(buffer);
}
if (p_action->GetUnknowna0()->GetWriteOffset() < 0x20000) {
g_unk0x10102878++;
}
{
MxAutoLocker lock(&m_criticalSection);
m_list.push_back(p_action);
}
m_unk0x35 = TRUE;
m_busySemaphore.Release(1);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100d18f0
void MxDiskStreamProvider::PerformWork()
{
MxDiskStreamController* controller = (MxDiskStreamController*) m_pLookup;
MxDSStreamingAction* streamingAction = NULL;
{
MxAutoLocker lock(&m_criticalSection);
if (!m_list.empty()) {
streamingAction = (MxDSStreamingAction*) m_list.front();
if (streamingAction && !FUN_100d1af0(streamingAction)) {
m_thread.Sleep(500);
m_busySemaphore.Release(1);
return;
}
}
}
{
MxAutoLocker lock(&m_criticalSection);
if (!m_list.PopFrontStreamingAction(streamingAction))
return;
}
if (streamingAction->GetUnknowna0()->GetWriteOffset() < 0x20000) {
g_unk0x10102878--;
}
MxDSBuffer* buffer = streamingAction->GetUnknowna0();
if (m_pFile->GetPosition() == streamingAction->GetBufferOffset() ||
m_pFile->Seek(streamingAction->GetBufferOffset(), 0) == 0) {
buffer->SetUnknown14(m_pFile->GetPosition());
if (m_pFile->ReadToBuffer(buffer) == SUCCESS) {
buffer->SetUnknown1c(m_pFile->GetPosition());
if (streamingAction->GetUnknown9c() > 0) {
FUN_100d1b20(streamingAction);
}
else {
if (m_pLookup == NULL || !((MxDiskStreamController*) m_pLookup)->GetUnk0xc4()) {
controller->FUN_100c8670(streamingAction);
}
else {
controller->FUN_100c7f40(streamingAction);
}
}
streamingAction = NULL;
}
}
if (streamingAction) {
controller->FUN_100c8670(streamingAction);
}
m_thread.Sleep(0);
}
// FUNCTION: LEGO1 0x100d1af0
MxBool MxDiskStreamProvider::FUN_100d1af0(MxDSStreamingAction* p_action)
{
if (p_action->GetUnknowna0()->GetWriteOffset() == 0x20000) {
return g_unk0x10102878 == 0;
}
return TRUE;
}
// STUB: LEGO1 0x100d1b20
MxResult MxDiskStreamProvider::FUN_100d1b20(MxDSStreamingAction* p_action)
{
return FAILURE;
}
// FUNCTION: LEGO1 0x100d1e90
MxU32 MxDiskStreamProvider::GetFileSize()
{
return m_pFile->GetBufferSize();
}
// FUNCTION: LEGO1 0x100d1ea0
MxS32 MxDiskStreamProvider::GetStreamBuffersNum()
{
return m_pFile->GetStreamBuffersNum();
}
// FUNCTION: LEGO1 0x100d1eb0
MxU32 MxDiskStreamProvider::GetLengthInDWords()
{
return m_pFile->GetLengthInDWords();
}
// FUNCTION: LEGO1 0x100d1ec0
MxU32* MxDiskStreamProvider::GetBufferForDWords()
{
return m_pFile->GetBuffer();
}

View File

@@ -0,0 +1,493 @@
#include "mxdsbuffer.h"
#include "mxdiskstreamcontroller.h"
#include "mxdschunk.h"
#include "mxdsstreamingaction.h"
#include "mxomni.h"
#include "mxstreamchunk.h"
#include "mxstreamcontroller.h"
#include "mxstreamer.h"
DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34);
// FUNCTION: LEGO1 0x100c6470
MxDSBuffer::MxDSBuffer()
{
m_refcount = 0;
m_pBuffer = NULL;
m_pIntoBuffer = NULL;
m_pIntoBuffer2 = NULL;
m_unk0x14 = 0;
m_unk0x18 = 0;
m_unk0x1c = 0;
m_writeOffset = 0;
m_bytesRemaining = 0;
m_mode = MxDSBufferType_Preallocated;
m_unk0x30 = 0;
}
// FUNCTION: LEGO1 0x100c6530
MxDSBuffer::~MxDSBuffer()
{
if (m_pBuffer != NULL) {
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;
}
}
}
}
}
m_unk0x14 = 0;
m_unk0x1c = 0;
}
// FUNCTION: LEGO1 0x100c6640
MxResult MxDSBuffer::AllocateBuffer(MxU32 p_bufferSize, MxDSBufferType p_mode)
{
MxResult result = FAILURE;
switch (p_mode) {
case MxDSBufferType_Allocate:
m_pBuffer = new MxU8[p_bufferSize];
break;
case MxDSBufferType_Chunk: {
MxStreamer* streamer = Streamer();
switch (p_bufferSize / 1024) {
case 0x40: {
for (MxU32 i = 0; i < 22; i++) {
if (((1 << (i & 0x1f)) & (*(MxU32*) &streamer->GetSubclass1().GetUnk08Ref()[(i & ~0x18u) >> 3])) == 0) {
MxU32* ptr = (MxU32*) &streamer->GetSubclass1().GetUnk08Ref()[(i & 0xffffffe7) >> 3];
*ptr = *ptr ^ 1 << (i & 0x1f);
m_pBuffer =
(MxU8*) (streamer->GetSubclass1().GetSize() * i * 0x400 + streamer->GetSubclass1().GetBuffer());
goto done;
}
}
m_pBuffer = NULL;
break;
}
case 0x80: {
for (MxU32 i = 0; i < 2; i++) {
if (((1 << (i & 0x1f)) & (*(MxU32*) &streamer->GetSubclass2().GetUnk08Ref()[(i & ~0x18u) >> 3])) == 0) {
MxU32* ptr = (MxU32*) &streamer->GetSubclass2().GetUnk08Ref()[(i & 0xffffffe7) >> 3];
*ptr = *ptr ^ 1 << (i & 0x1f);
m_pBuffer =
(MxU8*) (streamer->GetSubclass2().GetSize() * i * 0x400 + streamer->GetSubclass2().GetBuffer());
goto done;
}
}
m_pBuffer = NULL;
break;
}
default:
m_pBuffer = NULL;
}
}
}
done:
m_pIntoBuffer = m_pBuffer;
m_pIntoBuffer2 = m_pBuffer;
if (m_pBuffer != NULL) {
m_mode = p_mode;
m_bytesRemaining = p_bufferSize;
m_writeOffset = p_bufferSize;
result = SUCCESS;
}
return result;
}
// FUNCTION: LEGO1 0x100c6780
MxResult MxDSBuffer::SetBufferPointer(MxU32* p_buffer, MxU32 p_size)
{
m_pBuffer = (MxU8*) p_buffer;
m_pIntoBuffer = (MxU8*) p_buffer;
m_pIntoBuffer2 = (MxU8*) p_buffer;
m_bytesRemaining = p_size;
m_writeOffset = p_size;
m_mode = MxDSBufferType_Preallocated;
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c67b0
MxResult MxDSBuffer::FUN_100c67b0(
MxStreamController* p_controller,
MxDSAction* p_action,
MxDSStreamingAction** p_streamingAction
)
{
MxResult result = FAILURE;
m_unk0x30 = (MxDSStreamingAction*) p_controller->GetUnk0x3c().Find(p_action, FALSE);
if (m_unk0x30 == NULL)
return FAILURE;
MxU8* data;
while (data = (MxU8*) SkipToData()) {
if (*p_streamingAction == NULL) {
result = CreateObject(p_controller, (MxU32*) data, p_action, p_streamingAction);
if (result == FAILURE)
return result;
// TODO: Not a MxResult value?
if (result == 1)
break;
}
else {
MxDSBuffer* buffer = (*p_streamingAction)->GetUnknowna0();
if (buffer->CalcBytesRemaining(data) != SUCCESS) {
return result;
}
if (buffer->GetBytesRemaining() == 0) {
buffer->SetUnk30(m_unk0x30);
result = buffer->CreateObject(p_controller, (MxU32*) buffer->GetBuffer(), p_action, p_streamingAction);
if (result != SUCCESS) {
return result;
}
if (buffer->GetRefCount() != 0) {
// Note: *p_streamingAction is always null in MxRamStreamProvider
((MxDiskStreamController*) p_controller)->InsertToList74(buffer);
(*p_streamingAction)->SetUnknowna0(NULL);
}
((MxDiskStreamController*) p_controller)->FUN_100c7cb0(*p_streamingAction);
*p_streamingAction = NULL;
}
}
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c68a0
MxResult MxDSBuffer::CreateObject(
MxStreamController* p_controller,
MxU32* p_data,
MxDSAction* p_action,
MxDSStreamingAction** p_streamingAction
)
{
if (p_data == NULL) {
return FAILURE;
}
MxCore* header = ReadChunk(this, p_data, p_action->GetUnknown24());
if (header == NULL) {
return FAILURE;
}
if (*p_data == FOURCC('M', 'x', 'O', 'b'))
return StartPresenterFromAction(p_controller, p_action, (MxDSAction*) header);
else if (*p_data == FOURCC('M', 'x', 'C', 'h')) {
MxStreamChunk* chunk = (MxStreamChunk*) header;
if (!m_unk0x30->HasId((chunk)->GetObjectId())) {
delete header;
return SUCCESS;
}
return ParseChunk(p_controller, p_data, p_action, p_streamingAction, chunk);
}
delete header;
return FAILURE;
}
// FUNCTION: LEGO1 0x100c6960
MxResult MxDSBuffer::StartPresenterFromAction(
MxStreamController* p_controller,
MxDSAction* p_action1,
MxDSAction* p_objectheader
)
{
if (!m_unk0x30->GetInternalAction()) {
p_objectheader->SetAtomId(p_action1->GetAtomId());
p_objectheader->SetUnknown28(p_action1->GetUnknown28());
p_objectheader->SetUnknown84(p_action1->GetUnknown84());
p_objectheader->SetOrigin(p_action1->GetOrigin());
p_objectheader->SetUnknown90(p_action1->GetUnknown90());
p_objectheader->MergeFrom(*p_action1);
m_unk0x30->SetInternalAction(p_objectheader->Clone());
p_controller->InsertActionToList54(p_objectheader);
if (MxOmni::GetInstance()->CreatePresenter(p_controller, *p_objectheader) != SUCCESS) {
return FAILURE;
}
m_unk0x30->SetLoopCount(p_objectheader->GetLoopCount());
m_unk0x30->SetFlags(p_objectheader->GetFlags());
m_unk0x30->SetDuration(p_objectheader->GetDuration());
if (m_unk0x30->GetInternalAction() == NULL) {
return FAILURE;
}
}
else if (p_objectheader) {
delete p_objectheader;
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c6a50
MxResult MxDSBuffer::ParseChunk(
MxStreamController* p_controller,
MxU32* p_data,
MxDSAction* p_action,
MxDSStreamingAction** p_streamingAction,
MxStreamChunk* p_header
)
{
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_Split) {
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_Split;
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_End) {
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
MxCore* MxDSBuffer::ReadChunk(MxDSBuffer* p_buffer, MxU32* p_chunkData, MxU16 p_flags)
{
// This function reads a chunk. If it is an object, this function returns an MxDSObject. If it is a chunk,
// returns a MxDSChunk.
MxCore* result = NULL;
MxU8* dataStart = (MxU8*) p_chunkData + 8;
switch (*p_chunkData) {
case FOURCC('M', 'x', 'O', 'b'):
result = DeserializeDSObjectDispatch(&dataStart, p_flags);
break;
case FOURCC('M', 'x', 'C', 'h'):
result = new MxStreamChunk();
if (result != NULL && ((MxStreamChunk*) result)->ReadChunk(p_buffer, (MxU8*) p_chunkData) != SUCCESS) {
delete result;
result = NULL;
}
return result;
}
return result;
}
// FUNCTION: LEGO1 0x100c6df0
MxU8* MxDSBuffer::SkipToData()
{
MxU8* result = NULL;
if (m_pIntoBuffer != NULL) {
do {
MxU32* ptr = (MxU32*) m_pIntoBuffer;
switch (*ptr) {
case FOURCC('L', 'I', 'S', 'T'):
case FOURCC('R', 'I', 'F', 'F'):
m_pIntoBuffer = (MxU8*) (ptr + 3);
break;
case FOURCC('M', 'x', 'O', 'b'):
case FOURCC('M', 'x', 'C', 'h'):
result = m_pIntoBuffer;
m_pIntoBuffer = (MxU8*) ((ptr[1] & 1) + ptr[1] + (MxU32) ptr);
m_pIntoBuffer = (MxU8*) ((MxU32*) m_pIntoBuffer + 2);
if (m_pBuffer + (m_writeOffset - 8) < m_pIntoBuffer) {
m_pIntoBuffer2 = result;
m_pIntoBuffer = NULL;
return result;
}
goto done;
case FOURCC('M', 'x', 'D', 'a'):
case FOURCC('M', 'x', 'S', 't'):
m_pIntoBuffer = (MxU8*) (ptr + 2);
break;
case FOURCC('M', 'x', 'H', 'd'):
m_pIntoBuffer = (MxU8*) ((MxU32) ptr + ptr[1] + 8);
break;
default:
m_pIntoBuffer = NULL;
m_pIntoBuffer2 = NULL;
return NULL;
}
} while (m_pIntoBuffer <= m_pBuffer + (m_writeOffset - 8));
}
done:
m_pIntoBuffer2 = result;
return result;
}
// FUNCTION: LEGO1 0x100c6ec0
MxU8 MxDSBuffer::ReleaseRef(MxDSChunk*)
{
if (m_refcount != 0) {
m_refcount--;
}
return 0;
}
// FUNCTION: LEGO1 0x100c6ee0
void MxDSBuffer::AddRef(MxDSChunk* p_chunk)
{
if (p_chunk) {
m_refcount++;
}
}
// FUNCTION: LEGO1 0x100c6ef0
MxResult MxDSBuffer::CalcBytesRemaining(MxU8* p_data)
{
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::IntoLength(m_pBuffer) + MxStreamChunk::ReturnE();
m_bytesRemaining -= bytesRead;
result = SUCCESS;
}
}
return result;
}
// FUNCTION: LEGO1 0x100c6f80
void MxDSBuffer::FUN_100c6f80(MxU32 p_writeOffset)
{
if (p_writeOffset < m_writeOffset) {
m_pIntoBuffer2 = m_pBuffer + p_writeOffset;
m_pIntoBuffer = m_pBuffer + p_writeOffset;
}
}

View File

@@ -0,0 +1,26 @@
#include "mxdschunk.h"
DECOMP_SIZE_ASSERT(MxDSChunk, 0x1c);
// FUNCTION: LEGO1 0x100be050
MxDSChunk::MxDSChunk()
{
m_flags = 0;
m_data = NULL;
m_objectId = -1;
m_time = 0;
m_length = 0;
}
// FUNCTION: LEGO1 0x100be170
MxDSChunk::~MxDSChunk()
{
if (m_flags & Flag_Bit1)
delete[] m_data;
}
// FUNCTION: LEGO1 0x100be1e0
MxU32 MxDSChunk::ReturnE()
{
return 0xe;
}

View File

@@ -0,0 +1,124 @@
#include "mxdsfile.h"
#include <stdio.h>
#define SI_MAJOR_VERSION 2
#define SI_MINOR_VERSION 2
// FUNCTION: LEGO1 0x100bfed0
MxDSFile::~MxDSFile()
{
Close();
}
// FUNCTION: LEGO1 0x100cc4b0
MxDSFile::MxDSFile(const char* p_filename, MxULong p_skipReadingChunks)
{
m_filename = p_filename;
m_skipReadingChunks = p_skipReadingChunks;
}
// FUNCTION: LEGO1 0x100cc590
MxLong MxDSFile::Open(MxULong p_uStyle)
{
MXIOINFO& io = m_io;
MxLong longResult = 1;
memset(&io, 0, sizeof(MXIOINFO));
if (io.Open(m_filename.GetData(), p_uStyle) != 0) {
return -1;
}
io.SetBuffer(NULL, 0, 0);
m_position = 0;
if (m_skipReadingChunks == 0) {
longResult = ReadChunks();
}
if (longResult != 0) {
Close(); // vtable + 0x18
}
else {
Seek(0, 0); // vtable + 0x24
}
return longResult;
}
// FUNCTION: LEGO1 0x100cc620
MxLong MxDSFile::ReadChunks()
{
_MMCKINFO topChunk;
_MMCKINFO childChunk;
char tempBuffer[80];
topChunk.fccType = FOURCC('O', 'M', 'N', 'I');
if (m_io.Descend(&topChunk, NULL, MMIO_FINDRIFF) != 0) {
return -1;
}
childChunk.ckid = FOURCC('M', 'x', 'H', 'd');
if (m_io.Descend(&childChunk, &topChunk, 0) != 0) {
return -1;
}
m_io.Read(&m_header, 0xc);
if ((m_header.m_majorVersion == SI_MAJOR_VERSION) && (m_header.m_minorVersion == SI_MINOR_VERSION)) {
childChunk.ckid = FOURCC('M', 'x', 'O', 'f');
if (m_io.Descend(&childChunk, &topChunk, 0) != 0) {
return -1;
}
MxULong* pLengthInDWords = &m_lengthInDWords;
m_io.Read(pLengthInDWords, 4);
m_pBuffer = new MxU32[*pLengthInDWords];
m_io.Read(m_pBuffer, *pLengthInDWords * 4);
return 0;
}
else {
sprintf(tempBuffer, "Wrong SI file version. %d.%d expected.", SI_MAJOR_VERSION, SI_MINOR_VERSION);
MessageBoxA(NULL, tempBuffer, NULL, MB_ICONERROR);
return -1;
}
}
// FUNCTION: LEGO1 0x100cc740
MxLong MxDSFile::Close()
{
m_io.Close(0);
m_position = -1;
memset(&m_header, 0, sizeof(m_header));
if (m_lengthInDWords != 0) {
m_lengthInDWords = 0;
delete[] m_pBuffer;
m_pBuffer = NULL;
}
return 0;
}
// FUNCTION: LEGO1 0x100cc780
MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes)
{
if (m_io.Read(p_buf, p_nbytes) != p_nbytes)
return FAILURE;
m_position += p_nbytes;
return SUCCESS;
}
// FUNCTION: LEGO1 0x100cc7b0
MxLong MxDSFile::Seek(MxLong p_lOffset, MxS32 p_iOrigin)
{
return (m_position = m_io.Seek(p_lOffset, p_iOrigin)) == -1 ? -1 : 0;
}
// FUNCTION: LEGO1 0x100cc7e0
MxULong MxDSFile::GetBufferSize()
{
return m_header.m_bufferSize;
}
// FUNCTION: LEGO1 0x100cc7f0
MxULong MxDSFile::GetStreamBuffersNum()
{
return m_header.m_streamBuffersNum;
}

View File

@@ -0,0 +1,23 @@
#include "mxdssource.h"
#include "mxdsbuffer.h"
DECOMP_SIZE_ASSERT(MxDSSource, 0x14)
// FUNCTION: LEGO1 0x100bffd0
MxResult MxDSSource::ReadToBuffer(MxDSBuffer* p_buffer)
{
return Read(p_buffer->GetBuffer(), p_buffer->GetWriteOffset());
}
// FUNCTION: LEGO1 0x100bfff0
MxLong MxDSSource::GetLengthInDWords()
{
return m_lengthInDWords;
}
// FUNCTION: LEGO1 0x100c0000
MxU32* MxDSSource::GetBuffer()
{
return m_pBuffer;
}

View File

@@ -0,0 +1,125 @@
#include "mxdssubscriber.h"
#include "mxstreamcontroller.h"
DECOMP_SIZE_ASSERT(MxDSSubscriber, 0x4c);
// FUNCTION: LEGO1 0x100b7bb0
MxDSSubscriber::MxDSSubscriber()
{
m_unk0x48 = -1;
m_objectId = -1;
m_unk0x20 = NULL;
m_unk0x3c = NULL;
}
// FUNCTION: LEGO1 0x100b7e00
MxDSSubscriber::~MxDSSubscriber()
{
if (m_controller)
m_controller->RemoveSubscriber(this);
DeleteChunks();
if (m_unk0x20)
delete m_unk0x20;
m_unk0x20 = NULL;
if (m_unk0x3c)
delete m_unk0x3c;
m_unk0x3c = NULL;
}
// FUNCTION: LEGO1 0x100b7ed0
MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48)
{
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->AddSubscriber(this);
return SUCCESS;
}
// 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()
{
MxStreamChunk* chunk = NULL;
if (m_unk0x20)
m_unk0x20->First(chunk);
if (chunk) {
m_unk0x20->Detach();
m_unk0x24.Append(chunk);
}
return chunk;
}
// FUNCTION: LEGO1 0x100b8360
MxStreamChunk* MxDSSubscriber::FUN_100b8360()
{
MxStreamChunk* chunk = NULL;
if (m_unk0x20)
m_unk0x20->First(chunk);
return chunk;
}
// FUNCTION: LEGO1 0x100b8390
void MxDSSubscriber::FUN_100b8390(MxStreamChunk* p_chunk)
{
if (p_chunk) {
if (m_unk0x3c->Find(p_chunk)) {
m_unk0x3c->Detach();
if (p_chunk)
delete p_chunk;
}
else if (p_chunk->GetFlags() & MxDSChunk::Flag_Bit1 && p_chunk)
delete p_chunk;
}
}

View File

@@ -0,0 +1,460 @@
#include "mxioinfo.h"
#include "decomp.h"
// This class should be 72 bytes in size, same as the MMIOINFO struct.
// The current implementation has MMIOINFO as the only member of the class,
// but this assert will enforce the size if we decide to change that.
DECOMP_SIZE_ASSERT(MXIOINFO, sizeof(MMIOINFO));
// FUNCTION: LEGO1 0x100cc800
MXIOINFO::MXIOINFO()
{
memset(&m_info, 0, sizeof(m_info));
}
// FUNCTION: LEGO1 0x100cc820
MXIOINFO::~MXIOINFO()
{
Close(0);
}
// FUNCTION: LEGO1 0x100cc830
MxU16 MXIOINFO::Open(const char* p_filename, MxULong p_flags)
{
OFSTRUCT unused;
MxU16 result = 0;
m_info.lBufOffset = 0;
m_info.lDiskOffset = 0;
// DECOMP: Cast of p_flags to u16 forces the `movzx` instruction
m_info.hmmio = (HMMIO) OpenFile(p_filename, &unused, (MxU16) p_flags);
if ((HFILE) m_info.hmmio != HFILE_ERROR) {
m_info.dwFlags = p_flags;
if (p_flags & MMIO_ALLOCBUF) {
// Default buffer length of 8k if none specified
MxLong len = m_info.cchBuffer ? m_info.cchBuffer : 8192;
HPSTR buf = new char[len];
if (!buf) {
result = MMIOERR_OUTOFMEMORY;
m_info.cchBuffer = 0;
m_info.dwFlags &= ~MMIO_ALLOCBUF;
m_info.pchBuffer = 0;
}
else {
m_info.pchBuffer = buf;
m_info.cchBuffer = len;
}
m_info.pchEndRead = m_info.pchBuffer;
m_info.pchNext = m_info.pchBuffer;
m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer;
}
}
else {
result = MMIOERR_CANNOTOPEN;
}
return result;
}
// FUNCTION: LEGO1 0x100cc8e0
MxU16 MXIOINFO::Close(MxLong p_unused)
{
MxU16 result = 0;
if (m_info.hmmio) {
result = Flush(0);
_lclose((HFILE) m_info.hmmio);
m_info.hmmio = 0;
if (m_info.dwFlags & MMIO_ALLOCBUF)
delete[] m_info.pchBuffer;
m_info.pchEndWrite = 0;
m_info.pchEndRead = 0;
m_info.pchBuffer = 0;
m_info.dwFlags = 0;
}
return result;
}
// FUNCTION: LEGO1 0x100cc930
MxLong MXIOINFO::Read(void* p_buf, MxLong p_len)
{
MxLong bytesRead = 0;
if (m_info.pchBuffer) {
MxLong bytesLeft = m_info.pchEndRead - m_info.pchNext;
while (p_len > 0) {
if (bytesLeft > 0) {
if (p_len < bytesLeft)
bytesLeft = p_len;
memcpy(p_buf, m_info.pchNext, bytesLeft);
p_len -= bytesLeft;
m_info.pchNext += bytesLeft;
bytesRead += bytesLeft;
}
if (p_len <= 0 || Advance(0))
break;
bytesLeft = m_info.pchEndRead - m_info.pchNext;
if (bytesLeft <= 0)
break;
}
}
else if (m_info.hmmio && p_len > 0) {
bytesRead = _hread((HFILE) m_info.hmmio, p_buf, p_len);
if (bytesRead == -1) {
bytesRead = 0;
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
m_info.lDiskOffset += bytesRead;
}
}
return bytesRead;
}
// FUNCTION: LEGO1 0x100cca00
MxLong MXIOINFO::Seek(MxLong p_offset, MxLong p_origin)
{
MxLong result = -1;
// If buffered I/O
if (m_info.pchBuffer) {
if (p_origin == SEEK_CUR) {
if (!p_offset) {
// don't seek at all and just return where we are.
return m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer);
}
else {
// With SEEK_CUR, p_offset is a relative offset.
// Get the absolute position instead and use SEEK_SET.
p_offset += m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer);
p_origin = SEEK_SET;
}
}
else if (p_origin == SEEK_END) {
// not possible with buffered I/O
return -1;
}
// else p_origin == SEEK_SET.
// is p_offset between the start and end of the buffer?
// i.e. can we do the seek without reading more from disk?
if (p_offset >= m_info.lBufOffset && p_offset < m_info.lBufOffset + m_info.cchBuffer) {
m_info.pchNext = m_info.pchBuffer + (p_offset - m_info.lBufOffset);
result = p_offset;
}
else {
// we have to read another chunk from disk.
if (m_info.hmmio && !Flush(0)) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin);
if (m_info.lDiskOffset == -1) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
// align offset to buffer size
MxLong newOffset = p_offset - (p_offset % m_info.cchBuffer);
m_info.lBufOffset = newOffset;
// do we need to seek again?
// (i.e. are we already aligned to buffer size?)
if (p_offset != newOffset) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, newOffset, SEEK_SET);
if (m_info.lDiskOffset == -1) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
}
if (m_info.lBufOffset == m_info.lDiskOffset) {
// is the file open for writing only?
if ((m_info.dwFlags & MMIO_RWMODE) && ((m_info.dwFlags & MMIO_RWMODE) != MMIO_READWRITE)) {
m_info.pchNext = m_info.pchBuffer - m_info.lBufOffset + p_offset;
result = p_offset;
}
else {
// We can read from the file. Fill the buffer.
MxLong bytesRead = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, m_info.cchBuffer);
if (bytesRead == -1) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
m_info.lDiskOffset += bytesRead;
m_info.pchNext = p_offset - m_info.lBufOffset + m_info.pchBuffer;
m_info.pchEndRead = m_info.pchBuffer + bytesRead;
if (m_info.pchNext < m_info.pchEndRead) {
result = p_offset;
}
}
}
}
}
}
}
}
else {
// No buffer so just seek the file directly (if we have a valid handle)
if (m_info.hmmio) {
// i.e. if we just want to get the current file position
if (p_origin == SEEK_CUR && p_offset == 0) {
return m_info.lDiskOffset;
}
else {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin);
result = m_info.lDiskOffset;
if (result == -1) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
}
}
}
return result;
}
// FUNCTION: LEGO1 0x100ccbc0
MxU16 MXIOINFO::SetBuffer(char* p_buf, MxLong p_len, MxLong p_unused)
{
MxU16 result = Flush(0);
if (m_info.dwFlags & MMIO_ALLOCBUF) {
m_info.dwFlags &= ~MMIO_ALLOCBUF;
delete[] m_info.pchBuffer;
}
m_info.pchBuffer = p_buf;
m_info.cchBuffer = p_len;
m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer;
m_info.pchEndRead = m_info.pchBuffer;
return result;
}
// FUNCTION: LEGO1 0x100ccc10
MxU16 MXIOINFO::Flush(MxU16 p_unused)
{
MxU16 result = 0;
// if buffer is dirty
if (m_info.dwFlags & MMIO_DIRTY) {
// if we have allocated an IO buffer
if (m_info.pchBuffer) {
// if we have a file open for writing
if (m_info.hmmio && (m_info.dwFlags & MMIO_RWMODE)) {
// DECOMP: pulling this value out into a variable forces it into EBX
MxLong cchBuffer = m_info.cchBuffer;
if (cchBuffer > 0) {
if (m_info.lBufOffset != m_info.lDiskOffset) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
}
// Was the previous seek (if required) successful?
if (m_info.lBufOffset != m_info.lDiskOffset) {
result = MMIOERR_CANNOTSEEK;
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
MxLong bytesWritten = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cchBuffer);
if (bytesWritten != -1 && bytesWritten == cchBuffer) {
m_info.lDiskOffset += bytesWritten;
m_info.pchNext = m_info.pchBuffer;
m_info.dwFlags &= ~MMIO_DIRTY;
}
else {
result = MMIOERR_CANNOTWRITE;
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
}
}
}
else {
result = MMIOERR_CANNOTWRITE;
}
}
else {
result = MMIOERR_UNBUFFERED;
}
}
return result;
}
// FUNCTION: LEGO1 0x100ccd00
MxU16 MXIOINFO::Advance(MxU16 p_option)
{
MxU16 result = 0;
MxULong rwmode = m_info.dwFlags & MMIO_RWMODE;
if (m_info.pchBuffer) {
MxLong cch = m_info.cchBuffer;
// If we can and should write to the file,
// if we are being asked to write to the file,
// and if there is a buffer *to* write:
if ((rwmode == MMIO_WRITE || rwmode == MMIO_READWRITE) && (m_info.dwFlags & MMIO_DIRTY) &&
((p_option & MMIO_WRITE) || (rwmode == MMIO_READWRITE)) && cch > 0) {
if (m_info.lBufOffset != m_info.lDiskOffset) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
}
if (m_info.lBufOffset != m_info.lDiskOffset) {
result = MMIOERR_CANNOTSEEK;
}
else {
MxLong bytesWritten = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cch);
if (bytesWritten != -1 && bytesWritten == cch) {
m_info.lDiskOffset += bytesWritten;
m_info.pchNext = m_info.pchBuffer;
m_info.pchEndRead = m_info.pchBuffer;
m_info.dwFlags &= ~MMIO_DIRTY;
}
else {
result = MMIOERR_CANNOTWRITE;
}
}
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
m_info.lBufOffset += cch;
if ((!rwmode || rwmode == MMIO_READWRITE) && cch > 0) {
if (m_info.lBufOffset != m_info.lDiskOffset) {
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
}
// if previous seek failed
if (m_info.lBufOffset != m_info.lDiskOffset) {
result = MMIOERR_CANNOTSEEK;
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
MxLong bytesRead = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, cch);
if (bytesRead == -1) {
result = MMIOERR_CANNOTREAD;
m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
}
else {
m_info.lDiskOffset += bytesRead;
m_info.pchNext = m_info.pchBuffer;
m_info.pchEndRead = m_info.pchBuffer + bytesRead;
}
}
}
}
else {
result = MMIOERR_UNBUFFERED;
}
return result;
}
// FUNCTION: LEGO1 0x100cce60
MxU16 MXIOINFO::Descend(MMCKINFO* p_chunkInfo, const MMCKINFO* p_parentInfo, MxU16 p_descend)
{
MxU16 result = 0;
if (!p_chunkInfo)
return MMIOERR_BASE; // ?
if (!p_descend) {
p_chunkInfo->dwFlags = 0;
if (Read(p_chunkInfo, 8) != 8) {
result = MMIOERR_CANNOTREAD;
}
else {
if (m_info.pchBuffer) {
p_chunkInfo->dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset;
}
else {
p_chunkInfo->dwDataOffset = m_info.lDiskOffset;
}
if ((p_chunkInfo->ckid == FOURCC_RIFF || p_chunkInfo->ckid == FOURCC_LIST) &&
Read(&p_chunkInfo->fccType, 4) != 4) {
result = MMIOERR_CANNOTREAD;
}
}
}
else {
MxULong ofs = MAXLONG;
if (p_parentInfo)
ofs = p_parentInfo->cksize + p_parentInfo->dwDataOffset;
BOOL running = TRUE;
BOOL readOk = FALSE;
MMCKINFO tmp;
tmp.dwFlags = 0;
while (running) {
if (Read(&tmp, 8) != 8) {
// If the first read fails, report read error. Else EOF.
result = readOk ? MMIOERR_CHUNKNOTFOUND : MMIOERR_CANNOTREAD;
running = FALSE;
}
else {
readOk = TRUE;
if (m_info.pchBuffer) {
tmp.dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset;
}
else {
tmp.dwDataOffset = m_info.lDiskOffset;
}
if (ofs < tmp.dwDataOffset) {
result = MMIOERR_CHUNKNOTFOUND;
running = FALSE;
}
else if ((p_descend == MMIO_FINDLIST && tmp.ckid == FOURCC_LIST) || (p_descend == MMIO_FINDRIFF && tmp.ckid == FOURCC_RIFF)) {
if (Read(&tmp.fccType, 4) != 4) {
result = MMIOERR_CANNOTREAD;
running = FALSE;
}
else if (p_chunkInfo->fccType == tmp.fccType) {
running = FALSE;
}
}
else if (p_chunkInfo->ckid == tmp.ckid) {
running = FALSE;
}
else if (Seek((tmp.cksize & 1) + tmp.cksize, SEEK_CUR) == -1) {
result = MMIOERR_CANNOTSEEK;
running = FALSE;
}
}
}
if (!result)
memcpy(p_chunkInfo, &tmp, sizeof(MMCKINFO));
}
return result;
}

View File

@@ -0,0 +1,103 @@
#include "mxramstreamcontroller.h"
#include "mxautolocker.h"
#include "mxdsstreamingaction.h"
#include "mxramstreamprovider.h"
DECOMP_SIZE_ASSERT(MxRAMStreamController, 0x98);
undefined* __cdecl ReadData(MxU32* p_fileSizeBuffer, MxU32 p_fileSize);
// FUNCTION: LEGO1 0x100c6110
MxResult MxRAMStreamController::Open(const char* p_filename)
{
MxAutoLocker lock(&m_criticalSection);
if (MxStreamController::Open(p_filename) != SUCCESS) {
return FAILURE;
}
m_provider = new MxRAMStreamProvider();
if (((MxRAMStreamProvider*) m_provider) != NULL) {
if (m_provider->SetResourceToGet(this) != SUCCESS) {
return FAILURE;
}
ReadData(
((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(),
((MxRAMStreamProvider*) m_provider)->GetFileSize()
);
m_buffer.SetBufferPointer(
((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(),
((MxRAMStreamProvider*) m_provider)->GetFileSize()
);
return SUCCESS;
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100c6210
MxResult MxRAMStreamController::VTable0x20(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxS32 unk0x24 = 0;
MxResult result = FAILURE;
if (p_action->GetUnknown24() == -1) {
p_action->SetUnknown24(-3);
MxDSAction* action = m_unk0x54.Find(p_action, FALSE);
if (action != NULL) {
unk0x24 = action->GetUnknown24() + 1;
}
p_action->SetUnknown24(unk0x24);
}
else {
if (m_unk0x54.Find(p_action, FALSE)) {
return FAILURE;
}
}
if (MxStreamController::VTable0x20(p_action) == SUCCESS) {
MxDSStreamingAction* action = (MxDSStreamingAction*) m_unk0x3c.Find(p_action, FALSE);
MxDSStreamingAction streamingaction(*action);
result = DeserializeObject(streamingaction);
}
return result;
}
// FUNCTION: LEGO1 0x100c6320
MxResult MxRAMStreamController::VTable0x24(MxDSAction* p_action)
{
MxDSAction action;
do {
if (m_action0x60 != NULL) {
delete m_action0x60;
m_action0x60 = NULL;
}
action = *p_action;
MxStreamController::VTable0x24(&action);
} while (m_action0x60 != NULL);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c63c0
MxResult MxRAMStreamController::DeserializeObject(MxDSStreamingAction& p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxResult result;
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 == SUCCESS ? SUCCESS : FAILURE;
}
// STUB: LEGO1 0x100d0d80
undefined* __cdecl ReadData(MxU32* p_fileSizeBuffer, MxU32 p_fileSize)
{
return NULL;
}

View File

@@ -0,0 +1,98 @@
#include "mxramstreamprovider.h"
#include "decomp.h"
#include "mxomni.h"
#include "mxstreamcontroller.h"
DECOMP_SIZE_ASSERT(MxRAMStreamProvider, 0x24);
// FUNCTION: LEGO1 0x100d0730
MxRAMStreamProvider::MxRAMStreamProvider()
{
m_bufferSize = 0;
m_fileSize = 0;
m_pBufferOfFileSize = NULL;
m_lengthInDWords = 0;
m_bufferForDWords = NULL;
}
// FUNCTION: LEGO1 0x100d0930
MxU32 MxRAMStreamProvider::GetFileSize()
{
return m_fileSize;
}
// FUNCTION: LEGO1 0x100d0940
MxS32 MxRAMStreamProvider::GetStreamBuffersNum()
{
return 1;
}
// FUNCTION: LEGO1 0x100d0950
MxU32 MxRAMStreamProvider::GetLengthInDWords()
{
return m_lengthInDWords;
}
// FUNCTION: LEGO1 0x100d0960
MxU32* MxRAMStreamProvider::GetBufferForDWords()
{
return m_bufferForDWords;
}
// FUNCTION: LEGO1 0x100d0a50
MxRAMStreamProvider::~MxRAMStreamProvider()
{
m_bufferSize = 0;
m_fileSize = 0;
free(m_pBufferOfFileSize);
m_pBufferOfFileSize = NULL;
m_lengthInDWords = 0;
free(m_bufferForDWords);
m_bufferForDWords = NULL;
}
// FUNCTION: LEGO1 0x100d0ae0
MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource)
{
MxResult result = FAILURE;
MxString path;
m_pLookup = p_resource;
path = (MxString(MxOmni::GetHD()) + p_resource->GetAtom().GetInternal() + ".si");
m_pFile = new MxDSFile(path.GetData(), 0);
if (m_pFile != NULL) {
if (m_pFile->Open(0) != 0) {
path = MxString(MxOmni::GetCD()) + p_resource->GetAtom().GetInternal() + ".si";
m_pFile->SetFileName(path.GetData());
if (m_pFile->Open(0) != 0)
goto done;
}
m_fileSize = m_pFile->CalcFileSize();
if (m_fileSize != 0) {
m_bufferSize = m_pFile->GetBufferSize();
m_pBufferOfFileSize = (MxU32*) new MxU8[m_fileSize];
if (m_pBufferOfFileSize != NULL &&
m_pFile->Read((unsigned char*) m_pBufferOfFileSize, m_fileSize) == SUCCESS) {
m_lengthInDWords = m_pFile->GetLengthInDWords();
m_bufferForDWords = new MxU32[m_lengthInDWords];
if (m_bufferForDWords != NULL) {
memcpy(m_bufferForDWords, m_pFile->GetBuffer(), m_lengthInDWords * sizeof(MxU32));
result = SUCCESS;
}
}
}
}
done:
delete m_pFile;
m_pFile = NULL;
return result;
}

View File

@@ -0,0 +1,99 @@
#include "mxstreamchunk.h"
#include "legoutil.h"
#include "mxdsbuffer.h"
#include "mxstreamlist.h"
// FUNCTION: LEGO1 0x100c2fe0
MxStreamChunk::~MxStreamChunk()
{
if (m_buffer) {
m_buffer->ReleaseRef(this);
}
}
// FUNCTION: LEGO1 0x100c3050
MxResult MxStreamChunk::ReadChunk(MxDSBuffer* p_buffer, MxU8* p_chunkData)
{
MxResult result = FAILURE;
if (p_chunkData != NULL && *(MxU32*) p_chunkData == FOURCC('M', 'x', 'C', 'h')) {
if (ReadChunkHeader(p_chunkData + 8)) {
if (p_buffer) {
SetBuffer(p_buffer);
p_buffer->AddRef(this);
}
result = SUCCESS;
}
}
return result;
}
// FUNCTION: LEGO1 0x100c30a0
MxU32 MxStreamChunk::ReadChunkHeader(MxU8* p_chunkData)
{
MxU32 headersize = 0;
if (p_chunkData) {
MxU8* chunkData = p_chunkData;
// Note: the alpha debug version uses memcpy calls here,
// but the code generation is the same.
GetScalar(&p_chunkData, m_flags);
GetScalar(&p_chunkData, m_objectId);
GetScalar(&p_chunkData, m_time);
GetScalar(&p_chunkData, m_length);
m_data = p_chunkData;
headersize = p_chunkData - 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_End && 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 + 0x08);
}
// FUNCTION: LEGO1 0x100c3190
MxU32* MxStreamChunk::IntoObjectId(MxU8* p_buffer)
{
return (MxU32*) (p_buffer + 0x0a);
}
// FUNCTION: LEGO1 0x100c31a0
MxLong* MxStreamChunk::IntoTime(MxU8* p_buffer)
{
return (MxLong*) (p_buffer + 0x0e);
}
// FUNCTION: LEGO1 0x100c31b0
MxU32* MxStreamChunk::IntoLength(MxU8* p_buffer)
{
return (MxU32*) (p_buffer + 0x12);
}

View File

@@ -0,0 +1,318 @@
#include "mxstreamcontroller.h"
#include "legoomni.h"
#include "legoutil.h"
#include "mxautolocker.h"
#include "mxdsmultiaction.h"
#include "mxdsstreamingaction.h"
#include "mxnextactiondatastart.h"
#include "mxstl/stlcompat.h"
#include "mxstreamchunk.h"
#include "mxtimer.h"
DECOMP_SIZE_ASSERT(MxStreamController, 0x64)
DECOMP_SIZE_ASSERT(MxNextActionDataStart, 0x14)
// FUNCTION: LEGO1 0x100b9400
MxResult MxStreamController::VTable0x18(undefined4, undefined4)
{
return FAILURE;
}
// FUNCTION: LEGO1 0x100b9410
MxResult MxStreamController::VTable0x1c(undefined4, undefined4)
{
return FAILURE;
}
// FUNCTION: LEGO1 0x100b9420
MxDSStreamingAction* MxStreamController::VTable0x28()
{
return NULL;
}
// FUNCTION: LEGO1 0x100c0b90
MxStreamController::MxStreamController()
{
m_provider = NULL;
m_unk0x2c = NULL;
m_action0x60 = NULL;
}
// FUNCTION: LEGO1 0x100c1290
MxStreamController::~MxStreamController()
{
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;
#ifdef COMPAT_MODE
{
MxDSAction action;
provider->VTable0x20(&action);
}
#else
provider->VTable0x20(&MxDSAction());
#endif
delete provider;
}
if (m_unk0x2c) {
delete m_unk0x2c;
m_unk0x2c = NULL;
}
while (m_unk0x54.PopFront(action))
delete action;
}
// FUNCTION: LEGO1 0x100c1520
MxResult MxStreamController::Open(const char* p_filename)
{
char sourceName[256];
MxAutoLocker lock(&m_criticalSection);
MakeSourceName(sourceName, p_filename);
this->m_atom = MxAtomId(sourceName, LookupMode_LowerCase2);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c15d0
void MxStreamController::AddSubscriber(MxDSSubscriber* p_subscriber)
{
m_subscriberList.push_back(p_subscriber);
}
// FUNCTION: LEGO1 0x100c1620
void MxStreamController::RemoveSubscriber(MxDSSubscriber* p_subscriber)
{
m_subscriberList.remove(p_subscriber);
}
// FUNCTION: LEGO1 0x100c1690
MxResult MxStreamController::VTable0x20(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxResult result;
MxU32 offset = 0;
MxS32 objectId = p_action->GetObjectId();
MxStreamProvider* provider = m_provider;
if ((MxS32) provider->GetLengthInDWords() > objectId)
offset = provider->GetBufferForDWords()[objectId];
if (offset)
result = VTable0x2c(p_action, offset);
else
result = FAILURE;
return result;
}
// FUNCTION: LEGO1 0x100c1740
MxResult MxStreamController::VTable0x24(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
VTable0x30(p_action);
m_action0x60 = m_unk0x54.Find(p_action, TRUE);
if (m_action0x60 == NULL) {
return FAILURE;
}
else {
p_action->SetUnknown24(m_action0x60->GetUnknown24());
p_action->SetObjectId(m_action0x60->GetObjectId());
return FUN_100c1f00(m_action0x60);
}
}
// FUNCTION: LEGO1 0x100c1800
MxResult MxStreamController::FUN_100c1800(MxDSAction* p_action, MxU32 p_val)
{
MxNextActionDataStart* dataActionStart =
new MxNextActionDataStart(p_action->GetObjectId(), p_action->GetUnknown24(), p_val);
if (dataActionStart == NULL) {
return FAILURE;
}
m_nextActionList.push_back(dataActionStart);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c1a00
MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset)
{
if (p_action->GetUnknown24() == -1) {
MxS16 newUnknown24 = -1;
// These loops might be a template function in the list classes
for (MxStreamListMxDSAction::iterator it = m_unk0x54.begin(); it != m_unk0x54.end(); it++) {
MxDSAction* action = *it;
if (action->GetObjectId() == p_action->GetObjectId())
newUnknown24 = Max(newUnknown24, action->GetUnknown24());
}
if (newUnknown24 == -1) {
for (MxStreamListMxDSAction::iterator it = m_unk0x3c.begin(); it != m_unk0x3c.end(); it++) {
MxDSAction* action = *it;
if (action->GetObjectId() == p_action->GetObjectId())
newUnknown24 = Max(newUnknown24, action->GetUnknown24());
}
if (newUnknown24 == -1) {
for (MxStreamListMxDSSubscriber::iterator it = m_subscriberList.begin(); it != m_subscriberList.end();
it++) {
MxDSSubscriber* subscriber = *it;
if (subscriber->GetObjectId() == p_action->GetObjectId())
newUnknown24 = Max(newUnknown24, subscriber->GetUnknown48());
}
}
}
p_action->SetUnknown24(newUnknown24 + 1);
}
else {
if (m_unk0x3c.Find(p_action, FALSE))
return FAILURE;
}
MxDSStreamingAction* streamingAction = new MxDSStreamingAction(*p_action, p_offset);
if (!streamingAction)
return FAILURE;
MxU32 fileSize = m_provider->GetFileSize();
streamingAction->SetBufferOffset(fileSize * (p_offset / fileSize));
streamingAction->SetObjectId(p_action->GetObjectId());
MxLong time = Timer()->GetTime();
streamingAction->SetUnknown90(time);
m_unk0x3c.push_back(streamingAction);
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c1c10
MxResult MxStreamController::VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval)
{
MxAutoLocker lock(&m_criticalSection);
if (FUN_100c1a00(p_action, p_bufferval) != SUCCESS) {
return FAILURE;
}
return FUN_100c1800(p_action, (p_bufferval / m_provider->GetFileSize()) * m_provider->GetFileSize());
}
// FUNCTION: LEGO1 0x100c1ce0
MxResult MxStreamController::VTable0x30(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxResult result = FAILURE;
MxDSAction* action = m_unk0x3c.Find(p_action, TRUE);
if (action != NULL) {
MxNextActionDataStart* data = m_nextActionList.FindAndErase(action->GetObjectId(), action->GetUnknown24());
delete action;
delete data;
result = SUCCESS;
}
return result;
}
// FUNCTION: LEGO1 0x100c1da0
MxResult MxStreamController::InsertActionToList54(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxDSAction* action = p_action->Clone();
if (action == NULL) {
return FAILURE;
}
else {
m_unk0x54.push_back(action);
return SUCCESS;
}
}
// FUNCTION: LEGO1 0x100c1e70
MxPresenter* MxStreamController::FUN_100c1e70(MxDSAction& p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxPresenter* result = NULL;
if (p_action.GetObjectId() != -1) {
MxDSAction* action = m_unk0x3c.Find(&p_action, FALSE);
if (action != NULL) {
result = action->GetUnknown28();
}
}
return result;
}
// FUNCTION: LEGO1 0x100c1f00
MxResult MxStreamController::FUN_100c1f00(MxDSAction* p_action)
{
MxAutoLocker lock(&m_criticalSection);
MxU32 objectId = p_action->GetObjectId();
MxStreamChunk* chunk = new MxStreamChunk;
if (!chunk)
return FAILURE;
chunk->SetFlags(MxDSChunk::Flag_Bit3);
chunk->SetObjectId(objectId);
if (chunk->SendChunk(m_subscriberList, FALSE, p_action->GetUnknown24()) != SUCCESS)
delete chunk;
if (p_action->IsA("MxDSMultiAction")) {
MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList();
MxDSActionListCursor cursor(actions);
MxDSAction* action;
while (cursor.Next(action)) {
if (FUN_100c1f00(action) != SUCCESS)
return FAILURE;
}
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x100c20b0
MxNextActionDataStart* MxStreamController::FindNextActionDataStartFromStreamingAction(MxDSStreamingAction* p_action)
{
return m_nextActionList.Find(p_action->GetObjectId(), p_action->GetUnknown24());
}
// FUNCTION: LEGO1 0x100c20d0
MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj)
{
if (m_subscriberList.Find(&p_obj))
return FALSE;
if (p_obj.IsA("MxDSMultiAction")) {
MxDSActionList* actions = ((MxDSMultiAction&) p_obj).GetActionList();
MxDSActionListCursor cursor(actions);
MxDSAction* action;
while (cursor.Next(action)) {
if (!FUN_100c20d0(*action))
return FALSE;
}
}
return TRUE;
}

View File

@@ -0,0 +1,209 @@
#include "mxstreamer.h"
#include "legoomni.h"
#include "mxdiskstreamcontroller.h"
#include "mxnotificationmanager.h"
#include "mxramstreamcontroller.h"
#include <algorithm>
DECOMP_SIZE_ASSERT(MxStreamer, 0x2c);
// FUNCTION: LEGO1 0x100b8f00
MxStreamer::MxStreamer()
{
NotificationManager()->Register(this);
}
// FUNCTION: LEGO1 0x100b9190
MxResult MxStreamer::Create()
{
undefined* b = new undefined[m_subclass1.GetSize() * 0x5800];
m_subclass1.SetBuffer(b);
if (b) {
b = new undefined[m_subclass2.GetSize() * 0x800];
m_subclass2.SetBuffer(b);
if (b) {
return SUCCESS;
}
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100b91d0
MxStreamer::~MxStreamer()
{
while (!m_openStreams.empty()) {
MxStreamController* c = m_openStreams.front();
m_openStreams.pop_front();
delete c;
}
NotificationManager()->Unregister(this);
}
// FUNCTION: LEGO1 0x100b92c0
MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType)
{
MxStreamController* stream = NULL;
if (!GetOpenStream(p_name)) {
switch (p_lookupType) {
case e_DiskStream:
stream = new MxDiskStreamController();
break;
case e_RAMStream:
stream = new MxRAMStreamController();
break;
}
if (stream && (stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS)) {
delete stream;
stream = NULL;
}
}
return stream;
}
// FUNCTION: LEGO1 0x100b9570
MxLong MxStreamer::Close(const char* p_name)
{
MxDSAction ds;
ds.SetUnknown24(-2);
for (list<MxStreamController*>::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) {
MxStreamController* c = *it;
if (!p_name || !strcmp(p_name, c->GetAtom().GetInternal())) {
m_openStreams.erase(it);
if (c->FUN_100c20d0(ds))
delete c;
else {
#ifdef COMPAT_MODE
{
MxStreamerNotification notification(MXSTREAMER_DELETE_NOTIFY, NULL, c);
NotificationManager()->Send(this, &notification);
}
#else
NotificationManager()->Send(this, &MxStreamerNotification(MXSTREAMER_DELETE_NOTIFY, NULL, c));
#endif
}
return SUCCESS;
}
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100b9700
MxNotificationParam* MxStreamerNotification::Clone()
{
return new MxStreamerNotification(m_type, m_sender, m_controller);
}
// FUNCTION: LEGO1 0x100b9870
MxStreamController* MxStreamer::GetOpenStream(const char* p_name)
{
for (list<MxStreamController*>::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) {
MxStreamController* c = *it;
MxAtomId& atom = c->GetAtom();
if (p_name) {
if (!strcmp(atom.GetInternal(), p_name)) {
return *it;
}
}
}
return NULL;
}
// FUNCTION: LEGO1 0x100b9930
MxResult MxStreamer::AddStreamControllerToOpenList(MxStreamController* p_stream)
{
if (find(m_openStreams.begin(), m_openStreams.end(), p_stream) == m_openStreams.end()) {
m_openStreams.push_back(p_stream);
return SUCCESS;
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100b99b0
MxResult MxStreamer::FUN_100b99b0(MxDSAction* p_action)
{
MxStreamController* controller;
if (p_action != NULL && p_action->GetAtomId().GetInternal() != NULL && p_action->GetObjectId() != -1) {
controller = GetOpenStream(p_action->GetAtomId().GetInternal());
if (controller == NULL) {
return FAILURE;
}
return controller->VTable0x20(p_action);
}
return FAILURE;
}
// FUNCTION: LEGO1 0x100b99f0
MxResult MxStreamer::DeleteObject(MxDSAction* p_dsAction)
{
MxDSAction tempAction;
if (p_dsAction == NULL) {
tempAction.SetUnknown24(-2);
}
else {
tempAction.SetObjectId(p_dsAction->GetObjectId());
tempAction.SetAtomId(p_dsAction->GetAtomId());
tempAction.SetUnknown24(p_dsAction->GetUnknown24());
}
MxResult result = FAILURE;
for (list<MxStreamController*>::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) {
const char* id = p_dsAction->GetAtomId().GetInternal();
if (!id || id == (*it)->GetAtom().GetInternal()) {
tempAction.SetAtomId((*it)->GetAtom());
result = (*it)->VTable0x24(&tempAction);
}
}
return result;
}
// FUNCTION: LEGO1 0x100b9b30
MxBool MxStreamer::FUN_100b9b30(MxDSObject& p_dsObject)
{
MxStreamController* controller = GetOpenStream(p_dsObject.GetAtomId().GetInternal());
if (controller)
return controller->FUN_100c20d0(p_dsObject);
return TRUE;
}
// FUNCTION: LEGO1 0x100b9b60
MxLong MxStreamer::Notify(MxParam& p_param)
{
if (((MxNotificationParam&) p_param).GetNotification() == MXSTREAMER_DELETE_NOTIFY) {
MxDSAction ds;
ds.SetUnknown24(-2);
MxStreamController* c = static_cast<MxStreamerNotification&>(p_param).GetController();
if (c->FUN_100c20d0(ds))
delete c;
else {
#ifdef COMPAT_MODE
{
MxStreamerNotification notification(MXSTREAMER_DELETE_NOTIFY, NULL, c);
NotificationManager()->Send(this, &notification);
}
#else
NotificationManager()->Send(this, &MxStreamerNotification(MXSTREAMER_DELETE_NOTIFY, NULL, c));
#endif
}
}
return 0;
}

View File

@@ -0,0 +1,77 @@
#include "mxstreamlist.h"
// Wrappers around STL list that are used by the MxStream* classes.
DECOMP_SIZE_ASSERT(MxStreamListMxDSAction, 0xc);
DECOMP_SIZE_ASSERT(MxStreamListMxNextActionDataStart, 0xc);
DECOMP_SIZE_ASSERT(MxStreamListMxDSSubscriber, 0xc);
// FUNCTION: LEGO1 0x100b8450
MxDSSubscriber* MxStreamListMxDSSubscriber::Find(MxDSObject* p_object)
{
for (iterator it = begin(); it != end(); it++) {
if (p_object->GetObjectId() == -1 || p_object->GetObjectId() == (*it)->GetObjectId()) {
if (p_object->GetUnknown24() == -2 || p_object->GetUnknown24() == (*it)->GetUnknown48()) {
return *it;
}
}
}
return NULL;
}
// FUNCTION: LEGO1 0x100bfa80
MxDSAction* MxStreamListMxDSAction::Find(MxDSAction* p_action, MxBool p_delete)
{
// DECOMP ALPHA 0x1008b99d ?
MxDSAction* found = NULL;
#ifdef COMPAT_MODE
iterator it;
for (it = begin(); it != end(); it++) {
#else
for (iterator it = begin(); it != end(); it++) {
#endif
if (p_action->GetObjectId() == -1 || p_action->GetObjectId() == (*it)->GetObjectId()) {
if (p_action->GetUnknown24() == -2 || p_action->GetUnknown24() == -3 ||
p_action->GetUnknown24() == (*it)->GetUnknown24()) {
found = *it;
if (p_action->GetUnknown24() != -3)
break;
}
}
}
if (p_delete && found != NULL) {
erase(it);
}
return found;
}
// FUNCTION: LEGO1 0x100c21e0
MxNextActionDataStart* MxStreamListMxNextActionDataStart::Find(MxU32 p_id, MxS16 p_value)
{
for (iterator it = begin(); it != end(); it++) {
if (p_id == (*it)->GetObjectId() && p_value == (*it)->GetUnknown24())
return *it;
}
return NULL;
}
// FUNCTION: LEGO1 0x100c2240
MxNextActionDataStart* MxStreamListMxNextActionDataStart::FindAndErase(MxU32 p_id, MxS16 p_value)
{
MxNextActionDataStart* match = NULL;
for (iterator it = begin(); it != end(); it++) {
if (p_id == (*it)->GetObjectId() && (p_value == -2 || p_value == (*it)->GetUnknown24())) {
match = *it;
erase(it);
break;
}
}
return match;
}

View File

@@ -0,0 +1,17 @@
#include "mxstreamprovider.h"
#include "decomp.h"
DECOMP_SIZE_ASSERT(MxStreamProvider, 0x10);
// FUNCTION: LEGO1 0x100d07c0
MxResult MxStreamProvider::SetResourceToGet(MxStreamController* p_resource)
{
m_pLookup = p_resource;
return SUCCESS;
}
// FUNCTION: LEGO1 0x100d07d0
void MxStreamProvider::VTable0x20(MxDSAction* p_action)
{
}