mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-06-06 01:02:08 +00:00
clang-format Workflow
Signed-off-by: Isaac Marovitz <isaacryu@icloud.com>
This commit is contained in:
parent
7b8e37aa37
commit
10b627e986
17
.clang-format
Normal file
17
.clang-format
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
BasedOnStyle: LLVM
|
||||||
|
UseTab: Never
|
||||||
|
IndentWidth: 4
|
||||||
|
Language: Cpp
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Left
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
LineEnding: LF
|
||||||
|
ColumnLimit: 0
|
||||||
|
IndentCaseLabels: false
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
SpaceBeforeCpp11BracedList: true
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
25
.github/workflows/format.yml
vendored
Normal file
25
.github/workflows/format.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: Clang Format
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "**/*.md"
|
||||||
|
- '**/*.txt'
|
||||||
|
- 'thirdparty/*'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "**/*.md"
|
||||||
|
- '**/*.txt'
|
||||||
|
- 'thirdparty/*'
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run clang-format
|
||||||
|
uses: jidicula/clang-format-action@v4.14.0
|
||||||
|
with:
|
||||||
|
exclude-regex: (thirdparty)
|
||||||
|
clang-format-version: 19
|
@ -1,10 +1,10 @@
|
|||||||
#include "function.h"
|
#include "function.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <bit>
|
||||||
|
#include <byteswap.h>
|
||||||
|
#include <cassert>
|
||||||
#include <disasm.h>
|
#include <disasm.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <bit>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <byteswap.h>
|
|
||||||
|
|
||||||
size_t Function::SearchBlock(size_t address) const
|
size_t Function::SearchBlock(size_t address) const
|
||||||
{
|
{
|
||||||
@ -40,7 +40,7 @@ size_t Function::SearchBlock(size_t address) const
|
|||||||
|
|
||||||
Function Function::Analyze(const void* code, size_t size, size_t base)
|
Function Function::Analyze(const void* code, size_t size, size_t base)
|
||||||
{
|
{
|
||||||
Function fn{ base, 0 };
|
Function fn { base, 0 };
|
||||||
|
|
||||||
if (*((uint32_t*)code + 1) == 0x04000048) // shifted ptr tail call
|
if (*((uint32_t*)code + 1) == 0x04000048) // shifted ptr tail call
|
||||||
{
|
{
|
||||||
@ -55,14 +55,16 @@ Function Function::Analyze(const void* code, size_t size, size_t base)
|
|||||||
const auto* data = (uint32_t*)code;
|
const auto* data = (uint32_t*)code;
|
||||||
const auto* dataStart = data;
|
const auto* dataStart = data;
|
||||||
const auto* dataEnd = (uint32_t*)((uint8_t*)code + size);
|
const auto* dataEnd = (uint32_t*)((uint8_t*)code + size);
|
||||||
std::vector<size_t> blockStack{};
|
std::vector<size_t> blockStack {};
|
||||||
blockStack.reserve(32);
|
blockStack.reserve(32);
|
||||||
blockStack.emplace_back();
|
blockStack.emplace_back();
|
||||||
|
|
||||||
#define RESTORE_DATA() if (!blockStack.empty()) data = (dataStart + ((blocks[blockStack.back()].base + blocks[blockStack.back()].size) / sizeof(*data))) - 1; // continue adds one
|
#define RESTORE_DATA() \
|
||||||
|
if (!blockStack.empty()) \
|
||||||
|
data = (dataStart + ((blocks[blockStack.back()].base + blocks[blockStack.back()].size) / sizeof(*data))) - 1; // continue adds one
|
||||||
|
|
||||||
// TODO: Branch fallthrough
|
// TODO: Branch fallthrough
|
||||||
for (; data <= dataEnd ; ++data)
|
for (; data <= dataEnd; ++data)
|
||||||
{
|
{
|
||||||
const size_t addr = base + ((data - dataStart) * sizeof(*data));
|
const size_t addr = base + ((data - dataStart) * sizeof(*data));
|
||||||
if (blockStack.empty())
|
if (blockStack.empty())
|
||||||
@ -82,7 +84,7 @@ Function Function::Analyze(const void* code, size_t size, size_t base)
|
|||||||
ppc::Disassemble(data, addr, insn);
|
ppc::Disassemble(data, addr, insn);
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
assert(addr == base + curBlock.base + curBlock.size);
|
assert(addr == base + curBlock.base + curBlock.size);
|
||||||
if (curBlock.projectedSize != -1 && curBlock.size >= curBlock.projectedSize) // fallthrough
|
if (curBlock.projectedSize != -1 && curBlock.size >= curBlock.projectedSize) // fallthrough
|
||||||
{
|
{
|
||||||
blockStack.pop_back();
|
blockStack.pop_back();
|
||||||
@ -172,7 +174,7 @@ Function Function::Analyze(const void* code, size_t size, size_t base)
|
|||||||
blocks.emplace_back(branchBase, 0, sizeProjection);
|
blocks.emplace_back(branchBase, 0, sizeProjection);
|
||||||
|
|
||||||
blockStack.emplace_back(blocks.size() - 1);
|
blockStack.emplace_back(blocks.size() - 1);
|
||||||
|
|
||||||
DEBUG(blocks.back().parent = blockBase);
|
DEBUG(blocks.back().parent = blockBase);
|
||||||
RESTORE_DATA();
|
RESTORE_DATA();
|
||||||
continue;
|
continue;
|
||||||
@ -214,9 +216,7 @@ Function Function::Analyze(const void* code, size_t size, size_t base)
|
|||||||
if (blocks.size() > 1)
|
if (blocks.size() > 1)
|
||||||
{
|
{
|
||||||
std::sort(blocks.begin(), blocks.end(), [](const Block& a, const Block& b)
|
std::sort(blocks.begin(), blocks.end(), [](const Block& a, const Block& b)
|
||||||
{
|
{ return a.base < b.base; });
|
||||||
return a.base < b.base;
|
|
||||||
});
|
|
||||||
|
|
||||||
size_t discontinuity = -1;
|
size_t discontinuity = -1;
|
||||||
for (size_t i = 0; i < blocks.size() - 1; i++)
|
for (size_t i = 0; i < blocks.size() - 1; i++)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include <cassert>
|
|
||||||
#include <iterator>
|
|
||||||
#include <file.h>
|
|
||||||
#include <disasm.h>
|
|
||||||
#include <image.h>
|
|
||||||
#include <xbox.h>
|
|
||||||
#include <fmt/core.h>
|
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <disasm.h>
|
||||||
|
#include <file.h>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <image.h>
|
||||||
|
#include <iterator>
|
||||||
|
#include <xbox.h>
|
||||||
|
|
||||||
#define SWITCH_ABSOLUTE 0
|
#define SWITCH_ABSOLUTE 0
|
||||||
#define SWITCH_COMPUTED 1
|
#define SWITCH_COMPUTED 1
|
||||||
@ -14,11 +14,11 @@
|
|||||||
|
|
||||||
struct SwitchTable
|
struct SwitchTable
|
||||||
{
|
{
|
||||||
std::vector<size_t> labels{};
|
std::vector<size_t> labels {};
|
||||||
size_t base{};
|
size_t base {};
|
||||||
size_t defaultLabel{};
|
size_t defaultLabel {};
|
||||||
uint32_t r{};
|
uint32_t r {};
|
||||||
uint32_t type{};
|
uint32_t type {};
|
||||||
};
|
};
|
||||||
|
|
||||||
void ReadTable(Image& image, SwitchTable& table)
|
void ReadTable(Image& image, SwitchTable& table)
|
||||||
@ -104,7 +104,7 @@ void ReadTable(Image& image, SwitchTable& table)
|
|||||||
void ScanTable(const uint32_t* code, size_t base, SwitchTable& table)
|
void ScanTable(const uint32_t* code, size_t base, SwitchTable& table)
|
||||||
{
|
{
|
||||||
ppc_insn insn;
|
ppc_insn insn;
|
||||||
uint32_t cr{ (uint32_t)-1 };
|
uint32_t cr { (uint32_t)-1 };
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
ppc::Disassemble(&code[-i], base - (4 * i), insn);
|
ppc::Disassemble(&code[-i], base - (4 * i), insn);
|
||||||
@ -193,65 +193,64 @@ int main(int argc, char** argv)
|
|||||||
auto image = Image::ParseImage(file.data(), file.size());
|
auto image = Image::ParseImage(file.data(), file.size());
|
||||||
|
|
||||||
auto printTable = [&](const SwitchTable& table)
|
auto printTable = [&](const SwitchTable& table)
|
||||||
|
{
|
||||||
|
println("[[switch]]");
|
||||||
|
println("base = 0x{:X}", table.base);
|
||||||
|
println("r = {}", table.r);
|
||||||
|
println("default = 0x{:X}", table.defaultLabel);
|
||||||
|
println("labels = [");
|
||||||
|
for (const auto& label : table.labels)
|
||||||
{
|
{
|
||||||
println("[[switch]]");
|
println(" 0x{:X},", label);
|
||||||
println("base = 0x{:X}", table.base);
|
}
|
||||||
println("r = {}", table.r);
|
|
||||||
println("default = 0x{:X}", table.defaultLabel);
|
|
||||||
println("labels = [");
|
|
||||||
for (const auto& label : table.labels)
|
|
||||||
{
|
|
||||||
println(" 0x{:X},", label);
|
|
||||||
}
|
|
||||||
|
|
||||||
println("]");
|
println("]");
|
||||||
println("");
|
println("");
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<SwitchTable> switches{};
|
std::vector<SwitchTable> switches {};
|
||||||
|
|
||||||
println("# Generated by XenonAnalyse");
|
println("# Generated by XenonAnalyse");
|
||||||
|
|
||||||
auto scanPattern = [&](uint32_t* pattern, size_t count, size_t type)
|
auto scanPattern = [&](uint32_t* pattern, size_t count, size_t type)
|
||||||
{
|
|
||||||
for (const auto& section : image.sections)
|
|
||||||
{
|
|
||||||
if (!(section.flags & SectionFlags_Code))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t base = section.base;
|
|
||||||
uint8_t* data = section.data;
|
|
||||||
uint8_t* dataStart = section.data;
|
|
||||||
uint8_t* dataEnd = section.data + section.size;
|
|
||||||
while (data < dataEnd && data != nullptr)
|
|
||||||
{
|
|
||||||
data = (uint8_t*)SearchMask(data, pattern, count, dataEnd - data);
|
|
||||||
|
|
||||||
if (data != nullptr)
|
|
||||||
{
|
|
||||||
SwitchTable table{};
|
|
||||||
table.type = type;
|
|
||||||
ScanTable((uint32_t*)data, base + (data - dataStart), table);
|
|
||||||
|
|
||||||
// fmt::println("{:X} ; jmptable - {}", base + (data - dataStart), table.labels.size());
|
|
||||||
if (table.base != 0)
|
|
||||||
{
|
|
||||||
ReadTable(image, table);
|
|
||||||
printTable(table);
|
|
||||||
switches.emplace_back(std::move(table));
|
|
||||||
}
|
|
||||||
|
|
||||||
data += 4;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t absoluteSwitch[] =
|
|
||||||
{
|
{
|
||||||
|
for (const auto& section : image.sections)
|
||||||
|
{
|
||||||
|
if (!(section.flags & SectionFlags_Code))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t base = section.base;
|
||||||
|
uint8_t* data = section.data;
|
||||||
|
uint8_t* dataStart = section.data;
|
||||||
|
uint8_t* dataEnd = section.data + section.size;
|
||||||
|
while (data < dataEnd && data != nullptr)
|
||||||
|
{
|
||||||
|
data = (uint8_t*)SearchMask(data, pattern, count, dataEnd - data);
|
||||||
|
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
SwitchTable table {};
|
||||||
|
table.type = type;
|
||||||
|
ScanTable((uint32_t*)data, base + (data - dataStart), table);
|
||||||
|
|
||||||
|
// fmt::println("{:X} ; jmptable - {}", base + (data - dataStart), table.labels.size());
|
||||||
|
if (table.base != 0)
|
||||||
|
{
|
||||||
|
ReadTable(image, table);
|
||||||
|
printTable(table);
|
||||||
|
switches.emplace_back(std::move(table));
|
||||||
|
}
|
||||||
|
|
||||||
|
data += 4;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t absoluteSwitch[] = {
|
||||||
PPC_INST_LIS,
|
PPC_INST_LIS,
|
||||||
PPC_INST_ADDI,
|
PPC_INST_ADDI,
|
||||||
PPC_INST_RLWINM,
|
PPC_INST_RLWINM,
|
||||||
@ -260,8 +259,7 @@ int main(int argc, char** argv)
|
|||||||
PPC_INST_BCTR,
|
PPC_INST_BCTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t computedSwitch[] =
|
uint32_t computedSwitch[] = {
|
||||||
{
|
|
||||||
PPC_INST_LIS,
|
PPC_INST_LIS,
|
||||||
PPC_INST_ADDI,
|
PPC_INST_ADDI,
|
||||||
PPC_INST_LBZX,
|
PPC_INST_LBZX,
|
||||||
@ -272,8 +270,7 @@ int main(int argc, char** argv)
|
|||||||
PPC_INST_MTCTR,
|
PPC_INST_MTCTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t offsetSwitch[] =
|
uint32_t offsetSwitch[] = {
|
||||||
{
|
|
||||||
PPC_INST_LIS,
|
PPC_INST_LIS,
|
||||||
PPC_INST_ADDI,
|
PPC_INST_ADDI,
|
||||||
PPC_INST_LBZX,
|
PPC_INST_LBZX,
|
||||||
@ -283,8 +280,7 @@ int main(int argc, char** argv)
|
|||||||
PPC_INST_MTCTR,
|
PPC_INST_MTCTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t wordOffsetSwitch[] =
|
uint32_t wordOffsetSwitch[] = {
|
||||||
{
|
|
||||||
PPC_INST_LIS,
|
PPC_INST_LIS,
|
||||||
PPC_INST_ADDI,
|
PPC_INST_ADDI,
|
||||||
PPC_INST_RLWINM,
|
PPC_INST_RLWINM,
|
||||||
|
@ -11,12 +11,12 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* path =
|
const char* path =
|
||||||
#ifdef XENON_RECOMP_CONFIG_FILE_PATH
|
#ifdef XENON_RECOMP_CONFIG_FILE_PATH
|
||||||
XENON_RECOMP_CONFIG_FILE_PATH
|
XENON_RECOMP_CONFIG_FILE_PATH
|
||||||
#else
|
#else
|
||||||
argv[1]
|
argv[1]
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
if (std::filesystem::is_regular_file(path))
|
if (std::filesystem::is_regular_file(path))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "recompiler.h"
|
#include "recompiler.h"
|
||||||
|
#include "pch.h"
|
||||||
#include <xex_patcher.h>
|
#include <xex_patcher.h>
|
||||||
|
|
||||||
static uint64_t ComputeMask(uint32_t mstart, uint32_t mstop)
|
static uint64_t ComputeMask(uint32_t mstart, uint32_t mstop)
|
||||||
@ -104,7 +104,7 @@ void Recompiler::Analyse()
|
|||||||
auto& restgpr = functions.emplace_back();
|
auto& restgpr = functions.emplace_back();
|
||||||
restgpr.base = config.restGpr14Address + (i - 14) * 4;
|
restgpr.base = config.restGpr14Address + (i - 14) * 4;
|
||||||
restgpr.size = (32 - i) * 4 + 12;
|
restgpr.size = (32 - i) * 4 + 12;
|
||||||
image.symbols.emplace(Symbol{ fmt::format("__restgprlr_{}", i), restgpr.base, restgpr.size, Symbol_Function });
|
image.symbols.emplace(Symbol { fmt::format("__restgprlr_{}", i), restgpr.base, restgpr.size, Symbol_Function });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.saveGpr14Address != 0)
|
if (config.saveGpr14Address != 0)
|
||||||
@ -251,7 +251,8 @@ void Recompiler::Analyse()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; });
|
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs)
|
||||||
|
{ return lhs.base < rhs.base; });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Recompiler::Recompile(
|
bool Recompiler::Recompile(
|
||||||
@ -267,251 +268,251 @@ bool Recompiler::Recompile(
|
|||||||
|
|
||||||
// TODO: we could cache these formats in an array
|
// TODO: we could cache these formats in an array
|
||||||
auto r = [&](size_t index)
|
auto r = [&](size_t index)
|
||||||
|
{
|
||||||
|
if ((config.nonArgumentRegistersAsLocalVariables && (index == 0 || index == 2 || index == 11 || index == 12)) ||
|
||||||
|
(config.nonVolatileRegistersAsLocalVariables && index >= 14))
|
||||||
{
|
{
|
||||||
if ((config.nonArgumentRegistersAsLocalVariables && (index == 0 || index == 2 || index == 11 || index == 12)) ||
|
localVariables.r[index] = true;
|
||||||
(config.nonVolatileRegistersAsLocalVariables && index >= 14))
|
return fmt::format("r{}", index);
|
||||||
{
|
}
|
||||||
localVariables.r[index] = true;
|
return fmt::format("ctx.r{}", index);
|
||||||
return fmt::format("r{}", index);
|
};
|
||||||
}
|
|
||||||
return fmt::format("ctx.r{}", index);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto f = [&](size_t index)
|
auto f = [&](size_t index)
|
||||||
|
{
|
||||||
|
if ((config.nonArgumentRegistersAsLocalVariables && index == 0) ||
|
||||||
|
(config.nonVolatileRegistersAsLocalVariables && index >= 14))
|
||||||
{
|
{
|
||||||
if ((config.nonArgumentRegistersAsLocalVariables && index == 0) ||
|
localVariables.f[index] = true;
|
||||||
(config.nonVolatileRegistersAsLocalVariables && index >= 14))
|
return fmt::format("f{}", index);
|
||||||
{
|
}
|
||||||
localVariables.f[index] = true;
|
return fmt::format("ctx.f{}", index);
|
||||||
return fmt::format("f{}", index);
|
};
|
||||||
}
|
|
||||||
return fmt::format("ctx.f{}", index);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto v = [&](size_t index)
|
auto v = [&](size_t index)
|
||||||
|
{
|
||||||
|
if ((config.nonArgumentRegistersAsLocalVariables && (index >= 32 && index <= 63)) ||
|
||||||
|
(config.nonVolatileRegistersAsLocalVariables && ((index >= 14 && index <= 31) || (index >= 64 && index <= 127))))
|
||||||
{
|
{
|
||||||
if ((config.nonArgumentRegistersAsLocalVariables && (index >= 32 && index <= 63)) ||
|
localVariables.v[index] = true;
|
||||||
(config.nonVolatileRegistersAsLocalVariables && ((index >= 14 && index <= 31) || (index >= 64 && index <= 127))))
|
return fmt::format("v{}", index);
|
||||||
{
|
}
|
||||||
localVariables.v[index] = true;
|
return fmt::format("ctx.v{}", index);
|
||||||
return fmt::format("v{}", index);
|
};
|
||||||
}
|
|
||||||
return fmt::format("ctx.v{}", index);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto cr = [&](size_t index)
|
auto cr = [&](size_t index)
|
||||||
|
{
|
||||||
|
if (config.crRegistersAsLocalVariables)
|
||||||
{
|
{
|
||||||
if (config.crRegistersAsLocalVariables)
|
localVariables.cr[index] = true;
|
||||||
{
|
return fmt::format("cr{}", index);
|
||||||
localVariables.cr[index] = true;
|
}
|
||||||
return fmt::format("cr{}", index);
|
return fmt::format("ctx.cr{}", index);
|
||||||
}
|
};
|
||||||
return fmt::format("ctx.cr{}", index);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto ctr = [&]()
|
auto ctr = [&]()
|
||||||
|
{
|
||||||
|
if (config.ctrAsLocalVariable)
|
||||||
{
|
{
|
||||||
if (config.ctrAsLocalVariable)
|
localVariables.ctr = true;
|
||||||
{
|
return "ctr";
|
||||||
localVariables.ctr = true;
|
}
|
||||||
return "ctr";
|
return "ctx.ctr";
|
||||||
}
|
};
|
||||||
return "ctx.ctr";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto xer = [&]()
|
auto xer = [&]()
|
||||||
|
{
|
||||||
|
if (config.xerAsLocalVariable)
|
||||||
{
|
{
|
||||||
if (config.xerAsLocalVariable)
|
localVariables.xer = true;
|
||||||
{
|
return "xer";
|
||||||
localVariables.xer = true;
|
}
|
||||||
return "xer";
|
return "ctx.xer";
|
||||||
}
|
};
|
||||||
return "ctx.xer";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto reserved = [&]()
|
auto reserved = [&]()
|
||||||
|
{
|
||||||
|
if (config.reservedRegisterAsLocalVariable)
|
||||||
{
|
{
|
||||||
if (config.reservedRegisterAsLocalVariable)
|
localVariables.reserved = true;
|
||||||
{
|
return "reserved";
|
||||||
localVariables.reserved = true;
|
}
|
||||||
return "reserved";
|
return "ctx.reserved";
|
||||||
}
|
};
|
||||||
return "ctx.reserved";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto temp = [&]()
|
auto temp = [&]()
|
||||||
{
|
{
|
||||||
localVariables.temp = true;
|
localVariables.temp = true;
|
||||||
return "temp";
|
return "temp";
|
||||||
};
|
};
|
||||||
|
|
||||||
auto vTemp = [&]()
|
auto vTemp = [&]()
|
||||||
{
|
{
|
||||||
localVariables.vTemp = true;
|
localVariables.vTemp = true;
|
||||||
return "vTemp";
|
return "vTemp";
|
||||||
};
|
};
|
||||||
|
|
||||||
auto env = [&]()
|
auto env = [&]()
|
||||||
{
|
{
|
||||||
localVariables.env = true;
|
localVariables.env = true;
|
||||||
return "env";
|
return "env";
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ea = [&]()
|
auto ea = [&]()
|
||||||
{
|
{
|
||||||
localVariables.ea = true;
|
localVariables.ea = true;
|
||||||
return "ea";
|
return "ea";
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO (Sajid): Check for out of bounds access
|
// TODO (Sajid): Check for out of bounds access
|
||||||
auto mmioStore = [&]() -> bool
|
auto mmioStore = [&]() -> bool
|
||||||
{
|
{
|
||||||
return *(data + 1) == c_eieio;
|
return *(data + 1) == c_eieio;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto printFunctionCall = [&](uint32_t address)
|
auto printFunctionCall = [&](uint32_t address)
|
||||||
|
{
|
||||||
|
if (address == config.longJmpAddress)
|
||||||
{
|
{
|
||||||
if (address == config.longJmpAddress)
|
println("\tlongjmp(*reinterpret_cast<jmp_buf*>(base + {}.u32), {}.s32);", r(3), r(4));
|
||||||
{
|
}
|
||||||
println("\tlongjmp(*reinterpret_cast<jmp_buf*>(base + {}.u32), {}.s32);", r(3), r(4));
|
else if (address == config.setJmpAddress)
|
||||||
}
|
{
|
||||||
else if (address == config.setJmpAddress)
|
println("\t{} = ctx;", env());
|
||||||
{
|
println("\t{}.s64 = setjmp(*reinterpret_cast<jmp_buf*>(base + {}.u32));", r(3), r(3));
|
||||||
println("\t{} = ctx;", env());
|
println("\tif ({}.s64 != 0) ctx = {};", r(3), env());
|
||||||
println("\t{}.s64 = setjmp(*reinterpret_cast<jmp_buf*>(base + {}.u32));", r(3), r(3));
|
}
|
||||||
println("\tif ({}.s64 != 0) ctx = {};", r(3), env());
|
else
|
||||||
}
|
{
|
||||||
else
|
auto targetSymbol = image.symbols.find(address);
|
||||||
{
|
|
||||||
auto targetSymbol = image.symbols.find(address);
|
|
||||||
|
|
||||||
if (targetSymbol != image.symbols.end() && targetSymbol->address == address && targetSymbol->type == Symbol_Function)
|
if (targetSymbol != image.symbols.end() && targetSymbol->address == address && targetSymbol->type == Symbol_Function)
|
||||||
|
{
|
||||||
|
if (config.nonVolatileRegistersAsLocalVariables && (targetSymbol->name.find("__rest") == 0 || targetSymbol->name.find("__save") == 0))
|
||||||
{
|
{
|
||||||
if (config.nonVolatileRegistersAsLocalVariables && (targetSymbol->name.find("__rest") == 0 || targetSymbol->name.find("__save") == 0))
|
// print nothing
|
||||||
{
|
|
||||||
// print nothing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
println("\t{}(ctx, base);", targetSymbol->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
println("\t// ERROR {:X}", address);
|
println("\t{}(ctx, base);", targetSymbol->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
auto printConditionalBranch = [&](bool not_, const std::string_view& cond)
|
|
||||||
{
|
|
||||||
if (insn.operands[1] < fn.base || insn.operands[1] >= fn.base + fn.size)
|
|
||||||
{
|
|
||||||
println("\tif ({}{}.{}) {{", not_ ? "!" : "", cr(insn.operands[0]), cond);
|
|
||||||
print("\t");
|
|
||||||
printFunctionCall(insn.operands[1]);
|
|
||||||
println("\t\treturn;");
|
|
||||||
println("\t}}");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
println("\tif ({}{}.{}) goto loc_{:X};", not_ ? "!" : "", cr(insn.operands[0]), cond, insn.operands[1]);
|
println("\t// ERROR {:X}", address);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto printConditionalBranch = [&](bool not_, const std::string_view& cond)
|
||||||
|
{
|
||||||
|
if (insn.operands[1] < fn.base || insn.operands[1] >= fn.base + fn.size)
|
||||||
|
{
|
||||||
|
println("\tif ({}{}.{}) {{", not_ ? "!" : "", cr(insn.operands[0]), cond);
|
||||||
|
print("\t");
|
||||||
|
printFunctionCall(insn.operands[1]);
|
||||||
|
println("\t\treturn;");
|
||||||
|
println("\t}}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("\tif ({}{}.{}) goto loc_{:X};", not_ ? "!" : "", cr(insn.operands[0]), cond, insn.operands[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto printSetFlushMode = [&](bool enable)
|
auto printSetFlushMode = [&](bool enable)
|
||||||
|
{
|
||||||
|
auto newState = enable ? CSRState::VMX : CSRState::FPU;
|
||||||
|
if (csrState != newState)
|
||||||
{
|
{
|
||||||
auto newState = enable ? CSRState::VMX : CSRState::FPU;
|
auto prefix = enable ? "enable" : "disable";
|
||||||
if (csrState != newState)
|
auto suffix = csrState != CSRState::Unknown ? "Unconditional" : "";
|
||||||
{
|
println("\tctx.fpscr.{}FlushMode{}();", prefix, suffix);
|
||||||
auto prefix = enable ? "enable" : "disable";
|
|
||||||
auto suffix = csrState != CSRState::Unknown ? "Unconditional" : "";
|
|
||||||
println("\tctx.fpscr.{}FlushMode{}();", prefix, suffix);
|
|
||||||
|
|
||||||
csrState = newState;
|
csrState = newState;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto midAsmHook = config.midAsmHooks.find(base);
|
auto midAsmHook = config.midAsmHooks.find(base);
|
||||||
|
|
||||||
auto printMidAsmHook = [&]()
|
auto printMidAsmHook = [&]()
|
||||||
|
{
|
||||||
|
bool returnsBool = midAsmHook->second.returnOnFalse || midAsmHook->second.returnOnTrue ||
|
||||||
|
midAsmHook->second.jumpAddressOnFalse != NULL || midAsmHook->second.jumpAddressOnTrue != NULL;
|
||||||
|
|
||||||
|
print("\t");
|
||||||
|
if (returnsBool)
|
||||||
|
print("if (");
|
||||||
|
|
||||||
|
print("{}(", midAsmHook->second.name);
|
||||||
|
for (auto& reg : midAsmHook->second.registers)
|
||||||
{
|
{
|
||||||
bool returnsBool = midAsmHook->second.returnOnFalse || midAsmHook->second.returnOnTrue ||
|
if (out.back() != '(')
|
||||||
midAsmHook->second.jumpAddressOnFalse != NULL || midAsmHook->second.jumpAddressOnTrue != NULL;
|
out += ", ";
|
||||||
|
|
||||||
print("\t");
|
switch (reg[0])
|
||||||
if (returnsBool)
|
|
||||||
print("if (");
|
|
||||||
|
|
||||||
print("{}(", midAsmHook->second.name);
|
|
||||||
for (auto& reg : midAsmHook->second.registers)
|
|
||||||
{
|
{
|
||||||
if (out.back() != '(')
|
case 'c':
|
||||||
out += ", ";
|
if (reg == "ctr")
|
||||||
|
out += ctr();
|
||||||
|
else
|
||||||
|
out += cr(std::atoi(reg.c_str() + 2));
|
||||||
|
break;
|
||||||
|
|
||||||
switch (reg[0])
|
case 'x':
|
||||||
{
|
out += xer();
|
||||||
case 'c':
|
break;
|
||||||
if (reg == "ctr")
|
|
||||||
out += ctr();
|
|
||||||
else
|
|
||||||
out += cr(std::atoi(reg.c_str() + 2));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'x':
|
case 'r':
|
||||||
out += xer();
|
if (reg == "reserved")
|
||||||
break;
|
out += reserved();
|
||||||
|
else
|
||||||
|
out += r(std::atoi(reg.c_str() + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'f':
|
||||||
if (reg == "reserved")
|
if (reg == "fpscr")
|
||||||
out += reserved();
|
out += "ctx.fpscr";
|
||||||
else
|
else
|
||||||
out += r(std::atoi(reg.c_str() + 1));
|
out += f(std::atoi(reg.c_str() + 1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'v':
|
||||||
if (reg == "fpscr")
|
out += v(std::atoi(reg.c_str() + 1));
|
||||||
out += "ctx.fpscr";
|
break;
|
||||||
else
|
|
||||||
out += f(std::atoi(reg.c_str() + 1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'v':
|
|
||||||
out += v(std::atoi(reg.c_str() + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (returnsBool)
|
if (returnsBool)
|
||||||
{
|
{
|
||||||
println(")) {{");
|
println(")) {{");
|
||||||
|
|
||||||
if (midAsmHook->second.returnOnTrue)
|
if (midAsmHook->second.returnOnTrue)
|
||||||
println("\t\treturn;");
|
println("\t\treturn;");
|
||||||
else if (midAsmHook->second.jumpAddressOnTrue != NULL)
|
else if (midAsmHook->second.jumpAddressOnTrue != NULL)
|
||||||
println("\t\tgoto loc_{:X};", midAsmHook->second.jumpAddressOnTrue);
|
println("\t\tgoto loc_{:X};", midAsmHook->second.jumpAddressOnTrue);
|
||||||
|
|
||||||
println("\t}}");
|
println("\t}}");
|
||||||
|
|
||||||
println("\telse {{");
|
println("\telse {{");
|
||||||
|
|
||||||
if (midAsmHook->second.returnOnFalse)
|
if (midAsmHook->second.returnOnFalse)
|
||||||
println("\t\treturn;");
|
println("\t\treturn;");
|
||||||
else if (midAsmHook->second.jumpAddressOnFalse != NULL)
|
else if (midAsmHook->second.jumpAddressOnFalse != NULL)
|
||||||
println("\t\tgoto loc_{:X};", midAsmHook->second.jumpAddressOnFalse);
|
println("\t\tgoto loc_{:X};", midAsmHook->second.jumpAddressOnFalse);
|
||||||
|
|
||||||
println("\t}}");
|
println("\t}}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
println(");");
|
println(");");
|
||||||
|
|
||||||
if (midAsmHook->second.ret)
|
if (midAsmHook->second.ret)
|
||||||
println("\treturn;");
|
println("\treturn;");
|
||||||
else if (midAsmHook->second.jumpAddress != NULL)
|
else if (midAsmHook->second.jumpAddress != NULL)
|
||||||
println("\tgoto loc_{:X};", midAsmHook->second.jumpAddress);
|
println("\tgoto loc_{:X};", midAsmHook->second.jumpAddress);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (midAsmHook != config.midAsmHooks.end() && !midAsmHook->second.afterInstruction)
|
if (midAsmHook != config.midAsmHooks.end() && !midAsmHook->second.afterInstruction)
|
||||||
printMidAsmHook();
|
printMidAsmHook();
|
||||||
@ -519,8 +520,10 @@ bool Recompiler::Recompile(
|
|||||||
int id = insn.opcode->id;
|
int id = insn.opcode->id;
|
||||||
|
|
||||||
// Handling instructions that don't disassemble correctly for some reason here
|
// Handling instructions that don't disassemble correctly for some reason here
|
||||||
if (id == PPC_INST_VUPKHSB128 && insn.operands[2] == 0x60) id = PPC_INST_VUPKHSH128;
|
if (id == PPC_INST_VUPKHSB128 && insn.operands[2] == 0x60)
|
||||||
else if (id == PPC_INST_VUPKLSB128 && insn.operands[2] == 0x60) id = PPC_INST_VUPKLSH128;
|
id = PPC_INST_VUPKHSH128;
|
||||||
|
else if (id == PPC_INST_VUPKLSB128 && insn.operands[2] == 0x60)
|
||||||
|
id = PPC_INST_VUPKLSH128;
|
||||||
|
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
@ -2255,7 +2258,7 @@ bool Recompiler::Recompile(
|
|||||||
|
|
||||||
if (midAsmHook != config.midAsmHooks.end() && midAsmHook->second.afterInstruction)
|
if (midAsmHook != config.midAsmHooks.end() && midAsmHook->second.afterInstruction)
|
||||||
printMidAsmHook();
|
printMidAsmHook();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2339,9 +2342,9 @@ bool Recompiler::Recompile(const Function& fn)
|
|||||||
println(");\n");
|
println(");\n");
|
||||||
|
|
||||||
if (midAsmHook->second.jumpAddress != NULL)
|
if (midAsmHook->second.jumpAddress != NULL)
|
||||||
labels.emplace(midAsmHook->second.jumpAddress);
|
labels.emplace(midAsmHook->second.jumpAddress);
|
||||||
if (midAsmHook->second.jumpAddressOnTrue != NULL)
|
if (midAsmHook->second.jumpAddressOnTrue != NULL)
|
||||||
labels.emplace(midAsmHook->second.jumpAddressOnTrue);
|
labels.emplace(midAsmHook->second.jumpAddressOnTrue);
|
||||||
if (midAsmHook->second.jumpAddressOnFalse != NULL)
|
if (midAsmHook->second.jumpAddressOnFalse != NULL)
|
||||||
labels.emplace(midAsmHook->second.jumpAddressOnFalse);
|
labels.emplace(midAsmHook->second.jumpAddressOnFalse);
|
||||||
}
|
}
|
||||||
@ -2430,7 +2433,7 @@ bool Recompiler::Recompile(const Function& fn)
|
|||||||
|
|
||||||
std::swap(out, tempString);
|
std::swap(out, tempString);
|
||||||
if (localVariables.ctr)
|
if (localVariables.ctr)
|
||||||
println("\tPPCRegister ctr{{}};");
|
println("\tPPCRegister ctr{{}};");
|
||||||
if (localVariables.xer)
|
if (localVariables.xer)
|
||||||
println("\tPPCXERRegister xer{{}};");
|
println("\tPPCXERRegister xer{{}};");
|
||||||
if (localVariables.reserved)
|
if (localVariables.reserved)
|
||||||
@ -2461,11 +2464,11 @@ bool Recompiler::Recompile(const Function& fn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (localVariables.env)
|
if (localVariables.env)
|
||||||
println("\tPPCContext env{{}};");
|
println("\tPPCContext env{{}};");
|
||||||
|
|
||||||
if (localVariables.temp)
|
if (localVariables.temp)
|
||||||
println("\tPPCRegister temp{{}};");
|
println("\tPPCRegister temp{{}};");
|
||||||
|
|
||||||
if (localVariables.vTemp)
|
if (localVariables.vTemp)
|
||||||
println("\tPPCVRegister vTemp{{}};");
|
println("\tPPCVRegister vTemp{{}};");
|
||||||
|
|
||||||
@ -2488,19 +2491,19 @@ void Recompiler::Recompile(const std::filesystem::path& headerFilePath)
|
|||||||
println("#define PPC_CONFIG_H_INCLUDED\n");
|
println("#define PPC_CONFIG_H_INCLUDED\n");
|
||||||
|
|
||||||
if (config.skipLr)
|
if (config.skipLr)
|
||||||
println("#define PPC_CONFIG_SKIP_LR");
|
println("#define PPC_CONFIG_SKIP_LR");
|
||||||
if (config.ctrAsLocalVariable)
|
if (config.ctrAsLocalVariable)
|
||||||
println("#define PPC_CONFIG_CTR_AS_LOCAL");
|
println("#define PPC_CONFIG_CTR_AS_LOCAL");
|
||||||
if (config.xerAsLocalVariable)
|
if (config.xerAsLocalVariable)
|
||||||
println("#define PPC_CONFIG_XER_AS_LOCAL");
|
println("#define PPC_CONFIG_XER_AS_LOCAL");
|
||||||
if (config.reservedRegisterAsLocalVariable)
|
if (config.reservedRegisterAsLocalVariable)
|
||||||
println("#define PPC_CONFIG_RESERVED_AS_LOCAL");
|
println("#define PPC_CONFIG_RESERVED_AS_LOCAL");
|
||||||
if (config.skipMsr)
|
if (config.skipMsr)
|
||||||
println("#define PPC_CONFIG_SKIP_MSR");
|
println("#define PPC_CONFIG_SKIP_MSR");
|
||||||
if (config.crRegistersAsLocalVariables)
|
if (config.crRegistersAsLocalVariables)
|
||||||
println("#define PPC_CONFIG_CR_AS_LOCAL");
|
println("#define PPC_CONFIG_CR_AS_LOCAL");
|
||||||
if (config.nonArgumentRegistersAsLocalVariables)
|
if (config.nonArgumentRegistersAsLocalVariables)
|
||||||
println("#define PPC_CONFIG_NON_ARGUMENT_AS_LOCAL");
|
println("#define PPC_CONFIG_NON_ARGUMENT_AS_LOCAL");
|
||||||
if (config.nonVolatileRegistersAsLocalVariables)
|
if (config.nonVolatileRegistersAsLocalVariables)
|
||||||
println("#define PPC_CONFIG_NON_VOLATILE_AS_LOCAL");
|
println("#define PPC_CONFIG_NON_VOLATILE_AS_LOCAL");
|
||||||
|
|
||||||
@ -2508,7 +2511,7 @@ void Recompiler::Recompile(const std::filesystem::path& headerFilePath)
|
|||||||
|
|
||||||
println("#define PPC_IMAGE_BASE 0x{:X}ull", image.base);
|
println("#define PPC_IMAGE_BASE 0x{:X}ull", image.base);
|
||||||
println("#define PPC_IMAGE_SIZE 0x{:X}ull", image.size);
|
println("#define PPC_IMAGE_SIZE 0x{:X}ull", image.size);
|
||||||
|
|
||||||
// Extract the address of the minimum code segment to store the function table at.
|
// Extract the address of the minimum code segment to store the function table at.
|
||||||
size_t codeMin = ~0;
|
size_t codeMin = ~0;
|
||||||
size_t codeMax = 0;
|
size_t codeMax = 0;
|
||||||
@ -2543,7 +2546,7 @@ void Recompiler::Recompile(const std::filesystem::path& headerFilePath)
|
|||||||
println("#pragma once");
|
println("#pragma once");
|
||||||
|
|
||||||
println("#include \"ppc_config.h\"\n");
|
println("#include \"ppc_config.h\"\n");
|
||||||
|
|
||||||
std::ifstream stream(headerFilePath);
|
std::ifstream stream(headerFilePath);
|
||||||
if (stream.good())
|
if (stream.good())
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@ void RecompilerConfig::Load(const std::string_view& configFilePath)
|
|||||||
directoryPath = configFilePath.substr(0, configFilePath.find_last_of("\\/") + 1);
|
directoryPath = configFilePath.substr(0, configFilePath.find_last_of("\\/") + 1);
|
||||||
toml::table toml = toml::parse_file(configFilePath)
|
toml::table toml = toml::parse_file(configFilePath)
|
||||||
#if !TOML_EXCEPTIONS
|
#if !TOML_EXCEPTIONS
|
||||||
.table()
|
.table()
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -38,14 +38,22 @@ void RecompilerConfig::Load(const std::string_view& configFilePath)
|
|||||||
longJmpAddress = main["longjmp_address"].value_or(0u);
|
longJmpAddress = main["longjmp_address"].value_or(0u);
|
||||||
setJmpAddress = main["setjmp_address"].value_or(0u);
|
setJmpAddress = main["setjmp_address"].value_or(0u);
|
||||||
|
|
||||||
if (restGpr14Address == 0) fmt::println("ERROR: __restgprlr_14 address is unspecified");
|
if (restGpr14Address == 0)
|
||||||
if (saveGpr14Address == 0) fmt::println("ERROR: __savegprlr_14 address is unspecified");
|
fmt::println("ERROR: __restgprlr_14 address is unspecified");
|
||||||
if (restFpr14Address == 0) fmt::println("ERROR: __restfpr_14 address is unspecified");
|
if (saveGpr14Address == 0)
|
||||||
if (saveFpr14Address == 0) fmt::println("ERROR: __savefpr_14 address is unspecified");
|
fmt::println("ERROR: __savegprlr_14 address is unspecified");
|
||||||
if (restVmx14Address == 0) fmt::println("ERROR: __restvmx_14 address is unspecified");
|
if (restFpr14Address == 0)
|
||||||
if (saveVmx14Address == 0) fmt::println("ERROR: __savevmx_14 address is unspecified");
|
fmt::println("ERROR: __restfpr_14 address is unspecified");
|
||||||
if (restVmx64Address == 0) fmt::println("ERROR: __restvmx_64 address is unspecified");
|
if (saveFpr14Address == 0)
|
||||||
if (saveVmx64Address == 0) fmt::println("ERROR: __savevmx_64 address is unspecified");
|
fmt::println("ERROR: __savefpr_14 address is unspecified");
|
||||||
|
if (restVmx14Address == 0)
|
||||||
|
fmt::println("ERROR: __restvmx_14 address is unspecified");
|
||||||
|
if (saveVmx14Address == 0)
|
||||||
|
fmt::println("ERROR: __savevmx_14 address is unspecified");
|
||||||
|
if (restVmx64Address == 0)
|
||||||
|
fmt::println("ERROR: __restvmx_64 address is unspecified");
|
||||||
|
if (saveVmx64Address == 0)
|
||||||
|
fmt::println("ERROR: __savevmx_64 address is unspecified");
|
||||||
|
|
||||||
if (auto functionsArray = main["functions"].as_array())
|
if (auto functionsArray = main["functions"].as_array())
|
||||||
{
|
{
|
||||||
@ -73,7 +81,7 @@ void RecompilerConfig::Load(const std::string_view& configFilePath)
|
|||||||
{
|
{
|
||||||
toml::table switchToml = toml::parse_file(directoryPath + switchTableFilePath)
|
toml::table switchToml = toml::parse_file(directoryPath + switchTableFilePath)
|
||||||
#if !TOML_EXCEPTIONS
|
#if !TOML_EXCEPTIONS
|
||||||
.table()
|
.table()
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
if (auto switchArray = switchToml["switch"].as_array())
|
if (auto switchArray = switchToml["switch"].as_array())
|
||||||
|
@ -23,13 +23,14 @@ void TestRecompiler::Analyse(const std::string_view& testName)
|
|||||||
|
|
||||||
auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base));
|
auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base));
|
||||||
image.symbols.emplace(fmt::format("{}_{:X}", testName, fn.base), fn.base, fn.size, Symbol_Function);
|
image.symbols.emplace(fmt::format("{}_{:X}", testName, fn.base), fn.base, fn.size, Symbol_Function);
|
||||||
|
|
||||||
base += fn.size;
|
base += fn.size;
|
||||||
data += fn.size;
|
data += fn.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; });
|
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs)
|
||||||
|
{ return lhs.base < rhs.base; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* dstDirectoryPath)
|
void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* dstDirectoryPath)
|
||||||
@ -118,15 +119,15 @@ void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* ds
|
|||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
auto getline = [&]()
|
auto getline = [&]()
|
||||||
|
{
|
||||||
|
if (std::getline(in, str))
|
||||||
{
|
{
|
||||||
if (std::getline(in, str))
|
str.erase(str.find_last_not_of(' ') + 1);
|
||||||
{
|
str.erase(0, str.find_first_not_of(' '));
|
||||||
str.erase(str.find_last_not_of(' ') + 1);
|
return true;
|
||||||
str.erase(0, str.find_first_not_of(' '));
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
};
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
while (getline())
|
while (getline())
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "disasm.h"
|
#include "disasm.h"
|
||||||
|
|
||||||
thread_local ppc::DisassemblerEngine ppc::gBigEndianDisassembler{ BFD_ENDIAN_BIG, "cell 64"};
|
thread_local ppc::DisassemblerEngine ppc::gBigEndianDisassembler { BFD_ENDIAN_BIG, "cell 64" };
|
||||||
|
|
||||||
ppc::DisassemblerEngine::DisassemblerEngine(bfd_endian endian, const char* options)
|
ppc::DisassemblerEngine::DisassemblerEngine(bfd_endian endian, const char* options)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ Image ElfLoadImage(const uint8_t* data, size_t size)
|
|||||||
const auto* header = (elf32_hdr*)data;
|
const auto* header = (elf32_hdr*)data;
|
||||||
assert(header->e_ident[EI_DATA] == 2);
|
assert(header->e_ident[EI_DATA] == 2);
|
||||||
|
|
||||||
Image image{};
|
Image image {};
|
||||||
image.size = size;
|
image.size = size;
|
||||||
image.data = std::make_unique<uint8_t[]>(size);
|
image.data = std::make_unique<uint8_t[]>(size);
|
||||||
image.entry_point = ByteSwap(header->e_entry);
|
image.entry_point = ByteSwap(header->e_entry);
|
||||||
@ -81,7 +81,7 @@ Image ElfLoadImage(const uint8_t* data, size_t size)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flags{};
|
uint8_t flags {};
|
||||||
|
|
||||||
if (section.sh_flags & ByteSwap(SHF_EXECINSTR))
|
if (section.sh_flags & ByteSwap(SHF_EXECINSTR))
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#include "memory_mapped_file.h"
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
# include <cstring>
|
#include <cstdio>
|
||||||
# include <cstdio>
|
#include <cstring>
|
||||||
# include <fcntl.h>
|
#include <fcntl.h>
|
||||||
# include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MemoryMappedFile::MemoryMappedFile()
|
MemoryMappedFile::MemoryMappedFile()
|
||||||
@ -12,7 +12,7 @@ MemoryMappedFile::MemoryMappedFile()
|
|||||||
// Default constructor.
|
// Default constructor.
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryMappedFile::MemoryMappedFile(const std::filesystem::path &path)
|
MemoryMappedFile::MemoryMappedFile(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
open(path);
|
open(path);
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ MemoryMappedFile::~MemoryMappedFile()
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other)
|
MemoryMappedFile::MemoryMappedFile(MemoryMappedFile&& other)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
fileHandle = other.fileHandle;
|
fileHandle = other.fileHandle;
|
||||||
@ -45,7 +45,7 @@ MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryMappedFile::open(const std::filesystem::path &path)
|
bool MemoryMappedFile::open(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
fileHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
fileHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
@ -154,9 +154,9 @@ bool MemoryMappedFile::isOpen() const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *MemoryMappedFile::data() const
|
uint8_t* MemoryMappedFile::data() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<uint8_t *>(fileView);
|
return reinterpret_cast<uint8_t*>(fileView);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MemoryMappedFile::size() const
|
size_t MemoryMappedFile::size() const
|
||||||
|
@ -36,7 +36,7 @@ XDBFBlock XDBFWrapper::GetResource(EXDBFNamespace ns, uint64_t id) const
|
|||||||
|
|
||||||
if (entry.NamespaceID == ns && entry.ResourceID == id)
|
if (entry.NamespaceID == ns && entry.ResourceID == id)
|
||||||
{
|
{
|
||||||
XDBFBlock block{};
|
XDBFBlock block {};
|
||||||
block.pBuffer = pContent + entry.Offset;
|
block.pBuffer = pContent + entry.Offset;
|
||||||
block.BufferSize = entry.Length;
|
block.BufferSize = entry.Length;
|
||||||
return block;
|
return block;
|
||||||
@ -89,7 +89,7 @@ std::vector<Achievement> XDBFWrapper::GetAchievements(EXDBFLanguage language) co
|
|||||||
|
|
||||||
seek += sizeof(XACHEntry);
|
seek += sizeof(XACHEntry);
|
||||||
|
|
||||||
Achievement achievement{};
|
Achievement achievement {};
|
||||||
achievement.ID = entry->AchievementID;
|
achievement.ID = entry->AchievementID;
|
||||||
achievement.Name = GetString(language, entry->NameID);
|
achievement.Name = GetString(language, entry->NameID);
|
||||||
achievement.UnlockedDesc = GetString(language, entry->UnlockedDescID);
|
achievement.UnlockedDesc = GetString(language, entry->UnlockedDescID);
|
||||||
@ -112,7 +112,7 @@ std::vector<Achievement> XDBFWrapper::GetAchievements(EXDBFLanguage language) co
|
|||||||
|
|
||||||
Achievement XDBFWrapper::GetAchievement(EXDBFLanguage language, uint16_t id) const
|
Achievement XDBFWrapper::GetAchievement(EXDBFLanguage language, uint16_t id) const
|
||||||
{
|
{
|
||||||
Achievement result{};
|
Achievement result {};
|
||||||
|
|
||||||
auto achievementsBlock = GetResource(XDBF_SPA_NAMESPACE_METADATA, 0x58414348);
|
auto achievementsBlock = GetResource(XDBF_SPA_NAMESPACE_METADATA, 0x58414348);
|
||||||
|
|
||||||
|
@ -1,125 +1,130 @@
|
|||||||
#include "xex.h"
|
#include "xex.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
#include <aes.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <aes.hpp>
|
#include <vector>
|
||||||
|
|
||||||
#define STRINGIFY(X) #X
|
#define STRINGIFY(X) #X
|
||||||
#define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) }
|
#define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) }
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
typedef struct _IMAGE_DOS_HEADER {
|
typedef struct _IMAGE_DOS_HEADER
|
||||||
uint16_t e_magic;
|
{
|
||||||
uint16_t e_cblp;
|
uint16_t e_magic;
|
||||||
uint16_t e_cp;
|
uint16_t e_cblp;
|
||||||
uint16_t e_crlc;
|
uint16_t e_cp;
|
||||||
uint16_t e_cparhdr;
|
uint16_t e_crlc;
|
||||||
uint16_t e_minalloc;
|
uint16_t e_cparhdr;
|
||||||
uint16_t e_maxalloc;
|
uint16_t e_minalloc;
|
||||||
uint16_t e_ss;
|
uint16_t e_maxalloc;
|
||||||
uint16_t e_sp;
|
uint16_t e_ss;
|
||||||
uint16_t e_csum;
|
uint16_t e_sp;
|
||||||
uint16_t e_ip;
|
uint16_t e_csum;
|
||||||
uint16_t e_cs;
|
uint16_t e_ip;
|
||||||
uint16_t e_lfarlc;
|
uint16_t e_cs;
|
||||||
uint16_t e_ovno;
|
uint16_t e_lfarlc;
|
||||||
uint16_t e_res[4];
|
uint16_t e_ovno;
|
||||||
uint16_t e_oemid;
|
uint16_t e_res[4];
|
||||||
uint16_t e_oeminfo;
|
uint16_t e_oemid;
|
||||||
uint16_t e_res2[10];
|
uint16_t e_oeminfo;
|
||||||
uint32_t e_lfanew;
|
uint16_t e_res2[10];
|
||||||
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER;
|
uint32_t e_lfanew;
|
||||||
|
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
|
||||||
|
|
||||||
typedef struct _IMAGE_FILE_HEADER {
|
typedef struct _IMAGE_FILE_HEADER
|
||||||
uint16_t Machine;
|
{
|
||||||
uint16_t NumberOfSections;
|
uint16_t Machine;
|
||||||
uint32_t TimeDateStamp;
|
uint16_t NumberOfSections;
|
||||||
uint32_t PointerToSymbolTable;
|
uint32_t TimeDateStamp;
|
||||||
uint32_t NumberOfSymbols;
|
uint32_t PointerToSymbolTable;
|
||||||
uint16_t SizeOfOptionalHeader;
|
uint32_t NumberOfSymbols;
|
||||||
uint16_t Characteristics;
|
uint16_t SizeOfOptionalHeader;
|
||||||
} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER;
|
uint16_t Characteristics;
|
||||||
|
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
|
||||||
|
|
||||||
typedef struct _IMAGE_DATA_DIRECTORY {
|
typedef struct _IMAGE_DATA_DIRECTORY
|
||||||
uint32_t VirtualAddress;
|
{
|
||||||
uint32_t Size;
|
uint32_t VirtualAddress;
|
||||||
} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY;
|
uint32_t Size;
|
||||||
|
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
|
||||||
|
|
||||||
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
||||||
|
|
||||||
typedef struct _IMAGE_OPTIONAL_HEADER {
|
typedef struct _IMAGE_OPTIONAL_HEADER
|
||||||
uint16_t Magic;
|
{
|
||||||
uint8_t MajorLinkerVersion;
|
uint16_t Magic;
|
||||||
uint8_t MinorLinkerVersion;
|
uint8_t MajorLinkerVersion;
|
||||||
uint32_t SizeOfCode;
|
uint8_t MinorLinkerVersion;
|
||||||
uint32_t SizeOfInitializedData;
|
uint32_t SizeOfCode;
|
||||||
uint32_t SizeOfUninitializedData;
|
uint32_t SizeOfInitializedData;
|
||||||
uint32_t AddressOfEntryPoint;
|
uint32_t SizeOfUninitializedData;
|
||||||
uint32_t BaseOfCode;
|
uint32_t AddressOfEntryPoint;
|
||||||
uint32_t BaseOfData;
|
uint32_t BaseOfCode;
|
||||||
uint32_t ImageBase;
|
uint32_t BaseOfData;
|
||||||
uint32_t SectionAlignment;
|
uint32_t ImageBase;
|
||||||
uint32_t FileAlignment;
|
uint32_t SectionAlignment;
|
||||||
uint16_t MajorOperatingSystemVersion;
|
uint32_t FileAlignment;
|
||||||
uint16_t MinorOperatingSystemVersion;
|
uint16_t MajorOperatingSystemVersion;
|
||||||
uint16_t MajorImageVersion;
|
uint16_t MinorOperatingSystemVersion;
|
||||||
uint16_t MinorImageVersion;
|
uint16_t MajorImageVersion;
|
||||||
uint16_t MajorSubsystemVersion;
|
uint16_t MinorImageVersion;
|
||||||
uint16_t MinorSubsystemVersion;
|
uint16_t MajorSubsystemVersion;
|
||||||
uint32_t Win32VersionValue;
|
uint16_t MinorSubsystemVersion;
|
||||||
uint32_t SizeOfImage;
|
uint32_t Win32VersionValue;
|
||||||
uint32_t SizeOfHeaders;
|
uint32_t SizeOfImage;
|
||||||
uint32_t CheckSum;
|
uint32_t SizeOfHeaders;
|
||||||
uint16_t Subsystem;
|
uint32_t CheckSum;
|
||||||
uint16_t DllCharacteristics;
|
uint16_t Subsystem;
|
||||||
uint32_t SizeOfStackReserve;
|
uint16_t DllCharacteristics;
|
||||||
uint32_t SizeOfStackCommit;
|
uint32_t SizeOfStackReserve;
|
||||||
uint32_t SizeOfHeapReserve;
|
uint32_t SizeOfStackCommit;
|
||||||
uint32_t SizeOfHeapCommit;
|
uint32_t SizeOfHeapReserve;
|
||||||
uint32_t LoaderFlags;
|
uint32_t SizeOfHeapCommit;
|
||||||
uint32_t NumberOfRvaAndSizes;
|
uint32_t LoaderFlags;
|
||||||
|
uint32_t NumberOfRvaAndSizes;
|
||||||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
||||||
} IMAGE_OPTIONAL_HEADER32, * PIMAGE_OPTIONAL_HEADER32;
|
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
|
||||||
|
|
||||||
typedef struct _IMAGE_NT_HEADERS {
|
typedef struct _IMAGE_NT_HEADERS
|
||||||
|
{
|
||||||
uint32_t Signature;
|
uint32_t Signature;
|
||||||
IMAGE_FILE_HEADER FileHeader;
|
IMAGE_FILE_HEADER FileHeader;
|
||||||
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
||||||
} IMAGE_NT_HEADERS32, * PIMAGE_NT_HEADERS32;
|
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
|
||||||
|
|
||||||
#define IMAGE_SIZEOF_SHORT_NAME 8
|
#define IMAGE_SIZEOF_SHORT_NAME 8
|
||||||
|
|
||||||
typedef struct _IMAGE_SECTION_HEADER {
|
typedef struct _IMAGE_SECTION_HEADER
|
||||||
uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
|
{
|
||||||
union {
|
uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
|
||||||
uint32_t PhysicalAddress;
|
union
|
||||||
uint32_t VirtualSize;
|
{
|
||||||
|
uint32_t PhysicalAddress;
|
||||||
|
uint32_t VirtualSize;
|
||||||
} Misc;
|
} Misc;
|
||||||
uint32_t VirtualAddress;
|
uint32_t VirtualAddress;
|
||||||
uint32_t SizeOfRawData;
|
uint32_t SizeOfRawData;
|
||||||
uint32_t PointerToRawData;
|
uint32_t PointerToRawData;
|
||||||
uint32_t PointerToRelocations;
|
uint32_t PointerToRelocations;
|
||||||
uint32_t PointerToLinenumbers;
|
uint32_t PointerToLinenumbers;
|
||||||
uint16_t NumberOfRelocations;
|
uint16_t NumberOfRelocations;
|
||||||
uint16_t NumberOfLinenumbers;
|
uint16_t NumberOfLinenumbers;
|
||||||
uint32_t Characteristics;
|
uint32_t Characteristics;
|
||||||
} IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER;
|
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
|
||||||
|
|
||||||
#define IMAGE_SCN_CNT_CODE 0x00000020
|
#define IMAGE_SCN_CNT_CODE 0x00000020
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::unordered_map<size_t, const char*> XamExports =
|
std::unordered_map<size_t, const char*> XamExports = {
|
||||||
{
|
#include "xbox/xam_table.inc"
|
||||||
#include "xbox/xam_table.inc"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<size_t, const char*> XboxKernelExports =
|
std::unordered_map<size_t, const char*> XboxKernelExports = {
|
||||||
{
|
#include "xbox/xboxkrnl_table.inc"
|
||||||
#include "xbox/xboxkrnl_table.inc"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
|
Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
|
||||||
@ -128,8 +133,8 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
|
|||||||
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(data + header->securityOffset);
|
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(data + header->securityOffset);
|
||||||
const auto* fileFormatInfo = reinterpret_cast<const Xex2OptFileFormatInfo*>(getOptHeaderPtr(data, XEX_HEADER_FILE_FORMAT_INFO));
|
const auto* fileFormatInfo = reinterpret_cast<const Xex2OptFileFormatInfo*>(getOptHeaderPtr(data, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
|
|
||||||
Image image{};
|
Image image {};
|
||||||
std::unique_ptr<uint8_t[]> result{};
|
std::unique_ptr<uint8_t[]> result {};
|
||||||
size_t imageSize = security->imageSize;
|
size_t imageSize = security->imageSize;
|
||||||
|
|
||||||
// Decompress image
|
// Decompress image
|
||||||
@ -210,14 +215,14 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
|
|||||||
for (size_t i = 0; i < numSections; i++)
|
for (size_t i = 0; i < numSections; i++)
|
||||||
{
|
{
|
||||||
const auto& section = sections[i];
|
const auto& section = sections[i];
|
||||||
uint8_t flags{};
|
uint8_t flags {};
|
||||||
|
|
||||||
if (section.Characteristics & IMAGE_SCN_CNT_CODE)
|
if (section.Characteristics & IMAGE_SCN_CNT_CODE)
|
||||||
{
|
{
|
||||||
flags |= SectionFlags_Code;
|
flags |= SectionFlags_Code;
|
||||||
}
|
}
|
||||||
|
|
||||||
image.Map(reinterpret_cast<const char*>(section.Name), section.VirtualAddress,
|
image.Map(reinterpret_cast<const char*>(section.Name), section.VirtualAddress,
|
||||||
section.Misc.VirtualSize, flags, image.data.get() + section.VirtualAddress);
|
section.Misc.VirtualSize, flags, image.data.get() + section.VirtualAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,22 +17,22 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <TinySHA1.hpp>
|
||||||
#include <aes.hpp>
|
#include <aes.hpp>
|
||||||
#include <lzx.h>
|
#include <lzx.h>
|
||||||
#include <mspack.h>
|
#include <mspack.h>
|
||||||
#include <TinySHA1.hpp>
|
|
||||||
|
|
||||||
#include "memory_mapped_file.h"
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
struct mspack_memory_file
|
struct mspack_memory_file
|
||||||
{
|
{
|
||||||
mspack_system sys;
|
mspack_system sys;
|
||||||
void *buffer;
|
void* buffer;
|
||||||
size_t bufferSize;
|
size_t bufferSize;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer, size_t bufferSize)
|
static mspack_memory_file* mspack_memory_open(mspack_system* sys, void* buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
assert(bufferSize < INT_MAX);
|
assert(bufferSize < INT_MAX);
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(std::calloc(1, sizeof(mspack_memory_file)));
|
mspack_memory_file* memoryFile = (mspack_memory_file*)(std::calloc(1, sizeof(mspack_memory_file)));
|
||||||
if (memoryFile == nullptr)
|
if (memoryFile == nullptr)
|
||||||
{
|
{
|
||||||
return memoryFile;
|
return memoryFile;
|
||||||
@ -53,49 +53,49 @@ static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer,
|
|||||||
return memoryFile;
|
return memoryFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mspack_memory_close(mspack_memory_file *file)
|
static void mspack_memory_close(mspack_memory_file* file)
|
||||||
{
|
{
|
||||||
std::free(file);
|
std::free(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mspack_memory_read(mspack_file *file, void *buffer, int chars)
|
static int mspack_memory_read(mspack_file* file, void* buffer, int chars)
|
||||||
{
|
{
|
||||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
mspack_memory_file* memoryFile = (mspack_memory_file*)(file);
|
||||||
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||||
const size_t total = std::min(size_t(chars), remaining);
|
const size_t total = std::min(size_t(chars), remaining);
|
||||||
std::memcpy(buffer, (uint8_t *)(memoryFile->buffer) + memoryFile->offset, total);
|
std::memcpy(buffer, (uint8_t*)(memoryFile->buffer) + memoryFile->offset, total);
|
||||||
memoryFile->offset += total;
|
memoryFile->offset += total;
|
||||||
return int(total);
|
return int(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mspack_memory_write(mspack_file *file, void *buffer, int chars)
|
static int mspack_memory_write(mspack_file* file, void* buffer, int chars)
|
||||||
{
|
{
|
||||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
mspack_memory_file* memoryFile = (mspack_memory_file*)(file);
|
||||||
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||||
const size_t total = std::min(size_t(chars), remaining);
|
const size_t total = std::min(size_t(chars), remaining);
|
||||||
std::memcpy((uint8_t *)(memoryFile->buffer) + memoryFile->offset, buffer, total);
|
std::memcpy((uint8_t*)(memoryFile->buffer) + memoryFile->offset, buffer, total);
|
||||||
memoryFile->offset += total;
|
memoryFile->offset += total;
|
||||||
return int(total);
|
return int(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *mspack_memory_alloc(mspack_system *sys, size_t chars)
|
static void* mspack_memory_alloc(mspack_system* sys, size_t chars)
|
||||||
{
|
{
|
||||||
return std::calloc(chars, 1);
|
return std::calloc(chars, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mspack_memory_free(void *ptr)
|
static void mspack_memory_free(void* ptr)
|
||||||
{
|
{
|
||||||
std::free(ptr);
|
std::free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mspack_memory_copy(void *src, void *dest, size_t chars)
|
static void mspack_memory_copy(void* src, void* dest, size_t chars)
|
||||||
{
|
{
|
||||||
std::memcpy(dest, src, chars);
|
std::memcpy(dest, src, chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mspack_system *mspack_memory_sys_create()
|
static mspack_system* mspack_memory_sys_create()
|
||||||
{
|
{
|
||||||
auto sys = (mspack_system *)(std::calloc(1, sizeof(mspack_system)));
|
auto sys = (mspack_system*)(std::calloc(1, sizeof(mspack_system)));
|
||||||
if (!sys)
|
if (!sys)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -109,31 +109,31 @@ static mspack_system *mspack_memory_sys_create()
|
|||||||
return sys;
|
return sys;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mspack_memory_sys_destroy(struct mspack_system *sys)
|
static void mspack_memory_sys_destroy(struct mspack_system* sys)
|
||||||
{
|
{
|
||||||
free(sys);
|
free(sys);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
inline bool bitScanForward(uint32_t v, uint32_t* outFirstSetIndex)
|
||||||
{
|
{
|
||||||
return _BitScanForward((unsigned long *)(outFirstSetIndex), v) != 0;
|
return _BitScanForward((unsigned long*)(outFirstSetIndex), v) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
inline bool bitScanForward(uint64_t v, uint32_t* outFirstSetIndex)
|
||||||
{
|
{
|
||||||
return _BitScanForward64((unsigned long *)(outFirstSetIndex), v) != 0;
|
return _BitScanForward64((unsigned long*)(outFirstSetIndex), v) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
inline bool bitScanForward(uint32_t v, uint32_t* outFirstSetIndex)
|
||||||
{
|
{
|
||||||
int i = ffs(v);
|
int i = ffs(v);
|
||||||
*outFirstSetIndex = i - 1;
|
*outFirstSetIndex = i - 1;
|
||||||
return i != 0;
|
return i != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
inline bool bitScanForward(uint64_t v, uint32_t* outFirstSetIndex)
|
||||||
{
|
{
|
||||||
int i = __builtin_ffsll(v);
|
int i = __builtin_ffsll(v);
|
||||||
*outFirstSetIndex = i - 1;
|
*outFirstSetIndex = i - 1;
|
||||||
@ -141,20 +141,23 @@ inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int lzxDecompress(const void *lzxData, size_t lzxLength, void *dst, size_t dstLength, uint32_t windowSize, void *windowData, size_t windowDataLength)
|
static int lzxDecompress(const void* lzxData, size_t lzxLength, void* dst, size_t dstLength, uint32_t windowSize, void* windowData, size_t windowDataLength)
|
||||||
{
|
{
|
||||||
int resultCode = 1;
|
int resultCode = 1;
|
||||||
uint32_t windowBits;
|
uint32_t windowBits;
|
||||||
if (!bitScanForward(windowSize, &windowBits)) {
|
if (!bitScanForward(windowSize, &windowBits))
|
||||||
|
{
|
||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
mspack_system *sys = mspack_memory_sys_create();
|
mspack_system* sys = mspack_memory_sys_create();
|
||||||
mspack_memory_file *lzxSrc = mspack_memory_open(sys, (void *)(lzxData), lzxLength);
|
mspack_memory_file* lzxSrc = mspack_memory_open(sys, (void*)(lzxData), lzxLength);
|
||||||
mspack_memory_file *lzxDst = mspack_memory_open(sys, dst, dstLength);
|
mspack_memory_file* lzxDst = mspack_memory_open(sys, dst, dstLength);
|
||||||
lzxd_stream *lzxd = lzxd_init(sys, (mspack_file *)(lzxSrc), (mspack_file *)(lzxDst), windowBits, 0, 0x8000, dstLength, 0);
|
lzxd_stream* lzxd = lzxd_init(sys, (mspack_file*)(lzxSrc), (mspack_file*)(lzxDst), windowBits, 0, 0x8000, dstLength, 0);
|
||||||
if (lzxd != nullptr) {
|
if (lzxd != nullptr)
|
||||||
if (windowData != nullptr) {
|
{
|
||||||
|
if (windowData != nullptr)
|
||||||
|
{
|
||||||
size_t paddingLength = windowSize - windowDataLength;
|
size_t paddingLength = windowSize - windowDataLength;
|
||||||
std::memset(&lzxd->window[0], 0, paddingLength);
|
std::memset(&lzxd->window[0], 0, paddingLength);
|
||||||
std::memcpy(&lzxd->window[paddingLength], windowData, windowDataLength);
|
std::memcpy(&lzxd->window[paddingLength], windowData, windowDataLength);
|
||||||
@ -165,28 +168,31 @@ static int lzxDecompress(const void *lzxData, size_t lzxLength, void *dst, size_
|
|||||||
lzxd_free(lzxd);
|
lzxd_free(lzxd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lzxSrc) {
|
if (lzxSrc)
|
||||||
|
{
|
||||||
mspack_memory_close(lzxSrc);
|
mspack_memory_close(lzxSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lzxDst) {
|
if (lzxDst)
|
||||||
|
{
|
||||||
mspack_memory_close(lzxDst);
|
mspack_memory_close(lzxDst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sys) {
|
if (sys)
|
||||||
|
{
|
||||||
mspack_memory_sys_destroy(sys);
|
mspack_memory_sys_destroy(sys);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzxDeltaApplyPatch(const Xex2DeltaPatch *deltaPatch, uint32_t patchLength, uint32_t windowSize, uint8_t *dstData)
|
static int lzxDeltaApplyPatch(const Xex2DeltaPatch* deltaPatch, uint32_t patchLength, uint32_t windowSize, uint8_t* dstData)
|
||||||
{
|
{
|
||||||
const void *patchEnd = (const uint8_t *)(deltaPatch) + patchLength;
|
const void* patchEnd = (const uint8_t*)(deltaPatch) + patchLength;
|
||||||
const Xex2DeltaPatch *curPatch = deltaPatch;
|
const Xex2DeltaPatch* curPatch = deltaPatch;
|
||||||
while (patchEnd > curPatch)
|
while (patchEnd > curPatch)
|
||||||
{
|
{
|
||||||
int patchSize = -4;
|
int patchSize = -4;
|
||||||
if (curPatch->compressedLength == 0 && curPatch->uncompressedLength == 0 && curPatch->newAddress == 0 && curPatch->oldAddress == 0)
|
if (curPatch->compressedLength == 0 && curPatch->uncompressedLength == 0 && curPatch->newAddress == 0 && curPatch->oldAddress == 0)
|
||||||
{
|
{
|
||||||
// End of patch.
|
// End of patch.
|
||||||
@ -216,23 +222,23 @@ static int lzxDeltaApplyPatch(const Xex2DeltaPatch *deltaPatch, uint32_t patchLe
|
|||||||
}
|
}
|
||||||
|
|
||||||
curPatch++;
|
curPatch++;
|
||||||
curPatch = (const Xex2DeltaPatch *)((const uint8_t *)(curPatch) + patchSize);
|
curPatch = (const Xex2DeltaPatch*)((const uint8_t*)(curPatch) + patchSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSize, const uint8_t* patchBytes, size_t patchBytesSize, std::vector<uint8_t> &outBytes, bool skipData)
|
XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSize, const uint8_t* patchBytes, size_t patchBytesSize, std::vector<uint8_t>& outBytes, bool skipData)
|
||||||
{
|
{
|
||||||
// Validate headers.
|
// Validate headers.
|
||||||
static const char Xex2Magic[] = "XEX2";
|
static const char Xex2Magic[] = "XEX2";
|
||||||
const Xex2Header *xexHeader = (const Xex2Header *)(xexBytes);
|
const Xex2Header* xexHeader = (const Xex2Header*)(xexBytes);
|
||||||
if (memcmp(xexBytes, Xex2Magic, 4) != 0)
|
if (memcmp(xexBytes, Xex2Magic, 4) != 0)
|
||||||
{
|
{
|
||||||
return Result::XexFileInvalid;
|
return Result::XexFileInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Xex2Header *patchHeader = (const Xex2Header *)(patchBytes);
|
const Xex2Header* patchHeader = (const Xex2Header*)(patchBytes);
|
||||||
if (memcmp(patchBytes, Xex2Magic, 4) != 0)
|
if (memcmp(patchBytes, Xex2Magic, 4) != 0)
|
||||||
{
|
{
|
||||||
return Result::PatchFileInvalid;
|
return Result::PatchFileInvalid;
|
||||||
@ -244,13 +250,13 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate patch.
|
// Validate patch.
|
||||||
const Xex2OptDeltaPatchDescriptor *patchDescriptor = (const Xex2OptDeltaPatchDescriptor *)(getOptHeaderPtr(patchBytes, XEX_HEADER_DELTA_PATCH_DESCRIPTOR));
|
const Xex2OptDeltaPatchDescriptor* patchDescriptor = (const Xex2OptDeltaPatchDescriptor*)(getOptHeaderPtr(patchBytes, XEX_HEADER_DELTA_PATCH_DESCRIPTOR));
|
||||||
if (patchDescriptor == nullptr)
|
if (patchDescriptor == nullptr)
|
||||||
{
|
{
|
||||||
return Result::PatchFileInvalid;
|
return Result::PatchFileInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Xex2OptFileFormatInfo *patchFileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(patchBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
const Xex2OptFileFormatInfo* patchFileFormatInfo = (const Xex2OptFileFormatInfo*)(getOptHeaderPtr(patchBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
if (patchFileFormatInfo == nullptr)
|
if (patchFileFormatInfo == nullptr)
|
||||||
{
|
{
|
||||||
return Result::PatchFileInvalid;
|
return Result::PatchFileInvalid;
|
||||||
@ -295,7 +301,7 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
memset(outBytes.data(), 0, newXexHeaderSize);
|
memset(outBytes.data(), 0, newXexHeaderSize);
|
||||||
memcpy(outBytes.data(), xexBytes, headerTargetSize);
|
memcpy(outBytes.data(), xexBytes, headerTargetSize);
|
||||||
|
|
||||||
Xex2Header *newXexHeader = (Xex2Header *)(outBytes.data());
|
Xex2Header* newXexHeader = (Xex2Header*)(outBytes.data());
|
||||||
if (patchDescriptor->deltaHeadersSourceOffset > 0)
|
if (patchDescriptor->deltaHeadersSourceOffset > 0)
|
||||||
{
|
{
|
||||||
memcpy(&outBytes[patchDescriptor->deltaHeadersTargetOffset], &outBytes[patchDescriptor->deltaHeadersSourceOffset], patchDescriptor->deltaHeadersSourceSize);
|
memcpy(&outBytes[patchDescriptor->deltaHeadersTargetOffset], &outBytes[patchDescriptor->deltaHeadersSourceOffset], patchDescriptor->deltaHeadersSourceSize);
|
||||||
@ -309,20 +315,20 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
|
|
||||||
// Make the header the specified size by the patch.
|
// Make the header the specified size by the patch.
|
||||||
outBytes.resize(headerTargetSize);
|
outBytes.resize(headerTargetSize);
|
||||||
newXexHeader = (Xex2Header *)(outBytes.data());
|
newXexHeader = (Xex2Header*)(outBytes.data());
|
||||||
|
|
||||||
// Copy the rest of the data.
|
// Copy the rest of the data.
|
||||||
const Xex2SecurityInfo *newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
const Xex2SecurityInfo* newSecurityInfo = (const Xex2SecurityInfo*)(&outBytes[newXexHeader->securityOffset]);
|
||||||
outBytes.resize(outBytes.size() + newSecurityInfo->imageSize);
|
outBytes.resize(outBytes.size() + newSecurityInfo->imageSize);
|
||||||
memset(&outBytes[headerTargetSize], 0, outBytes.size() - headerTargetSize);
|
memset(&outBytes[headerTargetSize], 0, outBytes.size() - headerTargetSize);
|
||||||
memcpy(&outBytes[headerTargetSize], &xexBytes[xexHeader->headerSize], xexBytesSize - xexHeader->headerSize);
|
memcpy(&outBytes[headerTargetSize], &xexBytes[xexHeader->headerSize], xexBytesSize - xexHeader->headerSize);
|
||||||
newXexHeader = (Xex2Header *)(outBytes.data());
|
newXexHeader = (Xex2Header*)(outBytes.data());
|
||||||
newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
newSecurityInfo = (const Xex2SecurityInfo*)(&outBytes[newXexHeader->securityOffset]);
|
||||||
|
|
||||||
// Decrypt the keys and validate that the patch is compatible with the base file.
|
// Decrypt the keys and validate that the patch is compatible with the base file.
|
||||||
constexpr uint32_t KeySize = 16;
|
constexpr uint32_t KeySize = 16;
|
||||||
const Xex2SecurityInfo *originalSecurityInfo = (const Xex2SecurityInfo *)(&xexBytes[xexHeader->securityOffset]);
|
const Xex2SecurityInfo* originalSecurityInfo = (const Xex2SecurityInfo*)(&xexBytes[xexHeader->securityOffset]);
|
||||||
const Xex2SecurityInfo *patchSecurityInfo = (const Xex2SecurityInfo *)(&patchBytes[patchHeader->securityOffset]);
|
const Xex2SecurityInfo* patchSecurityInfo = (const Xex2SecurityInfo*)(&patchBytes[patchHeader->securityOffset]);
|
||||||
uint8_t decryptedOriginalKey[KeySize];
|
uint8_t decryptedOriginalKey[KeySize];
|
||||||
uint8_t decryptedNewKey[KeySize];
|
uint8_t decryptedNewKey[KeySize];
|
||||||
uint8_t decryptedPatchKey[KeySize];
|
uint8_t decryptedPatchKey[KeySize];
|
||||||
@ -356,9 +362,9 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
{
|
{
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt base XEX if necessary.
|
// Decrypt base XEX if necessary.
|
||||||
const Xex2OptFileFormatInfo *fileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(xexBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
const Xex2OptFileFormatInfo* fileFormatInfo = (const Xex2OptFileFormatInfo*)(getOptHeaderPtr(xexBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
if (fileFormatInfo == nullptr)
|
if (fileFormatInfo == nullptr)
|
||||||
{
|
{
|
||||||
return Result::XexFileInvalid;
|
return Result::XexFileInvalid;
|
||||||
@ -377,11 +383,12 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
// Decompress base XEX if necessary.
|
// Decompress base XEX if necessary.
|
||||||
if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
||||||
{
|
{
|
||||||
const Xex2FileBasicCompressionBlock *blocks = &((const Xex2FileBasicCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
|
const Xex2FileBasicCompressionBlock* blocks = &((const Xex2FileBasicCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
|
||||||
int32_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionBlock)) - 1;
|
int32_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionBlock)) - 1;
|
||||||
int32_t baseCompressedSize = 0;
|
int32_t baseCompressedSize = 0;
|
||||||
int32_t baseImageSize = 0;
|
int32_t baseImageSize = 0;
|
||||||
for (int32_t i = 0; i < numBlocks; i++) {
|
for (int32_t i = 0; i < numBlocks; i++)
|
||||||
|
{
|
||||||
baseCompressedSize += blocks[i].dataSize;
|
baseCompressedSize += blocks[i].dataSize;
|
||||||
baseImageSize += blocks[i].dataSize + blocks[i].zeroSize;
|
baseImageSize += blocks[i].dataSize + blocks[i].zeroSize;
|
||||||
}
|
}
|
||||||
@ -390,10 +397,10 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
{
|
{
|
||||||
return Result::XexFileInvalid;
|
return Result::XexFileInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse iteration allows to perform this decompression in place.
|
// Reverse iteration allows to perform this decompression in place.
|
||||||
uint8_t *srcDataCursor = outBytes.data() + headerTargetSize + baseCompressedSize;
|
uint8_t* srcDataCursor = outBytes.data() + headerTargetSize + baseCompressedSize;
|
||||||
uint8_t *outDataCursor = outBytes.data() + headerTargetSize + baseImageSize;
|
uint8_t* outDataCursor = outBytes.data() + headerTargetSize + baseImageSize;
|
||||||
for (int32_t i = numBlocks - 1; i >= 0; i--)
|
for (int32_t i = numBlocks - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
outDataCursor -= blocks[i].zeroSize;
|
outDataCursor -= blocks[i].zeroSize;
|
||||||
@ -412,12 +419,12 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
return Result::XexFileInvalid;
|
return Result::XexFileInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Xex2OptFileFormatInfo *newFileFormatInfo = (Xex2OptFileFormatInfo *)(getOptHeaderPtr(outBytes.data(), XEX_HEADER_FILE_FORMAT_INFO));
|
Xex2OptFileFormatInfo* newFileFormatInfo = (Xex2OptFileFormatInfo*)(getOptHeaderPtr(outBytes.data(), XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
if (newFileFormatInfo == nullptr)
|
if (newFileFormatInfo == nullptr)
|
||||||
{
|
{
|
||||||
return Result::PatchFailed;
|
return Result::PatchFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the header to indicate no encryption or compression is used.
|
// Update the header to indicate no encryption or compression is used.
|
||||||
newFileFormatInfo->encryptionType = XEX_ENCRYPTION_NONE;
|
newFileFormatInfo->encryptionType = XEX_ENCRYPTION_NONE;
|
||||||
newFileFormatInfo->compressionType = XEX_COMPRESSION_NONE;
|
newFileFormatInfo->compressionType = XEX_COMPRESSION_NONE;
|
||||||
@ -437,8 +444,8 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
return Result::PatchFileInvalid;
|
return Result::PatchFileInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Xex2CompressedBlockInfo *currentBlock = &((const Xex2FileNormalCompressionInfo*)(patchFileFormatInfo + 1))->firstBlock;
|
const Xex2CompressedBlockInfo* currentBlock = &((const Xex2FileNormalCompressionInfo*)(patchFileFormatInfo + 1))->firstBlock;
|
||||||
uint8_t *outExe = &outBytes[newXexHeader->headerSize];
|
uint8_t* outExe = &outBytes[newXexHeader->headerSize];
|
||||||
if (patchDescriptor->deltaImageSourceOffset > 0)
|
if (patchDescriptor->deltaImageSourceOffset > 0)
|
||||||
{
|
{
|
||||||
memcpy(&outExe[patchDescriptor->deltaImageTargetOffset], &outExe[patchDescriptor->deltaImageSourceOffset], patchDescriptor->deltaImageSourceSize);
|
memcpy(&outExe[patchDescriptor->deltaImageTargetOffset], &outExe[patchDescriptor->deltaImageSourceOffset], patchDescriptor->deltaImageSourceSize);
|
||||||
@ -447,10 +454,10 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
static const uint32_t DigestSize = 20;
|
static const uint32_t DigestSize = 20;
|
||||||
uint8_t sha1Digest[DigestSize];
|
uint8_t sha1Digest[DigestSize];
|
||||||
sha1::SHA1 sha1Context;
|
sha1::SHA1 sha1Context;
|
||||||
uint8_t *patchDataCursor = patchData.data();
|
uint8_t* patchDataCursor = patchData.data();
|
||||||
while (currentBlock->blockSize > 0)
|
while (currentBlock->blockSize > 0)
|
||||||
{
|
{
|
||||||
const Xex2CompressedBlockInfo *nextBlock = (const Xex2CompressedBlockInfo *)(patchDataCursor);
|
const Xex2CompressedBlockInfo* nextBlock = (const Xex2CompressedBlockInfo*)(patchDataCursor);
|
||||||
|
|
||||||
// Hash and validate the block.
|
// Hash and validate the block.
|
||||||
sha1Context.reset();
|
sha1Context.reset();
|
||||||
@ -465,7 +472,7 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
|
|
||||||
// Apply the block's patch data.
|
// Apply the block's patch data.
|
||||||
uint32_t blockDataSize = currentBlock->blockSize - 24;
|
uint32_t blockDataSize = currentBlock->blockSize - 24;
|
||||||
if (lzxDeltaApplyPatch((const Xex2DeltaPatch *)(patchDataCursor), blockDataSize, ((const Xex2FileNormalCompressionInfo*)(patchFileFormatInfo + 1))->windowSize, outExe) != 0)
|
if (lzxDeltaApplyPatch((const Xex2DeltaPatch*)(patchDataCursor), blockDataSize, ((const Xex2FileNormalCompressionInfo*)(patchFileFormatInfo + 1))->windowSize, outExe) != 0)
|
||||||
{
|
{
|
||||||
return Result::PatchFailed;
|
return Result::PatchFailed;
|
||||||
}
|
}
|
||||||
@ -477,7 +484,7 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
|
|||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
XexPatcher::Result XexPatcher::apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath)
|
XexPatcher::Result XexPatcher::apply(const std::filesystem::path& baseXexPath, const std::filesystem::path& patchXexPath, const std::filesystem::path& newXexPath)
|
||||||
{
|
{
|
||||||
MemoryMappedFile baseXexFile(baseXexPath);
|
MemoryMappedFile baseXexFile(baseXexPath);
|
||||||
MemoryMappedFile patchFile(patchXexPath);
|
MemoryMappedFile patchFile(patchXexPath);
|
||||||
@ -499,7 +506,7 @@ XexPatcher::Result XexPatcher::apply(const std::filesystem::path &baseXexPath, c
|
|||||||
return Result::FileOpenFailed;
|
return Result::FileOpenFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
newXexFile.write((const char *)(newXexBytes.data()), newXexBytes.size());
|
newXexFile.write((const char*)(newXexBytes.data()), newXexBytes.size());
|
||||||
newXexFile.close();
|
newXexFile.close();
|
||||||
|
|
||||||
if (newXexFile.bad())
|
if (newXexFile.bad())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user