Mesen-SX/Utilities/UpsPatcher.cpp

115 lines
2.4 KiB
C++
Raw Normal View History

2019-02-13 14:10:36 -05:00
#include "stdafx.h"
#include <assert.h>
#include <cstring>
#include "UpsPatcher.h"
#include "CRC32.h"
2020-12-19 23:32:47 +03:00
int64_t UpsPatcher::ReadBase128Number(std::istream& file)
2019-02-13 14:10:36 -05:00
{
int64_t result = 0;
int shift = 0;
uint8_t buffer;
2020-12-19 23:32:47 +03:00
while (true)
{
2019-02-13 14:10:36 -05:00
file.read((char*)&buffer, 1);
2020-12-19 23:32:47 +03:00
if (file.eof())
{
2019-02-13 14:10:36 -05:00
return -1;
}
result += (buffer & 0x7F) << shift;
shift += 7;
2020-12-19 23:32:47 +03:00
if (buffer & 0x80)
{
2019-02-13 14:10:36 -05:00
break;
}
result += (int64_t)1 << shift;
}
return result;
}
2020-12-19 23:32:47 +03:00
bool UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t>& input, vector<uint8_t>& output)
2019-02-13 14:10:36 -05:00
{
ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary);
2020-12-19 23:32:47 +03:00
if (upsFile)
{
2019-02-13 14:10:36 -05:00
return PatchBuffer(upsFile, input, output);
}
return false;
}
2020-12-19 23:32:47 +03:00
bool UpsPatcher::PatchBuffer(std::istream& upsFile, vector<uint8_t>& input, vector<uint8_t>& output)
2019-02-13 14:10:36 -05:00
{
upsFile.seekg(0, std::ios::end);
size_t fileSize = (size_t)upsFile.tellg();
upsFile.seekg(0, std::ios::beg);
char header[4];
upsFile.read((char*)&header, 4);
2020-12-19 23:32:47 +03:00
if (memcmp((char*)&header, "UPS1", 4) != 0)
{
2019-02-13 14:10:36 -05:00
//Invalid UPS file
return false;
}
int64_t inputFileSize = ReadBase128Number(upsFile);
int64_t outputFileSize = ReadBase128Number(upsFile);
2020-12-19 23:32:47 +03:00
if (inputFileSize == -1 || outputFileSize == -1)
{
2019-02-13 14:10:36 -05:00
//Invalid file
return false;
}
output.resize((size_t)outputFileSize);
std::copy(input.begin(), input.end(), output.begin());
uint32_t pos = 0;
2020-12-19 23:32:47 +03:00
while ((size_t)upsFile.tellg() < fileSize - 12)
{
2019-02-13 14:10:36 -05:00
int32_t offset = (int32_t)ReadBase128Number(upsFile);
2020-12-19 23:32:47 +03:00
if (offset == -1)
{
2019-02-13 14:10:36 -05:00
//Invalid file
return false;
}
pos += offset;
2020-12-19 23:32:47 +03:00
while (true)
{
2019-02-13 14:10:36 -05:00
uint8_t xorValue = 0;
upsFile.read((char*)&xorValue, 1);
2020-12-19 23:32:47 +03:00
if ((size_t)upsFile.tellg() > fileSize - 12)
{
2019-02-13 14:10:36 -05:00
//Invalid file
return false;
}
output[pos] ^= xorValue;
pos++;
2020-12-19 23:32:47 +03:00
if (!xorValue)
{
2019-02-13 14:10:36 -05:00
break;
}
}
}
uint8_t inputChecksum[4];
uint8_t outputChecksum[4];
upsFile.read((char*)inputChecksum, 4);
upsFile.read((char*)outputChecksum, 4);
2020-12-19 23:32:47 +03:00
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] <<
24);
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[
3] << 24);
2019-02-13 14:10:36 -05:00
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
2020-12-19 23:32:47 +03:00
if (patchInputCrc != inputCrc || patchOutputCrc != outputCrc)
{
2019-02-13 14:10:36 -05:00
return false;
}
return true;
}