#include "stdafx.h" #include #include #include "UpsPatcher.h" #include "CRC32.h" int64_t UpsPatcher::ReadBase128Number(std::istream& file) { int64_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 += (int64_t)1 << shift; } return result; } bool UpsPatcher::PatchBuffer(string upsFilepath, vector& input, vector& output) { ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary); if (upsFile) { return PatchBuffer(upsFile, input, output); } return false; } bool UpsPatcher::PatchBuffer(std::istream& upsFile, vector& input, vector& output) { 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); if (memcmp((char*)&header, "UPS1", 4) != 0) { //Invalid UPS file return false; } int64_t inputFileSize = ReadBase128Number(upsFile); int64_t outputFileSize = ReadBase128Number(upsFile); if (inputFileSize == -1 || outputFileSize == -1) { //Invalid file return false; } output.resize((size_t)outputFileSize); std::copy(input.begin(), input.end(), output.begin()); uint32_t pos = 0; while ((size_t)upsFile.tellg() < fileSize - 12) { int32_t offset = (int32_t)ReadBase128Number(upsFile); if (offset == -1) { //Invalid file return false; } pos += offset; while (true) { uint8_t xorValue = 0; upsFile.read((char*)&xorValue, 1); if ((size_t)upsFile.tellg() > fileSize - 12) { //Invalid file return false; } output[pos] ^= xorValue; pos++; if (!xorValue) { break; } } } uint8_t inputChecksum[4]; uint8_t outputChecksum[4]; upsFile.read((char*)inputChecksum, 4); upsFile.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; }