OdysseyDecomp/lib/al/Library/Yaml/ByamlData.cpp

172 lines
4.3 KiB
C++

#include "Library/Yaml/ByamlData.h"
#include <byteswap.h>
namespace al {
ByamlData::ByamlData() = default;
void ByamlData::set(const ByamlHashPair* hash_pair, bool isRev) {
mType = hash_pair->getType();
mValue = hash_pair->getValue(isRev);
}
void ByamlData::set(u8 type, u32 value, bool isRev) {
mType = (ByamlDataType)type;
mValue = isRev ? bswap_32(value) : value;
}
ByamlDataType ByamlData::getType() const {
return mType;
}
u32 ByamlData::getValue() const {
return mValue;
}
s32 ByamlHashPair::getKey(bool isRev) const {
return isRev ? bswap_24(mData) : mData & 0xFFFFFF;
}
ByamlDataType ByamlHashPair::getType() const {
return (ByamlDataType)(mData >> 24);
}
s32 ByamlHashPair::getValue(bool isRev) const {
return isRev ? bswap_32(mValue) : mValue;
}
ByamlHashIter::ByamlHashIter(const u8* data, bool isRev) : mData(data), mIsRev(isRev) {}
ByamlHashIter::ByamlHashIter() : mData(nullptr), mIsRev(false) {}
const ByamlHashPair* ByamlHashIter::findPair(s32 key) const {
const ByamlHashPair* pairTable = getPairTable();
if (!mData)
return nullptr;
s32 lowerBound = 0;
s32 upperBound = getSize();
asm(""); // solves isRev leaking over between getSize() and getKey()
while (lowerBound < upperBound) {
s32 avg = (lowerBound + upperBound) / 2;
const ByamlHashPair* pair = &pairTable[avg];
s32 result = key - pair->getKey(mIsRev);
if (result == 0)
return pair;
if (result > 0)
lowerBound = avg + 1;
else
upperBound = avg;
}
return nullptr;
}
bool ByamlHashIter::getDataByIndex(ByamlData* data, s32 index) const {
if (!mData)
return false;
if (((s32)getSize()) < 1)
return false;
data->set(&getPairTable()[index], mIsRev);
return true;
}
// NON_MATCHING: minor additional instructions, probably not inlined
// (https://decomp.me/scratch/5VLcG)
bool ByamlHashIter::getDataByKey(ByamlData* data, s32 key) const {
if (!mData)
return false;
if (((s32)getSize()) < 1)
return false;
// probably inlined from findPair()
const ByamlHashPair* pairTable = getPairTable();
if (!mData)
return false;
s32 lowerBound = 0;
s32 upperBound = getSize();
const ByamlHashPair* pair;
if (lowerBound >= upperBound)
return false;
while (true) {
s32 avg = (lowerBound + upperBound) / 2;
pair = &pairTable[avg];
s32 result = key - pair->getKey(mIsRev);
if (result == 0)
break;
if (result > 0)
lowerBound = avg + 1;
else
upperBound = avg;
if (lowerBound >= upperBound)
return false;
}
if (!pair)
return false;
data->set(pair, mIsRev);
return true;
}
const u8* ByamlHashIter::getOffsetData(u32 off) const {
return &mData[off];
}
const ByamlHashPair* ByamlHashIter::getPairByIndex(s32 index) const {
if (index < 0)
return nullptr;
if (((s32)getSize()) <= index)
return nullptr;
return &getPairTable()[index];
}
const ByamlHashPair* ByamlHashIter::getPairTable() const {
if (!mData)
return nullptr;
return reinterpret_cast<const ByamlHashPair*>(mData + 4);
}
u32 ByamlHashIter::getSize() const {
if (!mData)
return 0;
u32 val = *reinterpret_cast<const u32*>(mData);
return mIsRev ? bswap_24(val >> 8) : val >> 8;
}
ByamlArrayIter::ByamlArrayIter(const u8* data, bool isRev) : mData(data), mIsRev(isRev) {}
ByamlArrayIter::ByamlArrayIter() : mData(nullptr), mIsRev(false) {}
bool ByamlArrayIter::getDataByIndex(ByamlData* data, s32 index) const {
if (index < 0)
return false;
if (((s32)getSize()) <= index)
return false;
data->set(getTypeTable()[index], getDataTable()[index], mIsRev);
return true;
}
// NON_MATCHING: regalloc (https://decomp.me/scratch/dGFdU)
const u32* ByamlArrayIter::getDataTable() const {
return reinterpret_cast<const u32*>(getOffsetData((getSize() + 7) & 0xFFFFFFFC));
}
const u8* ByamlArrayIter::getOffsetData(u32 off) const {
return &mData[off];
}
u32 ByamlArrayIter::getSize() const {
u32 val = *reinterpret_cast<const u32*>(mData);
return mIsRev ? bswap_24(val >> 8) : val >> 8;
}
const u8* ByamlArrayIter::getTypeTable() const {
return mData + 4;
}
} // namespace al