From 64e662069d50132efce196553cd85cf77484713c Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 22 Mar 2022 01:37:10 -0700 Subject: [PATCH] Fix reading/writing saves --- Runtime/CMemoryCardSys.cpp | 30 ++++++++++--------- Runtime/CMemoryCardSysNix.cpp | 2 +- Runtime/Streams/CInputStream.cpp | 40 ++++++++++++------------- Runtime/Streams/CInputStream.hpp | 3 +- Runtime/Streams/CMemoryStreamOut.hpp | 7 +++-- Runtime/Streams/COutputStream.cpp | 45 +++++++++++----------------- Runtime/Streams/COutputStream.hpp | 7 ++--- Runtime/Streams/CZipInputStream.hpp | 4 +-- 8 files changed, 64 insertions(+), 74 deletions(-) diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index e70e75f27..5fb68ed55 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -216,14 +216,16 @@ void CMemoryCardSys::CCardFileInfo::BuildCardBuffer() { u32 bannerSz = CalculateBannerDataSize(); x104_cardBuffer.resize((bannerSz + xf4_saveBuffer.size() + 8191) & ~8191); - CMemoryStreamOut w(x104_cardBuffer.data(), x104_cardBuffer.size(), CMemoryStreamOut::EOwnerShip::NotOwned); - w.WriteLong(0); - char comment[64]; - std::memset(comment, 0, std::size(comment)); - std::strncpy(comment, x28_comment.data(), std::size(comment) - 1); - w.Write(reinterpret_cast(comment), 64); - WriteBannerData(w); - WriteIconData(w); + { + CMemoryStreamOut w(x104_cardBuffer.data(), x104_cardBuffer.size(), CMemoryStreamOut::EOwnerShip::NotOwned); + w.WriteLong(0); + char comment[64]; + std::memset(comment, 0, std::size(comment)); + std::strncpy(comment, x28_comment.data(), std::size(comment) - 1); + w.Put(reinterpret_cast(comment), 64); + WriteBannerData(w); + WriteIconData(w); + } memmove(x104_cardBuffer.data() + bannerSz, xf4_saveBuffer.data(), xf4_saveBuffer.size()); reinterpret_cast(*x104_cardBuffer.data()) = 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* texels = tex->GetConstBitMapData(0); if (format == ETexelFormat::RGB5A3) { - out.Write(texels, 6144); + out.Put(texels, 6144); } else { - out.Write(texels, 3072); + out.Put(texels, 3072); } 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* texels = icon.x8_tex->GetConstBitMapData(0); if (format == ETexelFormat::RGB5A3) { - out.Write(texels, 2048); + out.Put(texels, 2048); } else { - out.Write(texels, 1024); + out.Put(texels, 1024); } if (format == ETexelFormat::C8) { palette = icon.x8_tex->GetPalette()->GetEntries(); } } if (palette != nullptr) { - out.Write(palette, 512); + out.Put(palette, 512); } } diff --git a/Runtime/CMemoryCardSysNix.cpp b/Runtime/CMemoryCardSysNix.cpp index aa69557ed..bebc5db5f 100644 --- a/Runtime/CMemoryCardSysNix.cpp +++ b/Runtime/CMemoryCardSysNix.cpp @@ -60,7 +60,7 @@ std::string CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot, bool do } auto path = *dolphinPath + "GC"; int ret = mkdir(path.c_str(), 0755); - if (ret != 0 && ret != EEXIST) { + if (ret != 0 && errno != EEXIST) { return {}; } diff --git a/Runtime/Streams/CInputStream.cpp b/Runtime/Streams/CInputStream.cpp index 2703c9ac4..0b595f31a 100644 --- a/Runtime/Streams/CInputStream.cpp +++ b/Runtime/Streams/CInputStream.cpp @@ -98,31 +98,29 @@ u32 CInputStream::ReadBytes(void* dest, u32 len) { u32 CInputStream::ReadBits(u32 bitCount) { u32 ret = 0; - const s32 shiftAmt = x20_bitOffset - s32(bitCount); - if (shiftAmt < 0) { - /* OR in remaining bits of cached value */ - u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); - ret |= (x1c_bitWord << u32(-shiftAmt)) & mask; - /* Load in exact number of bytes remaining */ - auto loadDiv = std::div(-shiftAmt, 8); - if (loadDiv.rem != 0) { - ++loadDiv.quot; - } - Get(reinterpret_cast(&x1c_bitWord) + 4 - loadDiv.quot, loadDiv.quot); -#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ + u32 bitOffset = x20_bitOffset; + if (bitOffset < bitCount) { + u32 shiftAmt = bitCount - bitOffset; + const u32 mask = bitOffset == 32 ? 0xffffffff : (1 << bitOffset) - 1; + const u32 bitWord = x1c_bitWord; + x20_bitOffset = 0; + const u32 len = (shiftAmt / 8) + static_cast((shiftAmt % 8) != 0); + Get(reinterpret_cast(&x1c_bitWord), len); +#if METAFORCE_TARGET_BYTE_ORDER == __LITTLE_ENDIAN x1c_bitWord = CBasics::SwapBytes(x1c_bitWord); #endif - /* New bit offset */ - x20_bitOffset = loadDiv.quot * 8 + shiftAmt; - /* OR in next bits */ - mask = (1U << u32(-shiftAmt)) - 1; - ret |= (x1c_bitWord >> x20_bitOffset) & mask; + const u32 mask2 = shiftAmt == 32 ? 0xffffffff : (1 << shiftAmt) - 1; + u32 tmp = x20_bitOffset; + x20_bitOffset = len * 8; + ret = ((mask & (bitWord >> (32 - bitOffset))) << shiftAmt) | + ((mask2 & (x1c_bitWord >> (32 - shiftAmt))) << tmp); + x20_bitOffset -= shiftAmt; + x1c_bitWord <<= u64(shiftAmt); } else { - /* OR in bits of cached value */ - const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); - ret |= (x1c_bitWord >> u32(shiftAmt)) & mask; - /* New bit offset */ + u32 baseVal2 = (bitCount == 0x20 ? 0xffffffff : (1 << bitCount) - 1); x20_bitOffset -= bitCount; + ret = baseVal2 & (x1c_bitWord >> (32 - bitCount)); + x1c_bitWord <<= u64(bitCount); } return ret; diff --git a/Runtime/Streams/CInputStream.hpp b/Runtime/Streams/CInputStream.hpp index 2eb74e03b..7a5b94546 100644 --- a/Runtime/Streams/CInputStream.hpp +++ b/Runtime/Streams/CInputStream.hpp @@ -18,13 +18,12 @@ class CInputStream { bool InternalReadNext(); bool GrabAnotherBlock(); + virtual u32 Read(void* dest, u32 len) = 0; public: explicit CInputStream(s32 len); CInputStream(const void* ptr, u32 len, bool owned); virtual ~CInputStream(); - virtual u32 Read(void* dest, u32 len) = 0; - u32 GetReadPosition() const { return x18_readPosition; } u32 ReadBits(u32 bitCount); u32 ReadBytes(void* dest, u32 len); diff --git a/Runtime/Streams/CMemoryStreamOut.hpp b/Runtime/Streams/CMemoryStreamOut.hpp index 41633e0d4..75698982f 100644 --- a/Runtime/Streams/CMemoryStreamOut.hpp +++ b/Runtime/Streams/CMemoryStreamOut.hpp @@ -15,13 +15,14 @@ private: u32 x84_position = 0; bool x88_owned; +protected: + void Write(const u8* ptr, u32 len) override; public: - CMemoryStreamOut(u8* workBuf, u32 len, EOwnerShip ownership = EOwnerShip::NotOwned, s32 unk = 4096) - : COutputStream(workBuf, unk), x7c_ptr(workBuf), x80_len(len), x88_owned(ownership == EOwnerShip::Owned) {} + CMemoryStreamOut(u8* workBuf, u32 len, EOwnerShip ownership = EOwnerShip::NotOwned, s32 blockLen = 4096) + : COutputStream(blockLen), x7c_ptr(workBuf), x80_len(len), x88_owned(ownership == EOwnerShip::Owned) {} ~CMemoryStreamOut() override; - void Write(const u8* ptr, u32 len) override; u32 GetWritePosition() const { return x84_position; } }; } // namespace metaforce diff --git a/Runtime/Streams/COutputStream.cpp b/Runtime/Streams/COutputStream.cpp index c38296b3f..06aee000e 100644 --- a/Runtime/Streams/COutputStream.cpp +++ b/Runtime/Streams/COutputStream.cpp @@ -7,11 +7,10 @@ namespace metaforce { static u32 min_containing_bytes(u32 v) { v = 32 - v; - v = (v >> 3) - (static_cast(-(v & 7)) >> 31); - return v; + return (v / 8) + static_cast((v % 8) != 0); } -COutputStream::COutputStream(u8* ptr, s32 len) : x8_bufLen(len) { +COutputStream::COutputStream(s32 len) : x8_bufLen(len) { xc_ptr = len <= 64 ? reinterpret_cast(((reinterpret_cast(x1c_scratch) + 7) & ~7) + 6) : new u8[len]; } @@ -34,24 +33,23 @@ void COutputStream::DoPut(const u8* ptr, u32 len) { } x10_numWrites += len; - u32 offset = x4_position; u32 curLen = len; - if (x8_bufLen < len + offset) { + if (x8_bufLen < len + x4_position) { while (curLen != 0) { - offset = x4_position; - u32 count = x8_bufLen - offset; + u32 count = x8_bufLen - x4_position; if (curLen < count) { count = curLen; } if (count == 0) { DoFlush(); } else { - memcpy(xc_ptr + offset, ptr + (len - curLen), count); + memcpy(xc_ptr + x4_position, ptr + (len - curLen), count); + x4_position += count; curLen -= count; } } } else { - memcpy(xc_ptr + offset, ptr, len); + memcpy(xc_ptr + x4_position, ptr, len); x4_position += len; } } @@ -77,28 +75,21 @@ void COutputStream::Put(const u8* ptr, u32 len) { DoPut(ptr, len); } -void COutputStream::WriteBits(u32 val, u32 bitCount) { - const s32 shiftAmt = x18_shiftRegisterOffset - s32(bitCount); - if (shiftAmt < 0) { - /* OR remaining bits to cached value */ - const u32 mask = (1U << x18_shiftRegisterOffset) - 1; - x14_shiftRegister |= (val >> u32(-shiftAmt)) & mask; - - /* Write out 32-bits */ +void COutputStream::WriteBits(u32 value, u32 bitCount) { + u32 bitOffset = x18_shiftRegisterOffset; + if (bitOffset < bitCount) { + u32 shiftAmt = bitCount - bitOffset; + x14_shiftRegister |= (value >> shiftAmt) & (bitOffset == 32 ? 0xffffffff : (1 << bitOffset) - 1); + x18_shiftRegisterOffset = 0; FlushShiftRegister(); - - /* Cache remaining bits */ - x18_shiftRegisterOffset = 0x20 + shiftAmt; - x14_shiftRegister = val << x18_shiftRegisterOffset; + const u32 mask = (shiftAmt == 0x20 ? 0xffffffff : (1 << shiftAmt) - 1); + x14_shiftRegister = (value & mask) << (0x20 - shiftAmt); + x18_shiftRegisterOffset -= shiftAmt; } else { - /* OR bits to cached value */ - const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); - x14_shiftRegister |= (val & mask) << u32(shiftAmt); - - /* New bit offset */ + const u32 mask = bitCount == 32 ? 0xffffffff : (1 << bitCount) - 1; + x14_shiftRegister |= (value & mask) << (bitOffset - bitCount); x18_shiftRegisterOffset -= bitCount; } - } void COutputStream::WriteChar(u8 c) { diff --git a/Runtime/Streams/COutputStream.hpp b/Runtime/Streams/COutputStream.hpp index 2bd1e2c2d..d8c0c833a 100644 --- a/Runtime/Streams/COutputStream.hpp +++ b/Runtime/Streams/COutputStream.hpp @@ -19,11 +19,10 @@ class COutputStream { protected: void DoFlush(); void DoPut(const u8* ptr, u32 len); - -public: - COutputStream(u8* ptr, s32 unk); - virtual ~COutputStream(); virtual void Write(const u8* ptr, u32 len) = 0; +public: + COutputStream(s32 unk); + virtual ~COutputStream(); void WriteBits(u32 val, u32 bitCount); void WriteChar(u8 c); diff --git a/Runtime/Streams/CZipInputStream.hpp b/Runtime/Streams/CZipInputStream.hpp index ae2eaed98..131d41fe1 100644 --- a/Runtime/Streams/CZipInputStream.hpp +++ b/Runtime/Streams/CZipInputStream.hpp @@ -7,15 +7,15 @@ #include namespace metaforce { -class CZipInputStream : public CInputStream { +class CZipInputStream final : public CInputStream { std::unique_ptr x24_compBuf; std::unique_ptr x28_strm; std::unique_ptr x30_zstrm = {}; + u32 Read(void* ptr, u32 len) override; public: explicit CZipInputStream(std::unique_ptr&& strm); ~CZipInputStream() override; - u32 Read(void* ptr, u32 len) override; }; } // namespace metaforce