mirror of https://github.com/AxioDL/metaforce.git
Fix reading/writing saves
This commit is contained in:
parent
e4715a2df6
commit
64e662069d
|
@ -216,14 +216,16 @@ void CMemoryCardSys::CCardFileInfo::BuildCardBuffer() {
|
||||||
u32 bannerSz = CalculateBannerDataSize();
|
u32 bannerSz = CalculateBannerDataSize();
|
||||||
x104_cardBuffer.resize((bannerSz + xf4_saveBuffer.size() + 8191) & ~8191);
|
x104_cardBuffer.resize((bannerSz + xf4_saveBuffer.size() + 8191) & ~8191);
|
||||||
|
|
||||||
CMemoryStreamOut w(x104_cardBuffer.data(), x104_cardBuffer.size(), CMemoryStreamOut::EOwnerShip::NotOwned);
|
{
|
||||||
w.WriteLong(0);
|
CMemoryStreamOut w(x104_cardBuffer.data(), x104_cardBuffer.size(), CMemoryStreamOut::EOwnerShip::NotOwned);
|
||||||
char comment[64];
|
w.WriteLong(0);
|
||||||
std::memset(comment, 0, std::size(comment));
|
char comment[64];
|
||||||
std::strncpy(comment, x28_comment.data(), std::size(comment) - 1);
|
std::memset(comment, 0, std::size(comment));
|
||||||
w.Write(reinterpret_cast<const u8*>(comment), 64);
|
std::strncpy(comment, x28_comment.data(), std::size(comment) - 1);
|
||||||
WriteBannerData(w);
|
w.Put(reinterpret_cast<const u8*>(comment), 64);
|
||||||
WriteIconData(w);
|
WriteBannerData(w);
|
||||||
|
WriteIconData(w);
|
||||||
|
}
|
||||||
memmove(x104_cardBuffer.data() + bannerSz, xf4_saveBuffer.data(), xf4_saveBuffer.size());
|
memmove(x104_cardBuffer.data() + bannerSz, xf4_saveBuffer.data(), xf4_saveBuffer.size());
|
||||||
reinterpret_cast<u32&>(*x104_cardBuffer.data()) =
|
reinterpret_cast<u32&>(*x104_cardBuffer.data()) =
|
||||||
CBasics::SwapBytes(CCRC32::Calculate(x104_cardBuffer.data() + 4, x104_cardBuffer.size() - 4));
|
CBasics::SwapBytes(CCRC32::Calculate(x104_cardBuffer.data() + 4, x104_cardBuffer.size() - 4));
|
||||||
|
@ -237,12 +239,12 @@ void CMemoryCardSys::CCardFileInfo::WriteBannerData(COutputStream& out) const {
|
||||||
const auto format = tex->GetTextureFormat();
|
const auto format = tex->GetTextureFormat();
|
||||||
const auto* texels = tex->GetConstBitMapData(0);
|
const auto* texels = tex->GetConstBitMapData(0);
|
||||||
if (format == ETexelFormat::RGB5A3) {
|
if (format == ETexelFormat::RGB5A3) {
|
||||||
out.Write(texels, 6144);
|
out.Put(texels, 6144);
|
||||||
} else {
|
} else {
|
||||||
out.Write(texels, 3072);
|
out.Put(texels, 3072);
|
||||||
}
|
}
|
||||||
if (format == ETexelFormat::C8) {
|
if (format == ETexelFormat::C8) {
|
||||||
out.Write(tex->GetPalette()->GetEntries(), 512);
|
out.Put(tex->GetPalette()->GetEntries(), 512);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,16 +255,16 @@ void CMemoryCardSys::CCardFileInfo::WriteIconData(COutputStream& out) const {
|
||||||
const auto format = icon.x8_tex->GetTextureFormat();
|
const auto format = icon.x8_tex->GetTextureFormat();
|
||||||
const auto* texels = icon.x8_tex->GetConstBitMapData(0);
|
const auto* texels = icon.x8_tex->GetConstBitMapData(0);
|
||||||
if (format == ETexelFormat::RGB5A3) {
|
if (format == ETexelFormat::RGB5A3) {
|
||||||
out.Write(texels, 2048);
|
out.Put(texels, 2048);
|
||||||
} else {
|
} else {
|
||||||
out.Write(texels, 1024);
|
out.Put(texels, 1024);
|
||||||
}
|
}
|
||||||
if (format == ETexelFormat::C8) {
|
if (format == ETexelFormat::C8) {
|
||||||
palette = icon.x8_tex->GetPalette()->GetEntries();
|
palette = icon.x8_tex->GetPalette()->GetEntries();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (palette != nullptr) {
|
if (palette != nullptr) {
|
||||||
out.Write(palette, 512);
|
out.Put(palette, 512);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ std::string CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot, bool do
|
||||||
}
|
}
|
||||||
auto path = *dolphinPath + "GC";
|
auto path = *dolphinPath + "GC";
|
||||||
int ret = mkdir(path.c_str(), 0755);
|
int ret = mkdir(path.c_str(), 0755);
|
||||||
if (ret != 0 && ret != EEXIST) {
|
if (ret != 0 && errno != EEXIST) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,31 +98,29 @@ u32 CInputStream::ReadBytes(void* dest, u32 len) {
|
||||||
|
|
||||||
u32 CInputStream::ReadBits(u32 bitCount) {
|
u32 CInputStream::ReadBits(u32 bitCount) {
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
const s32 shiftAmt = x20_bitOffset - s32(bitCount);
|
u32 bitOffset = x20_bitOffset;
|
||||||
if (shiftAmt < 0) {
|
if (bitOffset < bitCount) {
|
||||||
/* OR in remaining bits of cached value */
|
u32 shiftAmt = bitCount - bitOffset;
|
||||||
u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
const u32 mask = bitOffset == 32 ? 0xffffffff : (1 << bitOffset) - 1;
|
||||||
ret |= (x1c_bitWord << u32(-shiftAmt)) & mask;
|
const u32 bitWord = x1c_bitWord;
|
||||||
/* Load in exact number of bytes remaining */
|
x20_bitOffset = 0;
|
||||||
auto loadDiv = std::div(-shiftAmt, 8);
|
const u32 len = (shiftAmt / 8) + static_cast<unsigned int>((shiftAmt % 8) != 0);
|
||||||
if (loadDiv.rem != 0) {
|
Get(reinterpret_cast<u8*>(&x1c_bitWord), len);
|
||||||
++loadDiv.quot;
|
#if METAFORCE_TARGET_BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
}
|
|
||||||
Get(reinterpret_cast<u8*>(&x1c_bitWord) + 4 - loadDiv.quot, loadDiv.quot);
|
|
||||||
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
|
|
||||||
x1c_bitWord = CBasics::SwapBytes(x1c_bitWord);
|
x1c_bitWord = CBasics::SwapBytes(x1c_bitWord);
|
||||||
#endif
|
#endif
|
||||||
/* New bit offset */
|
const u32 mask2 = shiftAmt == 32 ? 0xffffffff : (1 << shiftAmt) - 1;
|
||||||
x20_bitOffset = loadDiv.quot * 8 + shiftAmt;
|
u32 tmp = x20_bitOffset;
|
||||||
/* OR in next bits */
|
x20_bitOffset = len * 8;
|
||||||
mask = (1U << u32(-shiftAmt)) - 1;
|
ret = ((mask & (bitWord >> (32 - bitOffset))) << shiftAmt) |
|
||||||
ret |= (x1c_bitWord >> x20_bitOffset) & mask;
|
((mask2 & (x1c_bitWord >> (32 - shiftAmt))) << tmp);
|
||||||
|
x20_bitOffset -= shiftAmt;
|
||||||
|
x1c_bitWord <<= u64(shiftAmt);
|
||||||
} else {
|
} else {
|
||||||
/* OR in bits of cached value */
|
u32 baseVal2 = (bitCount == 0x20 ? 0xffffffff : (1 << bitCount) - 1);
|
||||||
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
|
||||||
ret |= (x1c_bitWord >> u32(shiftAmt)) & mask;
|
|
||||||
/* New bit offset */
|
|
||||||
x20_bitOffset -= bitCount;
|
x20_bitOffset -= bitCount;
|
||||||
|
ret = baseVal2 & (x1c_bitWord >> (32 - bitCount));
|
||||||
|
x1c_bitWord <<= u64(bitCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -18,13 +18,12 @@ class CInputStream {
|
||||||
bool InternalReadNext();
|
bool InternalReadNext();
|
||||||
bool GrabAnotherBlock();
|
bool GrabAnotherBlock();
|
||||||
|
|
||||||
|
virtual u32 Read(void* dest, u32 len) = 0;
|
||||||
public:
|
public:
|
||||||
explicit CInputStream(s32 len);
|
explicit CInputStream(s32 len);
|
||||||
CInputStream(const void* ptr, u32 len, bool owned);
|
CInputStream(const void* ptr, u32 len, bool owned);
|
||||||
virtual ~CInputStream();
|
virtual ~CInputStream();
|
||||||
|
|
||||||
virtual u32 Read(void* dest, u32 len) = 0;
|
|
||||||
|
|
||||||
u32 GetReadPosition() const { return x18_readPosition; }
|
u32 GetReadPosition() const { return x18_readPosition; }
|
||||||
u32 ReadBits(u32 bitCount);
|
u32 ReadBits(u32 bitCount);
|
||||||
u32 ReadBytes(void* dest, u32 len);
|
u32 ReadBytes(void* dest, u32 len);
|
||||||
|
|
|
@ -15,13 +15,14 @@ private:
|
||||||
u32 x84_position = 0;
|
u32 x84_position = 0;
|
||||||
bool x88_owned;
|
bool x88_owned;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Write(const u8* ptr, u32 len) override;
|
||||||
public:
|
public:
|
||||||
CMemoryStreamOut(u8* workBuf, u32 len, EOwnerShip ownership = EOwnerShip::NotOwned, s32 unk = 4096)
|
CMemoryStreamOut(u8* workBuf, u32 len, EOwnerShip ownership = EOwnerShip::NotOwned, s32 blockLen = 4096)
|
||||||
: COutputStream(workBuf, unk), x7c_ptr(workBuf), x80_len(len), x88_owned(ownership == EOwnerShip::Owned) {}
|
: COutputStream(blockLen), x7c_ptr(workBuf), x80_len(len), x88_owned(ownership == EOwnerShip::Owned) {}
|
||||||
|
|
||||||
~CMemoryStreamOut() override;
|
~CMemoryStreamOut() override;
|
||||||
|
|
||||||
void Write(const u8* ptr, u32 len) override;
|
|
||||||
u32 GetWritePosition() const { return x84_position; }
|
u32 GetWritePosition() const { return x84_position; }
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
static u32 min_containing_bytes(u32 v) {
|
static u32 min_containing_bytes(u32 v) {
|
||||||
v = 32 - v;
|
v = 32 - v;
|
||||||
v = (v >> 3) - (static_cast<s32>(-(v & 7)) >> 31);
|
return (v / 8) + static_cast<unsigned int>((v % 8) != 0);
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COutputStream::COutputStream(u8* ptr, s32 len) : x8_bufLen(len) {
|
COutputStream::COutputStream(s32 len) : x8_bufLen(len) {
|
||||||
xc_ptr = len <= 64 ? reinterpret_cast<u8*>(((reinterpret_cast<uintptr_t>(x1c_scratch) + 7) & ~7) + 6) : new u8[len];
|
xc_ptr = len <= 64 ? reinterpret_cast<u8*>(((reinterpret_cast<uintptr_t>(x1c_scratch) + 7) & ~7) + 6) : new u8[len];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,24 +33,23 @@ void COutputStream::DoPut(const u8* ptr, u32 len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
x10_numWrites += len;
|
x10_numWrites += len;
|
||||||
u32 offset = x4_position;
|
|
||||||
u32 curLen = len;
|
u32 curLen = len;
|
||||||
if (x8_bufLen < len + offset) {
|
if (x8_bufLen < len + x4_position) {
|
||||||
while (curLen != 0) {
|
while (curLen != 0) {
|
||||||
offset = x4_position;
|
u32 count = x8_bufLen - x4_position;
|
||||||
u32 count = x8_bufLen - offset;
|
|
||||||
if (curLen < count) {
|
if (curLen < count) {
|
||||||
count = curLen;
|
count = curLen;
|
||||||
}
|
}
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
DoFlush();
|
DoFlush();
|
||||||
} else {
|
} else {
|
||||||
memcpy(xc_ptr + offset, ptr + (len - curLen), count);
|
memcpy(xc_ptr + x4_position, ptr + (len - curLen), count);
|
||||||
|
x4_position += count;
|
||||||
curLen -= count;
|
curLen -= count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(xc_ptr + offset, ptr, len);
|
memcpy(xc_ptr + x4_position, ptr, len);
|
||||||
x4_position += len;
|
x4_position += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,28 +75,21 @@ void COutputStream::Put(const u8* ptr, u32 len) {
|
||||||
DoPut(ptr, len);
|
DoPut(ptr, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void COutputStream::WriteBits(u32 val, u32 bitCount) {
|
void COutputStream::WriteBits(u32 value, u32 bitCount) {
|
||||||
const s32 shiftAmt = x18_shiftRegisterOffset - s32(bitCount);
|
u32 bitOffset = x18_shiftRegisterOffset;
|
||||||
if (shiftAmt < 0) {
|
if (bitOffset < bitCount) {
|
||||||
/* OR remaining bits to cached value */
|
u32 shiftAmt = bitCount - bitOffset;
|
||||||
const u32 mask = (1U << x18_shiftRegisterOffset) - 1;
|
x14_shiftRegister |= (value >> shiftAmt) & (bitOffset == 32 ? 0xffffffff : (1 << bitOffset) - 1);
|
||||||
x14_shiftRegister |= (val >> u32(-shiftAmt)) & mask;
|
x18_shiftRegisterOffset = 0;
|
||||||
|
|
||||||
/* Write out 32-bits */
|
|
||||||
FlushShiftRegister();
|
FlushShiftRegister();
|
||||||
|
const u32 mask = (shiftAmt == 0x20 ? 0xffffffff : (1 << shiftAmt) - 1);
|
||||||
/* Cache remaining bits */
|
x14_shiftRegister = (value & mask) << (0x20 - shiftAmt);
|
||||||
x18_shiftRegisterOffset = 0x20 + shiftAmt;
|
x18_shiftRegisterOffset -= shiftAmt;
|
||||||
x14_shiftRegister = val << x18_shiftRegisterOffset;
|
|
||||||
} else {
|
} else {
|
||||||
/* OR bits to cached value */
|
const u32 mask = bitCount == 32 ? 0xffffffff : (1 << bitCount) - 1;
|
||||||
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
x14_shiftRegister |= (value & mask) << (bitOffset - bitCount);
|
||||||
x14_shiftRegister |= (val & mask) << u32(shiftAmt);
|
|
||||||
|
|
||||||
/* New bit offset */
|
|
||||||
x18_shiftRegisterOffset -= bitCount;
|
x18_shiftRegisterOffset -= bitCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void COutputStream::WriteChar(u8 c) {
|
void COutputStream::WriteChar(u8 c) {
|
||||||
|
|
|
@ -19,11 +19,10 @@ class COutputStream {
|
||||||
protected:
|
protected:
|
||||||
void DoFlush();
|
void DoFlush();
|
||||||
void DoPut(const u8* ptr, u32 len);
|
void DoPut(const u8* ptr, u32 len);
|
||||||
|
|
||||||
public:
|
|
||||||
COutputStream(u8* ptr, s32 unk);
|
|
||||||
virtual ~COutputStream();
|
|
||||||
virtual void Write(const u8* ptr, u32 len) = 0;
|
virtual void Write(const u8* ptr, u32 len) = 0;
|
||||||
|
public:
|
||||||
|
COutputStream(s32 unk);
|
||||||
|
virtual ~COutputStream();
|
||||||
|
|
||||||
void WriteBits(u32 val, u32 bitCount);
|
void WriteBits(u32 val, u32 bitCount);
|
||||||
void WriteChar(u8 c);
|
void WriteChar(u8 c);
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
class CZipInputStream : public CInputStream {
|
class CZipInputStream final : public CInputStream {
|
||||||
std::unique_ptr<u8[]> x24_compBuf;
|
std::unique_ptr<u8[]> x24_compBuf;
|
||||||
std::unique_ptr<CInputStream> x28_strm;
|
std::unique_ptr<CInputStream> x28_strm;
|
||||||
std::unique_ptr<z_stream> x30_zstrm = {};
|
std::unique_ptr<z_stream> x30_zstrm = {};
|
||||||
|
|
||||||
|
u32 Read(void* ptr, u32 len) override;
|
||||||
public:
|
public:
|
||||||
explicit CZipInputStream(std::unique_ptr<CInputStream>&& strm);
|
explicit CZipInputStream(std::unique_ptr<CInputStream>&& strm);
|
||||||
~CZipInputStream() override;
|
~CZipInputStream() override;
|
||||||
|
|
||||||
u32 Read(void* ptr, u32 len) override;
|
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
||||||
|
|
Loading…
Reference in New Issue