From 3a0366a3d95962d08ee755528d2302db1c4a1ce3 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sun, 18 May 2025 22:27:44 +0200 Subject: [PATCH] Handle unaligned read/write (#82) --- LEGO1/lego/legoomni/src/entity/legoentity.cpp | 3 +- LEGO1/mxdirectx/mxdirectxinfo.h | 2 +- LEGO1/omni/include/mxdschunk.h | 6 +++- LEGO1/omni/include/mxutilities.h | 8 ++++++ LEGO1/omni/src/action/mxdsaction.cpp | 28 +++++++++---------- LEGO1/omni/src/action/mxdsmediaaction.cpp | 12 ++++---- LEGO1/omni/src/action/mxdsmultiaction.cpp | 8 ++++-- LEGO1/omni/src/action/mxdsobject.cpp | 6 ++-- LEGO1/omni/src/action/mxdssound.cpp | 4 ++- LEGO1/omni/src/stream/mxdsbuffer.cpp | 22 +++++++++------ LEGO1/omni/src/stream/mxramstreamprovider.cpp | 13 ++++----- LEGO1/omni/src/stream/mxstreamchunk.cpp | 2 +- 12 files changed, 66 insertions(+), 48 deletions(-) diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index ea569ad7..127971f5 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -119,7 +119,8 @@ void LegoEntity::SetWorld() { LegoWorld* world = CurrentWorld(); - if (world != NULL && world != (LegoWorld*) this) { + LegoWorld* maybeWorld = dynamic_cast(this); + if (world != NULL && world != maybeWorld) { world->Add(this); } } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.h b/LEGO1/mxdirectx/mxdirectxinfo.h index 0dcb7d43..9bfe0376 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.h +++ b/LEGO1/mxdirectx/mxdirectxinfo.h @@ -50,7 +50,7 @@ class MxAssignedDevice { ~MxAssignedDevice(); unsigned int GetFlags() { return m_flags; } - BOOL GetHardwareMode() { return ((int) m_flags << 31) >> 31; } + BOOL GetHardwareMode() { return (m_flags & 1) != 0; } D3DDEVICEDESC& GetDesc() { return m_desc; } friend class MxDirect3D; diff --git a/LEGO1/omni/include/mxdschunk.h b/LEGO1/omni/include/mxdschunk.h index d3fa7e5a..90c6c8b4 100644 --- a/LEGO1/omni/include/mxdschunk.h +++ b/LEGO1/omni/include/mxdschunk.h @@ -4,6 +4,7 @@ #include "decomp.h" #include "mxcore.h" #include "mxtypes.h" +#include "mxutilities.h" #define DS_CHUNK_BIT1 0x01 #define DS_CHUNK_END_OF_STREAM 0x02 @@ -37,7 +38,10 @@ class MxDSChunk : public MxCore { static MxU32 GetHeaderSize(); // FUNCTION: BETA10 0x101641f0 - static MxU32 Size(MxU8* p_buffer) { return (*(MxU32*) (p_buffer + 4) & 1) + *(MxU32*) (p_buffer + 4) + 8; } + static MxU32 Size(MxU8* p_buffer) + { + return (UnalignedRead(p_buffer + 4) & 1) + UnalignedRead(p_buffer + 4) + 8; + } // FUNCTION: BETA10 0x10164220 static MxU8* End(MxU8* p_buffer) { return p_buffer + Size(p_buffer); } diff --git a/LEGO1/omni/include/mxutilities.h b/LEGO1/omni/include/mxutilities.h index 51b897b7..b345ea79 100644 --- a/LEGO1/omni/include/mxutilities.h +++ b/LEGO1/omni/include/mxutilities.h @@ -29,6 +29,14 @@ inline T Max(T p_t1, T p_t2) return p_t1 > p_t2 ? p_t1 : p_t2; } +template +T UnalignedRead(MxU8* p_source) +{ + T value; + memcpy(&value, p_source, sizeof(T)); + return value; +} + template inline void GetScalar(MxU8*& p_source, T& p_dest) { diff --git a/LEGO1/omni/src/action/mxdsaction.cpp b/LEGO1/omni/src/action/mxdsaction.cpp index caab7f99..e67ad9d8 100644 --- a/LEGO1/omni/src/action/mxdsaction.cpp +++ b/LEGO1/omni/src/action/mxdsaction.cpp @@ -261,21 +261,21 @@ void MxDSAction::Deserialize(MxU8*& p_source, MxS16 p_flags) MxDSObject::Deserialize(p_source, p_flags); // clang-format off - m_flags = *( MxU32*) p_source; p_source += sizeof(m_flags); - m_startTime = *(MxLong*) p_source; p_source += sizeof(m_startTime); - m_duration = *(MxLong*) p_source; p_source += sizeof(m_duration); - m_loopCount = *( MxS32*) p_source; p_source += sizeof(m_loopCount); - m_location[0] = *(double*) p_source; p_source += sizeof(double); - m_location[1] = *(double*) p_source; p_source += sizeof(double); - m_location[2] = *(double*) p_source; p_source += sizeof(double); - m_direction[0] = *(double*) p_source; p_source += sizeof(double); - m_direction[1] = *(double*) p_source; p_source += sizeof(double); - m_direction[2] = *(double*) p_source; p_source += sizeof(double); - m_up[0] = *(double*) p_source; p_source += sizeof(double); - m_up[1] = *(double*) p_source; p_source += sizeof(double); - m_up[2] = *(double*) p_source; p_source += sizeof(double); + m_flags = UnalignedRead(p_source); p_source += sizeof(MxU32); + m_startTime = UnalignedRead(p_source); p_source += sizeof(MxLong); + m_duration = UnalignedRead(p_source); p_source += sizeof(MxLong); + m_loopCount = UnalignedRead(p_source); p_source += sizeof(MxS32); + m_location[0] = UnalignedRead(p_source); p_source += sizeof(double); + m_location[1] = UnalignedRead(p_source); p_source += sizeof(double); + m_location[2] = UnalignedRead(p_source); p_source += sizeof(double); + m_direction[0] = UnalignedRead(p_source); p_source += sizeof(double); + m_direction[1] = UnalignedRead(p_source); p_source += sizeof(double); + m_direction[2] = UnalignedRead(p_source); p_source += sizeof(double); + m_up[0] = UnalignedRead(p_source); p_source += sizeof(double); + m_up[1] = UnalignedRead(p_source); p_source += sizeof(double); + m_up[2] = UnalignedRead(p_source); p_source += sizeof(double); - MxU16 extraLength = *( MxU16*) p_source; p_source += sizeof(extraLength); + MxU16 extraLength = UnalignedRead(p_source); p_source += sizeof(extraLength); // clang-format on if (extraLength) { diff --git a/LEGO1/omni/src/action/mxdsmediaaction.cpp b/LEGO1/omni/src/action/mxdsmediaaction.cpp index dbd61ca4..5787ba37 100644 --- a/LEGO1/omni/src/action/mxdsmediaaction.cpp +++ b/LEGO1/omni/src/action/mxdsmediaaction.cpp @@ -137,12 +137,12 @@ void MxDSMediaAction::Deserialize(MxU8*& p_source, MxS16 p_flags) p_source += strlen(m_mediaSrcPath) + 1; // clang-format off - m_unk0x9c.SetUnk0x00(*(MxU32*) p_source); p_source += sizeof(m_unk0x9c.m_unk0x00); - m_unk0x9c.SetUnk0x04(*(MxU32*) p_source); p_source += sizeof(m_unk0x9c.m_unk0x04); + m_unk0x9c.SetUnk0x00(UnalignedRead(p_source)); p_source += sizeof(MxU32); + m_unk0x9c.SetUnk0x04(UnalignedRead(p_source)); p_source += sizeof(MxU32); - m_framesPerSecond = *(MxS32*) p_source; p_source += sizeof(m_framesPerSecond); - m_mediaFormat = *(MxS32*) p_source; p_source += sizeof(m_mediaFormat); - m_paletteManagement = *(MxS32*) p_source; p_source += sizeof(m_paletteManagement); - m_sustainTime = *(MxS32*) p_source; p_source += sizeof(m_sustainTime); + m_framesPerSecond = UnalignedRead(p_source); p_source += sizeof(MxS32); + m_mediaFormat = UnalignedRead(p_source); p_source += sizeof(MxS32); + m_paletteManagement = UnalignedRead(p_source); p_source += sizeof(MxS32); + m_sustainTime = UnalignedRead(p_source); p_source += sizeof(MxS32); // clang-format on } diff --git a/LEGO1/omni/src/action/mxdsmultiaction.cpp b/LEGO1/omni/src/action/mxdsmultiaction.cpp index 39adfe9b..452bbee5 100644 --- a/LEGO1/omni/src/action/mxdsmultiaction.cpp +++ b/LEGO1/omni/src/action/mxdsmultiaction.cpp @@ -1,5 +1,7 @@ #include "mxdsmultiaction.h" +#include "mxutilities.h" + #include DECOMP_SIZE_ASSERT(MxDSMultiAction, 0x9c) @@ -153,15 +155,15 @@ void MxDSMultiAction::Deserialize(MxU8*& p_source, MxS16 p_flags) { MxDSAction::Deserialize(p_source, p_flags); - MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + MxU32 extraFlag = UnalignedRead(p_source + 4) & 1; p_source += 12; - MxU32 count = *(MxU32*) p_source; + MxU32 count = UnalignedRead(p_source); p_source += sizeof(count); if (count) { while (count--) { - MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + MxU32 extraFlag = UnalignedRead(p_source + 4) & 1; p_source += 8; MxDSAction* action = (MxDSAction*) DeserializeDSObjectDispatch(p_source, p_flags); diff --git a/LEGO1/omni/src/action/mxdsobject.cpp b/LEGO1/omni/src/action/mxdsobject.cpp index 59ecc9d0..25a2a846 100644 --- a/LEGO1/omni/src/action/mxdsobject.cpp +++ b/LEGO1/omni/src/action/mxdsobject.cpp @@ -161,13 +161,13 @@ void MxDSObject::Deserialize(MxU8*& p_source, MxS16 p_flags) SetSourceName((char*) p_source); p_source += strlen(m_sourceName) + 1; - m_unk0x14 = *(undefined4*) p_source; + m_unk0x14 = UnalignedRead(p_source); p_source += sizeof(m_unk0x14); SetObjectName((char*) p_source); p_source += strlen(m_objectName) + 1; - m_objectId = *(MxU32*) p_source; + m_objectId = UnalignedRead(p_source); p_source += sizeof(m_objectId); m_unk0x24 = p_flags; @@ -211,7 +211,7 @@ MxDSObject* DeserializeDSObjectDispatch(MxU8*& p_source, MxS16 p_flags) { MxDSObject* obj = NULL; - MxU16 type = *(MxU16*) p_source; + MxU16 type = UnalignedRead(p_source); p_source += 2; switch (type) { diff --git a/LEGO1/omni/src/action/mxdssound.cpp b/LEGO1/omni/src/action/mxdssound.cpp index b16214d5..e81f3e1d 100644 --- a/LEGO1/omni/src/action/mxdssound.cpp +++ b/LEGO1/omni/src/action/mxdssound.cpp @@ -1,5 +1,7 @@ #include "mxdssound.h" +#include "mxutilities.h" + DECOMP_SIZE_ASSERT(MxDSSound, 0xc0) // FUNCTION: LEGO1 0x100c92c0 @@ -61,7 +63,7 @@ MxDSAction* MxDSSound::Clone() void MxDSSound::Deserialize(MxU8*& p_source, MxS16 p_flags) { MxDSMediaAction::Deserialize(p_source, p_flags); - m_volume = *(MxS32*) p_source; + m_volume = UnalignedRead(p_source); p_source += sizeof(m_volume); } diff --git a/LEGO1/omni/src/stream/mxdsbuffer.cpp b/LEGO1/omni/src/stream/mxdsbuffer.cpp index d76055fe..4d0b0113 100644 --- a/LEGO1/omni/src/stream/mxdsbuffer.cpp +++ b/LEGO1/omni/src/stream/mxdsbuffer.cpp @@ -9,6 +9,7 @@ #include "mxstreamcontroller.h" #include "mxstreamer.h" #include "mxstreamprovider.h" +#include "mxutilities.h" DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34); @@ -177,11 +178,11 @@ MxResult MxDSBuffer::CreateObject( return FAILURE; } - if (*p_data == FOURCC('M', 'x', 'O', 'b')) { + if (UnalignedRead((MxU8*) p_data) == FOURCC('M', 'x', 'O', 'b')) { MxDSAction* action = (MxDSAction*) header; return StartPresenterFromAction(p_controller, p_action, action); } - else if (*p_data == FOURCC('M', 'x', 'C', 'h')) { + else if (UnalignedRead((MxU8*) p_data) == FOURCC('M', 'x', 'C', 'h')) { MxStreamChunk* chunk = (MxStreamChunk*) header; if (!m_unk0x30->HasId((chunk)->GetObjectId())) { delete header; @@ -326,7 +327,7 @@ MxCore* MxDSBuffer::ReadChunk(MxDSBuffer* p_buffer, MxU32* p_chunkData, MxU16 p_ MxCore* result = NULL; MxU8* dataStart = (MxU8*) p_chunkData + 8; - switch (*p_chunkData) { + switch (UnalignedRead((MxU8*) p_chunkData)) { case FOURCC('M', 'x', 'O', 'b'): { MxDSObject* obj = DeserializeDSObjectDispatch(dataStart, p_flags); result = obj; @@ -355,11 +356,12 @@ MxU8* MxDSBuffer::SkipToData() if (m_pIntoBuffer != NULL) { while (TRUE) { - switch (*(MxU32*) m_pIntoBuffer) { + switch (UnalignedRead(m_pIntoBuffer)) { case FOURCC('M', 'x', 'O', 'b'): case FOURCC('M', 'x', 'C', 'h'): result = m_pIntoBuffer; - m_pIntoBuffer += (*(MxU32*) (m_pIntoBuffer + 4) & 1) + *(MxU32*) (m_pIntoBuffer + 4); + m_pIntoBuffer += + (UnalignedRead(m_pIntoBuffer + 4) & 1) + UnalignedRead(m_pIntoBuffer + 4); m_pIntoBuffer += 8; if (m_pBuffer + m_writeOffset - 8 < m_pIntoBuffer) { @@ -372,7 +374,7 @@ MxU8* MxDSBuffer::SkipToData() m_pIntoBuffer += 8; break; case FOURCC('M', 'x', 'H', 'd'): - m_pIntoBuffer += *(MxU32*) (m_pIntoBuffer + 4) + 8; + m_pIntoBuffer += UnalignedRead(m_pIntoBuffer + 4) + 8; break; case FOURCC('L', 'I', 'S', 'T'): case FOURCC('R', 'I', 'F', 'F'): @@ -424,7 +426,7 @@ MxResult MxDSBuffer::CalcBytesRemaining(MxU8* p_data) if (m_writeOffset == m_bytesRemaining) { ptr = p_data; - bytesRead = *(MxU32*) (p_data + 4) + 8; + bytesRead = UnalignedRead(p_data + 4) + 8; } else { ptr = p_data + MxStreamChunk::GetHeaderSize() + 8; @@ -435,7 +437,9 @@ MxResult MxDSBuffer::CalcBytesRemaining(MxU8* p_data) memcpy(m_pBuffer + m_writeOffset - m_bytesRemaining, ptr, bytesRead); if (m_writeOffset == m_bytesRemaining) { - *(MxU32*) (m_pBuffer + 4) = *MxStreamChunk::IntoLength(m_pBuffer) + MxStreamChunk::GetHeaderSize(); + MxU32 length = + UnalignedRead((MxU8*) MxStreamChunk::IntoLength(m_pBuffer)) + MxStreamChunk::GetHeaderSize(); + memcpy(m_pBuffer + 4, &length, sizeof(length)); } m_bytesRemaining -= bytesRead; @@ -462,7 +466,7 @@ MxU8* MxDSBuffer::FUN_100c6fa0(MxU8* p_data) MxU8* end = m_writeOffset + m_pBuffer - 8; while (current <= end) { - switch (*((MxU32*) current)) { + switch (UnalignedRead(current)) { case FOURCC('L', 'I', 'S', 'T'): case FOURCC('R', 'I', 'F', 'F'): current += 12; diff --git a/LEGO1/omni/src/stream/mxramstreamprovider.cpp b/LEGO1/omni/src/stream/mxramstreamprovider.cpp index ad6d80c4..81dc30e8 100644 --- a/LEGO1/omni/src/stream/mxramstreamprovider.cpp +++ b/LEGO1/omni/src/stream/mxramstreamprovider.cpp @@ -5,6 +5,7 @@ #include "mxdsfile.h" #include "mxomni.h" #include "mxstreamcontroller.h" +#include "mxutilities.h" DECOMP_SIZE_ASSERT(MxStreamProvider, 0x10) DECOMP_SIZE_ASSERT(MxRAMStreamProvider, 0x24) @@ -109,10 +110,8 @@ MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) MxU8* data = p_buffer; MxU8* data2; -#define IntoType(p) ((MxU32*) (p)) - while (data < p_buffer + p_size) { - if (*IntoType(data) == FOURCC('M', 'x', 'O', 'b')) { + if (data + sizeof(MxU32) <= p_buffer + p_size && UnalignedRead(data) == FOURCC('M', 'x', 'O', 'b')) { data2 = data; data = data2 + 8; @@ -122,11 +121,11 @@ MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) data = MxDSChunk::End(data2); while (data < p_buffer + p_size) { - if (*IntoType(data) == FOURCC('M', 'x', 'C', 'h')) { + if (UnalignedRead(data) == FOURCC('M', 'x', 'C', 'h')) { MxU8* data3 = data; data = MxDSChunk::End(data3); - if ((*IntoType(data2) == FOURCC('M', 'x', 'C', 'h')) && + if ((UnalignedRead(data2) == FOURCC('M', 'x', 'C', 'h')) && (*MxStreamChunk::IntoFlags(data2) & DS_CHUNK_SPLIT)) { if (*MxStreamChunk::IntoObjectId(data2) == *MxStreamChunk::IntoObjectId(data3) && (*MxStreamChunk::IntoFlags(data3) & DS_CHUNK_SPLIT) && @@ -142,7 +141,7 @@ MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) data2 = MxDSChunk::End(data2); memmove(data2, data3, MxDSChunk::Size(data3)); - if (*MxStreamChunk::IntoObjectId(data2) == id && + if (UnalignedRead((MxU8*) MxStreamChunk::IntoObjectId(data2)) == id && (*MxStreamChunk::IntoFlags(data2) & DS_CHUNK_END_OF_STREAM)) { break; } @@ -159,6 +158,4 @@ MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) *MxStreamChunk::IntoFlags(data2) &= ~DS_CHUNK_SPLIT; return MxDSChunk::Size(data2) + (MxU32) (data2 - p_buffer); - -#undef IntoType } diff --git a/LEGO1/omni/src/stream/mxstreamchunk.cpp b/LEGO1/omni/src/stream/mxstreamchunk.cpp index 7944b2f2..f3c5f191 100644 --- a/LEGO1/omni/src/stream/mxstreamchunk.cpp +++ b/LEGO1/omni/src/stream/mxstreamchunk.cpp @@ -17,7 +17,7 @@ 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 (p_chunkData != NULL && UnalignedRead(p_chunkData) == FOURCC('M', 'x', 'C', 'h')) { if (ReadChunkHeader(p_chunkData + 8)) { if (p_buffer) { SetBuffer(p_buffer);