mirror of https://github.com/snes9xgit/snes9x.git
Don't allocate 8MB for patching.
This commit is contained in:
parent
2fb67c7329
commit
08bf7a8696
97
memmap.cpp
97
memmap.cpp
|
@ -3470,6 +3470,33 @@ static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<uint8_t> ReadStreamUntilEOF(Stream *r)
|
||||||
|
{
|
||||||
|
const size_t max_buffer_size = 4096;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
uint8_t buffer[max_buffer_size];
|
||||||
|
size_t total_size = 0;
|
||||||
|
size_t buffer_size = 0;
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
while (value != EOF)
|
||||||
|
{
|
||||||
|
value = r->get_char();
|
||||||
|
if (value != EOF)
|
||||||
|
buffer[buffer_size++] = value;
|
||||||
|
|
||||||
|
if (buffer_size == max_buffer_size || (value == EOF && buffer_size > 0))
|
||||||
|
{
|
||||||
|
data.resize(data.size() + buffer_size);
|
||||||
|
memcpy(&data[total_size], buffer, buffer_size);
|
||||||
|
total_size += buffer_size;
|
||||||
|
buffer_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
//NOTE: UPS patches are *never* created against a headered ROM!
|
//NOTE: UPS patches are *never* created against a headered ROM!
|
||||||
//this is per the UPS file specification. however, do note that it is
|
//this is per the UPS file specification. however, do note that it is
|
||||||
//technically possible for a non-compliant patcher to ignore this requirement.
|
//technically possible for a non-compliant patcher to ignore this requirement.
|
||||||
|
@ -3482,40 +3509,28 @@ static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size)
|
||||||
static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
|
static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
|
||||||
{
|
{
|
||||||
//Reader lacks size() and rewind(), so we need to read in the file to get its size
|
//Reader lacks size() and rewind(), so we need to read in the file to get its size
|
||||||
uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
|
auto data_vector = ReadStreamUntilEOF(r);
|
||||||
uint32 size = 0;
|
uint8 *data = &data_vector[0];
|
||||||
while(true) {
|
uint32 size = data_vector.size();
|
||||||
int value = r->get_char();
|
|
||||||
if(value == EOF) break;
|
|
||||||
data[size++] = value;
|
|
||||||
if(size >= 8 * 1024 * 1024) {
|
|
||||||
//prevent buffer overflow: SNES-made UPS patches should never be this big anyway ...
|
|
||||||
delete[] data;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//4-byte header + 1-byte input size + 1-byte output size + 4-byte patch CRC32 + 4-byte unpatched CRC32 + 4-byte patched CRC32
|
//4-byte header + 1-byte input size + 1-byte output size + 4-byte patch CRC32 + 4-byte unpatched CRC32 + 4-byte patched CRC32
|
||||||
if(size < 18) { delete[] data; return false; } //patch is too small
|
if(size < 18) return false; //patch is too small
|
||||||
|
|
||||||
uint32 addr = 0;
|
uint32 addr = 4;
|
||||||
if(data[addr++] != 'U') { delete[] data; return false; } //patch has an invalid header
|
if (memcmp(data, "UPS1", 4) != 0) return false; //patch has an invalid header
|
||||||
if(data[addr++] != 'P') { delete[] data; return false; } //...
|
|
||||||
if(data[addr++] != 'S') { delete[] data; return false; } //...
|
|
||||||
if(data[addr++] != '1') { delete[] data; return false; } //...
|
|
||||||
|
|
||||||
uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
|
uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
|
||||||
uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
|
uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
|
||||||
uint32 px_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
|
uint32 px_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
|
||||||
uint32 py_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
|
uint32 py_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
|
||||||
uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
|
uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
|
||||||
if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted
|
if(patch_crc32 != pp_crc32) { return false; } //patch is corrupted
|
||||||
if(!Settings.IgnorePatchChecksum && (rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) { delete[] data; return false; } //patch is for a different ROM
|
if(!Settings.IgnorePatchChecksum && (rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) return false; //patch is for a different ROM
|
||||||
|
|
||||||
uint32 px_size = XPSdecode(data, addr, size);
|
uint32 px_size = XPSdecode(data, addr, size);
|
||||||
uint32 py_size = XPSdecode(data, addr, size);
|
uint32 py_size = XPSdecode(data, addr, size);
|
||||||
uint32 out_size = ((uint32) rom_size == px_size) ? py_size : px_size;
|
uint32 out_size = ((uint32) rom_size == px_size) ? py_size : px_size;
|
||||||
if(out_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer
|
if(out_size > CMemory::MAX_ROM_SIZE) { return false; } //applying this patch will overflow Memory.ROM buffer
|
||||||
|
|
||||||
//fill expanded area with 0x00s; so that XORing works as expected below.
|
//fill expanded area with 0x00s; so that XORing works as expected below.
|
||||||
//note that this is needed (and works) whether output ROM is larger or smaller than pre-patched ROM
|
//note that this is needed (and works) whether output ROM is larger or smaller than pre-patched ROM
|
||||||
|
@ -3534,7 +3549,6 @@ static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
rom_size = out_size;
|
rom_size = out_size;
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
uint32 out_crc32 = caCRC32(Memory.ROM, rom_size);
|
uint32 out_crc32 = caCRC32(Memory.ROM, rom_size);
|
||||||
if(Settings.IgnorePatchChecksum
|
if(Settings.IgnorePatchChecksum
|
||||||
|
@ -3565,49 +3579,38 @@ static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
|
||||||
//
|
//
|
||||||
static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size)
|
static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size)
|
||||||
{
|
{
|
||||||
uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
|
auto data_vector = ReadStreamUntilEOF(r);
|
||||||
uint32 size = 0;
|
uint8 *data = &data_vector[0];
|
||||||
while(true) {
|
uint32 size = data_vector.size();
|
||||||
int value = r->get_char();
|
|
||||||
if(value == EOF) break;
|
|
||||||
data[size++] = value;
|
|
||||||
if(size >= 8 * 1024 * 1024) {
|
|
||||||
//prevent buffer overflow: SNES-made BPS patches should never be this big anyway ...
|
|
||||||
delete[] data;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 4-byte header + 1-byte input size + 1-byte output size + 1-byte metadata size
|
/* 4-byte header + 1-byte input size + 1-byte output size + 1-byte metadata size
|
||||||
+ 4-byte unpatched CRC32 + 4-byte patched CRC32 + 4-byte patch CRC32 */
|
+ 4-byte unpatched CRC32 + 4-byte patched CRC32 + 4-byte patch CRC32 */
|
||||||
if(size < 19) { delete[] data; return false; } //patch is too small
|
if(size < 19) return false; //patch is too small
|
||||||
|
|
||||||
uint32 addr = 0;
|
uint32 addr = 4;
|
||||||
if(data[addr++] != 'B') { delete[] data; return false; } //patch has an invalid header
|
if (memcmp(data, "BPS1", 4) != 0) return false; //patch has an invalid header
|
||||||
if(data[addr++] != 'P') { delete[] data; return false; } //...
|
|
||||||
if(data[addr++] != 'S') { delete[] data; return false; } //...
|
|
||||||
if(data[addr++] != '1') { delete[] data; return false; } //...
|
|
||||||
|
|
||||||
uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
|
uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
|
||||||
uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
|
uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
|
||||||
uint32 source_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
|
uint32 source_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
|
||||||
uint32 target_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
|
uint32 target_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
|
||||||
uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
|
uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
|
||||||
if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted
|
if(patch_crc32 != pp_crc32) return false; //patch is corrupted
|
||||||
if(!Settings.IgnorePatchChecksum && rom_crc32 != source_crc32) { delete[] data; return false; } //patch is for a different ROM
|
if(!Settings.IgnorePatchChecksum && rom_crc32 != source_crc32) return false; //patch is for a different ROM
|
||||||
|
|
||||||
XPSdecode(data, addr, size);
|
XPSdecode(data, addr, size);
|
||||||
uint32 target_size = XPSdecode(data, addr, size);
|
uint32 target_size = XPSdecode(data, addr, size);
|
||||||
uint32 metadata_size = XPSdecode(data, addr, size);
|
uint32 metadata_size = XPSdecode(data, addr, size);
|
||||||
addr += metadata_size;
|
addr += metadata_size;
|
||||||
|
|
||||||
if(target_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer
|
if(target_size > CMemory::MAX_ROM_SIZE) return false; //applying this patch will overflow Memory.ROM buffer
|
||||||
|
|
||||||
enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||||
uint32 outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0;
|
uint32 outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0;
|
||||||
|
|
||||||
uint8 *patched_rom = new uint8[target_size];
|
std::vector<uint8_t> patched_rom_vector(target_size);
|
||||||
memset(patched_rom,0,target_size);
|
uint8 *patched_rom = &patched_rom_vector[0];
|
||||||
|
memset(patched_rom, 0, target_size);
|
||||||
|
|
||||||
while(addr < size - 12) {
|
while(addr < size - 12) {
|
||||||
uint32 length = XPSdecode(data, addr, size);
|
uint32 length = XPSdecode(data, addr, size);
|
||||||
|
@ -3642,17 +3645,13 @@ static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
uint32 out_crc32 = caCRC32(patched_rom, target_size);
|
uint32 out_crc32 = caCRC32(patched_rom, target_size);
|
||||||
if(Settings.IgnorePatchChecksum || out_crc32 == target_crc32) {
|
if(Settings.IgnorePatchChecksum || out_crc32 == target_crc32) {
|
||||||
memcpy(Memory.ROM, patched_rom, target_size);
|
memcpy(Memory.ROM, patched_rom, target_size);
|
||||||
rom_size = target_size;
|
rom_size = target_size;
|
||||||
delete[] patched_rom;
|
|
||||||
Settings.IsPatched = 2;
|
Settings.IsPatched = 2;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
delete[] patched_rom;
|
|
||||||
fprintf(stderr, "WARNING: BPS patching failed.\nROM has not been altered.\n");
|
fprintf(stderr, "WARNING: BPS patching failed.\nROM has not been altered.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue