mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-06-06 16:33:27 +00:00
CFBStreamedCompression: Eliminate undefined pointer casting
Some (but not all pointer casting in this file is undefined behavior). To rectify this, we can make use of a light wrapper around memcpy to make all of this well-defined.
This commit is contained in:
parent
c9f5483c59
commit
97f2576e2a
@ -1,8 +1,26 @@
|
|||||||
#include "Runtime/Character/CFBStreamedCompression.hpp"
|
#include "Runtime/Character/CFBStreamedCompression.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
#include "Runtime/Character/CFBStreamedAnimReader.hpp"
|
#include "Runtime/Character/CFBStreamedAnimReader.hpp"
|
||||||
|
|
||||||
namespace urde {
|
namespace urde {
|
||||||
|
namespace {
|
||||||
|
template <typename T>
|
||||||
|
T ReadValue(const u8* data) {
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
|
||||||
|
T value = 0;
|
||||||
|
std::memcpy(&value, data, sizeof(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void WriteValue(u8* data, T value) {
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
std::memcpy(data, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
CFBStreamedCompression::CFBStreamedCompression(CInputStream& in, IObjectStore& objStore, bool pc) : m_pc(pc) {
|
CFBStreamedCompression::CFBStreamedCompression(CInputStream& in, IObjectStore& objStore, bool pc) : m_pc(pc) {
|
||||||
x0_scratchSize = in.readUint32Big();
|
x0_scratchSize = in.readUint32Big();
|
||||||
@ -16,41 +34,46 @@ CFBStreamedCompression::CFBStreamedCompression(CInputStream& in, IObjectStore& o
|
|||||||
x10_averageVelocity = CalculateAverageVelocity(GetPerChannelHeaders());
|
x10_averageVelocity = CalculateAverageVelocity(GetPerChannelHeaders());
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32* CFBStreamedCompression::GetTimes() const { return reinterpret_cast<const u32*>(xc_rotsAndOffs.get() + 9); }
|
const u32* CFBStreamedCompression::GetTimes() const { return xc_rotsAndOffs.get() + 9; }
|
||||||
|
|
||||||
const u8* CFBStreamedCompression::GetPerChannelHeaders() const {
|
const u8* CFBStreamedCompression::GetPerChannelHeaders() const {
|
||||||
const u32* bitmap = reinterpret_cast<const u32*>(xc_rotsAndOffs.get() + 9);
|
const u32* bitmap = GetTimes();
|
||||||
u32 bitmapWordCount = (bitmap[0] + 31) / 32;
|
const u32 bitmapWordCount = (bitmap[0] + 31) / 32;
|
||||||
return reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
|
return reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* CFBStreamedCompression::GetBitstreamPointer() const {
|
const u8* CFBStreamedCompression::GetBitstreamPointer() const {
|
||||||
const u32* bitmap = reinterpret_cast<const u32*>(xc_rotsAndOffs.get() + 9);
|
const u32* bitmap = GetTimes();
|
||||||
u32 bitmapWordCount = (bitmap[0] + 31) / 32;
|
const u32 bitmapWordCount = (bitmap[0] + 31) / 32;
|
||||||
|
|
||||||
const u8* chans = reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
|
const u8* chans = reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
|
||||||
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
|
const u32 boneChanCount = ReadValue<u32>(chans);
|
||||||
|
|
||||||
chans += 4;
|
chans += 4;
|
||||||
|
|
||||||
if (m_pc) {
|
if (m_pc) {
|
||||||
for (unsigned b = 0; b < boneChanCount; ++b) {
|
for (u32 b = 0; b < boneChanCount; ++b) {
|
||||||
chans += 20;
|
chans += 20;
|
||||||
|
|
||||||
u32 tCount = *reinterpret_cast<const u32*>(chans);
|
const u32 tCount = ReadValue<u32>(chans);
|
||||||
|
|
||||||
chans += 4;
|
chans += 4;
|
||||||
if (tCount)
|
if (tCount != 0) {
|
||||||
chans += 12;
|
chans += 12;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (unsigned b = 0; b < boneChanCount; ++b) {
|
for (u32 b = 0; b < boneChanCount; ++b) {
|
||||||
chans += 15;
|
chans += 15;
|
||||||
|
|
||||||
u16 tCount = *reinterpret_cast<const u16*>(chans);
|
const u16 tCount = ReadValue<u16>(chans);
|
||||||
|
|
||||||
chans += 2;
|
chans += 2;
|
||||||
if (tCount)
|
if (tCount != 0) {
|
||||||
chans += 9;
|
chans += 9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return chans;
|
return chans;
|
||||||
}
|
}
|
||||||
@ -60,19 +83,20 @@ std::unique_ptr<u32[]> CFBStreamedCompression::GetRotationsAndOffsets(u32 words,
|
|||||||
|
|
||||||
Header head;
|
Header head;
|
||||||
head.read(in);
|
head.read(in);
|
||||||
*reinterpret_cast<Header*>(ret.get()) = head;
|
std::memcpy(ret.get(), &head, sizeof(head));
|
||||||
|
|
||||||
u32* bitmapOut = &ret[9];
|
u32* bitmapOut = &ret[9];
|
||||||
u32 bitmapBitCount = in.readUint32Big();
|
const u32 bitmapBitCount = in.readUint32Big();
|
||||||
bitmapOut[0] = bitmapBitCount;
|
bitmapOut[0] = bitmapBitCount;
|
||||||
u32 bitmapWordCount = (bitmapBitCount + 31) / 32;
|
const u32 bitmapWordCount = (bitmapBitCount + 31) / 32;
|
||||||
for (u32 i = 0; i < bitmapWordCount; ++i)
|
for (u32 i = 0; i < bitmapWordCount; ++i) {
|
||||||
bitmapOut[i + 1] = in.readUint32Big();
|
bitmapOut[i + 1] = in.readUint32Big();
|
||||||
|
}
|
||||||
|
|
||||||
in.readUint32Big();
|
in.readUint32Big();
|
||||||
u8* chans = reinterpret_cast<u8*>(bitmapOut + bitmapWordCount + 1);
|
u8* chans = reinterpret_cast<u8*>(bitmapOut + bitmapWordCount + 1);
|
||||||
u8* bs = ReadBoneChannelDescriptors(chans, in);
|
u8* bs = ReadBoneChannelDescriptors(chans, in);
|
||||||
u32 bsWords = ComputeBitstreamWords(chans);
|
const u32 bsWords = ComputeBitstreamWords(chans);
|
||||||
|
|
||||||
u32* bsPtr = reinterpret_cast<u32*>(bs);
|
u32* bsPtr = reinterpret_cast<u32*>(bs);
|
||||||
for (u32 w = 0; w < bsWords; ++w)
|
for (u32 w = 0; w < bsWords; ++w)
|
||||||
@ -82,58 +106,58 @@ std::unique_ptr<u32[]> CFBStreamedCompression::GetRotationsAndOffsets(u32 words,
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8* CFBStreamedCompression::ReadBoneChannelDescriptors(u8* out, CInputStream& in) const {
|
u8* CFBStreamedCompression::ReadBoneChannelDescriptors(u8* out, CInputStream& in) const {
|
||||||
u32 boneChanCount = in.readUint32Big();
|
const u32 boneChanCount = in.readUint32Big();
|
||||||
*reinterpret_cast<u32*>(out) = boneChanCount;
|
WriteValue(out, boneChanCount);
|
||||||
out += 4;
|
out += 4;
|
||||||
|
|
||||||
if (m_pc) {
|
if (m_pc) {
|
||||||
for (unsigned b = 0; b < boneChanCount; ++b) {
|
for (u32 b = 0; b < boneChanCount; ++b) {
|
||||||
*reinterpret_cast<u32*>(out) = in.readUint32Big();
|
WriteValue(out, in.readUint32Big());
|
||||||
out += 4;
|
out += 4;
|
||||||
|
|
||||||
*reinterpret_cast<u32*>(out) = in.readUint32Big();
|
WriteValue(out, in.readUint32Big());
|
||||||
out += 4;
|
out += 4;
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
*reinterpret_cast<u32*>(out) = in.readUint32Big();
|
WriteValue(out, in.readUint32Big());
|
||||||
out += 4;
|
out += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 tCount = in.readUint32Big();
|
const u32 tCount = in.readUint32Big();
|
||||||
*reinterpret_cast<u32*>(out) = tCount;
|
WriteValue(out, tCount);
|
||||||
out += 4;
|
out += 4;
|
||||||
|
|
||||||
if (tCount) {
|
if (tCount != 0) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
*reinterpret_cast<u32*>(out) = in.readUint32Big();
|
WriteValue(out, in.readUint32Big());
|
||||||
out += 4;
|
out += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (unsigned b = 0; b < boneChanCount; ++b) {
|
for (u32 b = 0; b < boneChanCount; ++b) {
|
||||||
*reinterpret_cast<u32*>(out) = in.readUint32Big();
|
WriteValue(out, in.readUint32Big());
|
||||||
out += 4;
|
out += 4;
|
||||||
|
|
||||||
*reinterpret_cast<u16*>(out) = in.readUint16Big();
|
WriteValue(out, in.readUint16Big());
|
||||||
out += 2;
|
out += 2;
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
*reinterpret_cast<s16*>(out) = in.readInt16Big();
|
WriteValue(out, in.readInt16Big());
|
||||||
out += 2;
|
out += 2;
|
||||||
*reinterpret_cast<u8*>(out) = in.readUByte();
|
WriteValue(out, in.readUByte());
|
||||||
out += 1;
|
out += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 tCount = in.readUint16Big();
|
const u16 tCount = in.readUint16Big();
|
||||||
*reinterpret_cast<u16*>(out) = tCount;
|
WriteValue(out, tCount);
|
||||||
out += 2;
|
out += 2;
|
||||||
|
|
||||||
if (tCount) {
|
if (tCount != 0) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
*reinterpret_cast<s16*>(out) = in.readInt16Big();
|
WriteValue(out, in.readInt16Big());
|
||||||
out += 2;
|
out += 2;
|
||||||
*reinterpret_cast<u8*>(out) = in.readUByte();
|
WriteValue(out, in.readUByte());
|
||||||
out += 1;
|
out += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,43 +168,43 @@ u8* CFBStreamedCompression::ReadBoneChannelDescriptors(u8* out, CInputStream& in
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 CFBStreamedCompression::ComputeBitstreamWords(const u8* chans) const {
|
u32 CFBStreamedCompression::ComputeBitstreamWords(const u8* chans) const {
|
||||||
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
|
const u32 boneChanCount = ReadValue<u32>(chans);
|
||||||
chans += 4;
|
chans += 4;
|
||||||
|
|
||||||
u32 keyCount;
|
u32 keyCount;
|
||||||
|
|
||||||
u32 totalBits = 0;
|
u32 totalBits = 0;
|
||||||
if (m_pc) {
|
if (m_pc) {
|
||||||
keyCount = *reinterpret_cast<const u32*>(chans + 0x4);
|
keyCount = ReadValue<u32>(chans + 0x4);
|
||||||
for (u32 c = 0; c < boneChanCount; ++c) {
|
for (u32 c = 0; c < boneChanCount; ++c) {
|
||||||
chans += 0x8;
|
chans += 0x8;
|
||||||
totalBits += 1;
|
totalBits += 1;
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans) & 0xff;
|
totalBits += ReadValue<u32>(chans) & 0xff;
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans + 0x4) & 0xff;
|
totalBits += ReadValue<u32>(chans + 0x4) & 0xff;
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans + 0x8) & 0xff;
|
totalBits += ReadValue<u32>(chans + 0x8) & 0xff;
|
||||||
u32 tKeyCount = *reinterpret_cast<const u32*>(chans + 0xc);
|
const u32 tKeyCount = ReadValue<u32>(chans + 0xc);
|
||||||
chans += 0x10;
|
chans += 0x10;
|
||||||
if (tKeyCount) {
|
if (tKeyCount != 0) {
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans) & 0xff;
|
totalBits += ReadValue<u32>(chans) & 0xff;
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans + 0x4) & 0xff;
|
totalBits += ReadValue<u32>(chans + 0x4) & 0xff;
|
||||||
totalBits += *reinterpret_cast<const u32*>(chans + 0x8) & 0xff;
|
totalBits += ReadValue<u32>(chans + 0x8) & 0xff;
|
||||||
chans += 0xc;
|
chans += 0xc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
keyCount = *reinterpret_cast<const u16*>(chans + 0x4);
|
keyCount = ReadValue<u16>(chans + 0x4);
|
||||||
for (u32 c = 0; c < boneChanCount; ++c) {
|
for (u32 c = 0; c < boneChanCount; ++c) {
|
||||||
chans += 0x6;
|
chans += 0x6;
|
||||||
totalBits += 1;
|
totalBits += 1;
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x2);
|
totalBits += ReadValue<u8>(chans + 0x2);
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x5);
|
totalBits += ReadValue<u8>(chans + 0x5);
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x8);
|
totalBits += ReadValue<u8>(chans + 0x8);
|
||||||
u16 tKeyCount = *reinterpret_cast<const u16*>(chans + 0x9);
|
const u16 tKeyCount = ReadValue<u16>(chans + 0x9);
|
||||||
chans += 0xb;
|
chans += 0xb;
|
||||||
if (tKeyCount) {
|
if (tKeyCount != 0) {
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x2);
|
totalBits += ReadValue<u8>(chans + 0x2);
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x5);
|
totalBits += ReadValue<u8>(chans + 0x5);
|
||||||
totalBits += *reinterpret_cast<const u8*>(chans + 0x8);
|
totalBits += ReadValue<u8>(chans + 0x8);
|
||||||
chans += 0x9;
|
chans += 0x9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,40 +214,44 @@ u32 CFBStreamedCompression::ComputeBitstreamWords(const u8* chans) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float CFBStreamedCompression::CalculateAverageVelocity(const u8* chans) const {
|
float CFBStreamedCompression::CalculateAverageVelocity(const u8* chans) const {
|
||||||
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
|
const u32 boneChanCount = ReadValue<u32>(chans);
|
||||||
chans += 4;
|
chans += 4;
|
||||||
|
|
||||||
u32 keyCount;
|
u32 keyCount;
|
||||||
u32 rootIdx = 0;
|
u32 rootIdx = 0;
|
||||||
if (m_pc) {
|
if (m_pc) {
|
||||||
keyCount = *reinterpret_cast<const u32*>(chans + 0x4);
|
keyCount = ReadValue<u32>(chans + 0x4);
|
||||||
for (u32 c = 0; c < boneChanCount; ++c) {
|
for (u32 c = 0; c < boneChanCount; ++c) {
|
||||||
u32 boneId = *reinterpret_cast<const u32*>(chans);
|
const u32 boneId = ReadValue<u32>(chans);
|
||||||
if (boneId == 3)
|
if (boneId == 3) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
++rootIdx;
|
++rootIdx;
|
||||||
|
|
||||||
chans += 0x8;
|
chans += 0x8;
|
||||||
u32 tKeyCount = *reinterpret_cast<const u32*>(chans + 0xc);
|
const u32 tKeyCount = ReadValue<u32>(chans + 0xc);
|
||||||
chans += 0x10;
|
chans += 0x10;
|
||||||
if (tKeyCount)
|
if (tKeyCount != 0) {
|
||||||
chans += 0xc;
|
chans += 0xc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
keyCount = *reinterpret_cast<const u16*>(chans + 0x4);
|
keyCount = ReadValue<u16>(chans + 0x4);
|
||||||
for (u32 c = 0; c < boneChanCount; ++c) {
|
for (u32 c = 0; c < boneChanCount; ++c) {
|
||||||
u32 boneId = *reinterpret_cast<const u32*>(chans);
|
const u32 boneId = ReadValue<u32>(chans);
|
||||||
if (boneId == 3)
|
if (boneId == 3) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
++rootIdx;
|
++rootIdx;
|
||||||
|
|
||||||
chans += 0x6;
|
chans += 0x6;
|
||||||
u16 tKeyCount = *reinterpret_cast<const u16*>(chans + 0x9);
|
const u16 tKeyCount = ReadValue<u16>(chans + 0x9);
|
||||||
chans += 0xb;
|
chans += 0xb;
|
||||||
if (tKeyCount)
|
if (tKeyCount != 0) {
|
||||||
chans += 0x9;
|
chans += 0x9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CBitLevelLoader loader(GetBitstreamPointer());
|
CBitLevelLoader loader(GetBitstreamPointer());
|
||||||
CFBStreamedAnimReaderTotals tempTotals(*this);
|
CFBStreamedAnimReaderTotals tempTotals(*this);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user