mirror of
https://github.com/libretro/Mesen.git
synced 2024-12-13 20:42:24 +00:00
129 lines
3.1 KiB
C++
129 lines
3.1 KiB
C++
#include "stdafx.h"
|
|
#include <assert.h>
|
|
#include <cstring>
|
|
#include "BpsPatcher.h"
|
|
#include "CRC32.h"
|
|
|
|
uint64_t BpsPatcher::ReadBase128Number(std::istream &file)
|
|
{
|
|
uint64_t result = 0;
|
|
int shift = 0;
|
|
uint8_t buffer;
|
|
while(true) {
|
|
file.read((char*)&buffer, 1);
|
|
if(file.eof()) {
|
|
return -1;
|
|
}
|
|
result += (buffer & 0x7F) << shift;
|
|
shift += 7;
|
|
if(buffer & 0x80) {
|
|
break;
|
|
}
|
|
result += (uint64_t)1 << shift;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
|
|
{
|
|
ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary);
|
|
if(bpsFile) {
|
|
return PatchBuffer(bpsFile, input, output);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
|
{
|
|
bpsFile.seekg(0, std::ios::end);
|
|
size_t fileSize = (size_t)bpsFile.tellg();
|
|
bpsFile.seekg(0, std::ios::beg);
|
|
|
|
char header[4];
|
|
bpsFile.read((char*)&header, 4);
|
|
if(memcmp((char*)&header, "BPS1", 4) != 0) {
|
|
//Invalid BPS file
|
|
return false;
|
|
}
|
|
|
|
uint64_t inputFileSize = ReadBase128Number(bpsFile);
|
|
uint64_t outputFileSize = ReadBase128Number(bpsFile);
|
|
if(inputFileSize == -1 || outputFileSize == -1) {
|
|
//Invalid file
|
|
return false;
|
|
}
|
|
|
|
uint64_t metadataSize = ReadBase128Number(bpsFile);
|
|
bpsFile.seekg(metadataSize, std::ios::cur);
|
|
|
|
output.resize((size_t)outputFileSize);
|
|
|
|
uint32_t outputOffset = 0;
|
|
uint32_t inputRelativeOffset = 0;
|
|
uint32_t outputRelativeOffset = 0;
|
|
while((size_t)bpsFile.tellg() < fileSize - 12) {
|
|
uint64_t data = ReadBase128Number(bpsFile);
|
|
if(data == -1) {
|
|
//Invalid file
|
|
return false;
|
|
}
|
|
|
|
uint8_t command = data & 0x03;
|
|
uint64_t length = (data >> 2) + 1;
|
|
switch(command) {
|
|
case 0:
|
|
//SourceRead
|
|
while(length--) {
|
|
output[outputOffset] = input[outputOffset];
|
|
outputOffset++;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
//TargetRead
|
|
while(length--) {
|
|
uint8_t value = 0;
|
|
bpsFile.read((char*)&value, 1);
|
|
|
|
output[outputOffset++] = value;
|
|
}
|
|
break;
|
|
|
|
case 2: {
|
|
//SourceCopy
|
|
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
|
inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
|
while(length--) {
|
|
output[outputOffset++] = input[inputRelativeOffset++];
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 3: {
|
|
//TargetCopy
|
|
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
|
outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
|
while(length--) {
|
|
output[outputOffset++] = output[outputRelativeOffset++];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t inputChecksum[4];
|
|
uint8_t outputChecksum[4];
|
|
bpsFile.read((char*)inputChecksum, 4);
|
|
bpsFile.read((char*)outputChecksum, 4);
|
|
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);
|
|
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
|
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
|
|
|
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|