diff --git a/CMakeLists.txt b/CMakeLists.txt index cdfebd05..5c4e11d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ add_library(lego1 SHARED LEGO1/legoroi.cpp LEGO1/legosoundmanager.cpp LEGO1/legostate.cpp + LEGO1/legostream.cpp LEGO1/legotexturepresenter.cpp LEGO1/legoutil.cpp LEGO1/legovideomanager.cpp diff --git a/LEGO1/legostream.cpp b/LEGO1/legostream.cpp new file mode 100644 index 00000000..1fd2bf11 --- /dev/null +++ b/LEGO1/legostream.cpp @@ -0,0 +1,149 @@ + +#include "legostream.h" + +#include +#include + +// Very likely but not certain sizes. +// The classes are only used on the stack in functions we have not 100% matched +// yet, we can confirm the size once we have. +DECOMP_SIZE_ASSERT(LegoStream, 0x8); +DECOMP_SIZE_ASSERT(LegoFileStream, 0xC); +DECOMP_SIZE_ASSERT(LegoMemoryStream, 0x10); + +// OFFSET: LEGO1 0x10045ae0 +MxBool LegoStream::IsWriteMode() +{ + return m_mode == LEGOSTREAM_MODE_WRITE; +} + +// OFFSET: LEGO1 0x10045af0 +MxBool LegoStream::IsReadMode() +{ + return m_mode == LEGOSTREAM_MODE_READ; +} + +// OFFSET: LEGO1 0x100991c0 +LegoFileStream::LegoFileStream() + : LegoStream() +{ + m_hFile = NULL; +} + +// OFFSET: LEGO1 0x10099250 +LegoFileStream::~LegoFileStream() +{ + if (m_hFile != NULL) + fclose(m_hFile); +} + +// OFFSET: LEGO1 0x100992c0 +MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size) +{ + if (m_hFile == NULL) + return FAILURE; + + return (fread(p_buffer, 1, p_size, m_hFile) == p_size) ? SUCCESS : FAILURE; +} + +// OFFSET: LEGO1 0x10099300 +MxResult LegoFileStream::Write(char* p_buffer, MxU32 p_size) +{ + if (m_hFile == NULL) + return FAILURE; + + return (fwrite(p_buffer, 1, p_size, m_hFile) == p_size) ? SUCCESS : FAILURE; +} + +// OFFSET: LEGO1 0x10099340 +MxResult LegoFileStream::Tell(MxU32* p_offset) +{ + if (m_hFile == NULL) + return FAILURE; + + int got = ftell(m_hFile); + if (got == -1) + return FAILURE; + + *p_offset = got; + return SUCCESS; +} + +// OFFSET: LEGO1 0x10099370 +MxResult LegoFileStream::Seek(MxU32 p_offset) +{ + if (m_hFile == NULL) + return FAILURE; + + return (fseek(m_hFile, p_offset, 0) == 0) ? SUCCESS : FAILURE; +} + +// OFFSET: LEGO1 0x100993a0 +MxResult LegoFileStream::Open(const char* p_filename, OpenFlags p_mode) +{ + char modeString[4]; + + if (m_hFile != NULL) + fclose(m_hFile); + + modeString[0] = '\0'; + if (p_mode & ReadBit) + { + m_mode = LEGOSTREAM_MODE_READ; + strcat(modeString, "r"); + } + + if (p_mode & WriteBit) + { + if (m_mode != LEGOSTREAM_MODE_READ) + m_mode = LEGOSTREAM_MODE_WRITE; + strcat(modeString, "w"); + } + + if ((p_mode & 4) != 0) + strcat(modeString, "b"); + else + strcat(modeString, "t"); + + return (m_hFile = fopen(p_filename, modeString)) ? SUCCESS : FAILURE; +} + +// OFFSET: LEGO1 0x10099080 +LegoMemoryStream::LegoMemoryStream(char* p_buffer) + : LegoStream() +{ + m_buffer = p_buffer; + m_offset = 0; +} + +// OFFSET: LEGO1 0x10099160 +MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size) +{ + memcpy(p_buffer, m_buffer + m_offset, p_size); + m_offset += p_size; + return SUCCESS; +} + +// OFFSET: LEGO1 0x10099190 +MxResult LegoMemoryStream::Write(char* p_buffer, MxU32 p_size) +{ + memcpy(m_buffer + m_offset, p_buffer, p_size); + m_offset += p_size; + return SUCCESS; +} + +// OFFSET: LEGO1 0x100994a0 +MxResult LegoMemoryStream::Tell(MxU32* p_offset) +{ + *p_offset = m_offset; + return SUCCESS; +} + +// OFFSET: LEGO1 0x100994b0 +MxResult LegoMemoryStream::Seek(MxU32 p_offset) +{ + m_offset = p_offset; + return SUCCESS; +} + + diff --git a/LEGO1/legostream.h b/LEGO1/legostream.h new file mode 100644 index 00000000..a505cd54 --- /dev/null +++ b/LEGO1/legostream.h @@ -0,0 +1,73 @@ +#ifndef LEGOSTREAM_H +#define LEGOSTREAM_H + +#include "decomp.h" +#include "mxtypes.h" + +#include + +#define LEGOSTREAM_MODE_READ 1 +#define LEGOSTREAM_MODE_WRITE 2 + +// VTABLE 0x100d7d80 +class LegoStream +{ +public: + LegoStream() : m_mode(0) {} + inline virtual ~LegoStream() {}; + + virtual MxResult Read(char* p_buffer, MxU32 p_size) = 0; + virtual MxResult Write(char* p_buffer, MxU32 p_size) = 0; + virtual MxResult Tell(MxU32* p_offset) = 0; + virtual MxResult Seek(MxU32 p_offset) = 0; + + virtual MxBool IsWriteMode(); + virtual MxBool IsReadMode(); + + enum OpenFlags + { + ReadBit = 1, + WriteBit = 2, + BinaryBit = 4, + }; + +protected: + MxU8 m_mode; +}; + +// VTABLE 0x100db730 +class LegoFileStream : public LegoStream +{ +public: + LegoFileStream(); + virtual ~LegoFileStream(); + + MxResult Read(char* p_buffer, MxU32 p_size) override; + MxResult Write(char* p_buffer, MxU32 p_size) override; + MxResult Tell(MxU32* p_offset) override; + MxResult Seek(MxU32 p_offset) override; + + MxResult Open(const char* p_filename, OpenFlags p_mode); + +private: + FILE *m_hFile; +}; + +// VTABLE 0x100db710 +class LegoMemoryStream : public LegoStream +{ +public: + LegoMemoryStream(char* p_buffer); + ~LegoMemoryStream() {} + + MxResult Read(char* p_buffer, MxU32 p_size) override; + MxResult Write(char* p_buffer, MxU32 p_size) override; + MxResult Tell(MxU32* p_offset) override; + MxResult Seek(MxU32 p_offset) override; + +private: + char *m_buffer; + MxU32 m_offset; +}; + +#endif // LEGOSTREAM_H \ No newline at end of file