mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 04:04:18 +02:00
Decode Yaz0 through guarded host buffers
Ported from chrissotraidis/wiicompiled (KartPad) 97cdc9a3609b6d3ad43009f76be17361b1a9e93a. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rLZ24cFcqTNBmb4w2dpSq
This commit is contained in:
1 parent
03db602a05
commit
8e9e905b85
1 file changed
+68
-13
@@ -1,20 +1,19 @@
|
||||
#include "hle_stubs.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include "memory.h"
|
||||
#include "recomp_mod_loader.h"
|
||||
#include "runtime_log.h"
|
||||
|
||||
extern "C" void GxNotifyGuestRamDmaWrite(uint32_t addr, uint32_t size);
|
||||
|
||||
// Native because a crafted Yaz0 run writes past the caller's buffer
|
||||
// (github.com/vabold/szsHaxx)
|
||||
// https://github.com/vabold/Kinoko/blob/main/source/egg/core/Decomp.cc
|
||||
|
||||
extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
{
|
||||
const uint32_t expandSize = (static_cast<uint32_t>(MemoryInline::FlatRead8(src + 4)) << 24) |
|
||||
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 5)) << 16) |
|
||||
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 6)) << 8) |
|
||||
static_cast<uint32_t>(MemoryInline::FlatRead8(src + 7));
|
||||
|
||||
template <typename Access>
|
||||
static uint32_t DecodeSZS(uint32_t src, uint32_t expandSize, Access& access) {
|
||||
uint32_t srcIdx = 16;
|
||||
uint32_t dstIdx = 0;
|
||||
uint32_t mask = 0;
|
||||
@@ -22,15 +21,15 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
|
||||
while (static_cast<int32_t>(dstIdx) < static_cast<int32_t>(expandSize)) {
|
||||
if (mask == 0) {
|
||||
flags = MemoryInline::FlatRead8(src + srcIdx++);
|
||||
flags = access.ReadSource(srcIdx++);
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
if ((flags & mask) != 0) {
|
||||
MemoryInline::FlatWrite8(dst + dstIdx++, MemoryInline::FlatRead8(src + srcIdx++));
|
||||
access.WriteOutput(dstIdx++, access.ReadSource(srcIdx++));
|
||||
} else {
|
||||
const uint32_t high = MemoryInline::FlatRead8(src + srcIdx);
|
||||
const uint32_t low = MemoryInline::FlatRead8(src + srcIdx + 1);
|
||||
const uint32_t high = access.ReadSource(srcIdx);
|
||||
const uint32_t low = access.ReadSource(srcIdx + 1);
|
||||
srcIdx += 2;
|
||||
|
||||
const uint32_t rep = (high << 8) | low;
|
||||
@@ -48,7 +47,7 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
uint32_t count = rep >> 12;
|
||||
count = count != 0
|
||||
? count + 2
|
||||
: static_cast<uint32_t>(MemoryInline::FlatRead8(src + srcIdx++)) + 18;
|
||||
: static_cast<uint32_t>(access.ReadSource(srcIdx++)) + 18;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (dstIdx >= expandSize) {
|
||||
@@ -59,7 +58,7 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
"The game stopped decoding a malformed Yaz0 file.");
|
||||
std::abort();
|
||||
}
|
||||
MemoryInline::FlatWrite8(dst + dstIdx++, MemoryInline::FlatRead8(dst + copyIdx++));
|
||||
access.WriteOutput(dstIdx++, access.ReadOutput(copyIdx++));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,5 +68,61 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
return expandSize;
|
||||
}
|
||||
|
||||
struct GuestSZSAccess {
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
|
||||
uint8_t ReadSource(uint32_t offset) const { return MemoryInline::FlatRead8(src + offset); }
|
||||
uint8_t ReadOutput(uint32_t offset) const { return MemoryInline::FlatRead8(dst + offset); }
|
||||
void WriteOutput(uint32_t offset, uint8_t value) const {
|
||||
MemoryInline::FlatWrite8(dst + offset, value);
|
||||
}
|
||||
};
|
||||
|
||||
struct HostSZSAccess {
|
||||
const uint8_t* src;
|
||||
uint8_t* dst;
|
||||
|
||||
uint8_t ReadSource(uint32_t offset) const { return src[offset]; }
|
||||
uint8_t ReadOutput(uint32_t offset) const { return dst[offset]; }
|
||||
void WriteOutput(uint32_t offset, uint8_t value) const { dst[offset] = value; }
|
||||
};
|
||||
|
||||
static bool HasDeferredReadPages(uint32_t address, size_t length) {
|
||||
const uint32_t first = address >> MemoryInline::kPageShift;
|
||||
const uint32_t last = static_cast<uint32_t>(
|
||||
(static_cast<uint64_t>(address) + length - 1) >> MemoryInline::kPageShift);
|
||||
for (uint32_t page = first; page <= last; ++page) {
|
||||
if (MemoryInline::g_deferredReadCoveredPages[page] != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
|
||||
{
|
||||
const uint32_t expandSize = (static_cast<uint32_t>(MemoryInline::FlatRead8(src + 4)) << 24) |
|
||||
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 5)) << 16) |
|
||||
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 6)) << 8) |
|
||||
static_cast<uint32_t>(MemoryInline::FlatRead8(src + 7));
|
||||
|
||||
// A token produces at least one byte; all-literal data is the largest
|
||||
// valid input (one flag per eight output bytes). Three extra bytes cover
|
||||
// the final malformed run before its output-overrun check aborts.
|
||||
const size_t maxSourceBytes = 16ull + expandSize + (static_cast<uint64_t>(expandSize) + 7) / 8 + 3;
|
||||
if (expandSize != 0 && expandSize <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) &&
|
||||
!GuestFlat::RequiresCheckedAccess() &&
|
||||
Memory::Contains(src, maxSourceBytes) && Memory::Contains(dst, expandSize) &&
|
||||
!HasDeferredReadPages(src, maxSourceBytes) && !HasDeferredReadPages(dst, expandSize) &&
|
||||
!RecompMod::ExecutableWriteGuardMayHit(dst, expandSize)) {
|
||||
HostSZSAccess access{Memory::GetPointer(src, maxSourceBytes), Memory::GetPointer(dst, expandSize)};
|
||||
const uint32_t decoded = DecodeSZS(src, expandSize, access);
|
||||
GxNotifyGuestRamDmaWrite(dst, decoded);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
GuestSZSAccess access{src, dst};
|
||||
return DecodeSZS(src, expandSize, access);
|
||||
}
|
||||
|
||||
PPC_NATIVE_OVERRIDE(80218C2C, EGG_Decomp_decodeSZS_80218c2c, uint32_t,
|
||||
(uint32_t src, uint32_t dst), (src, dst));
|
||||
Reference in new issue
Block a user