mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
143 lines
6.0 KiB
C++
143 lines
6.0 KiB
C++
/*
|
|
* sfall
|
|
* Copyright (C) 2008-2024 The sfall team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
|
|
#include "main.h"
|
|
#include "version.h"
|
|
#include "Logging.h"
|
|
|
|
#include "CRC.h"
|
|
|
|
namespace sfall
|
|
{
|
|
|
|
static const DWORD ExpectedSize = 1189888;
|
|
static const DWORD ExpectedCRC[] = {
|
|
0xE1680293, // US 1.02d
|
|
0xEF34F989 // US 1.02d + HRP by Mash
|
|
};
|
|
|
|
static void inline ExitMessageFail(const char* a) {
|
|
MessageBoxA(0, a, 0, MB_TASKMODAL | MB_ICONERROR);
|
|
ExitProcess(1);
|
|
}
|
|
|
|
// Precomputed CRC32C table
|
|
static const DWORD CRC_table[256] = {
|
|
0x00000000, 0x0A5F4D75, 0x14BE9AEA, 0x1EE1D79F, 0x14C5EB57, 0x1E9AA622, 0x007B71BD, 0x0A243CC8,
|
|
0x1433082D, 0x1E6C4558, 0x008D92C7, 0x0AD2DFB2, 0x00F6E37A, 0x0AA9AE0F, 0x14487990, 0x1E1734E5,
|
|
0x15DECED9, 0x1F8183AC, 0x01605433, 0x0B3F1946, 0x011B258E, 0x0B4468FB, 0x15A5BF64, 0x1FFAF211,
|
|
0x01EDC6F4, 0x0BB28B81, 0x15535C1E, 0x1F0C116B, 0x15282DA3, 0x1F7760D6, 0x0196B749, 0x0BC9FA3C,
|
|
0x16054331, 0x1C5A0E44, 0x02BBD9DB, 0x08E494AE, 0x02C0A866, 0x089FE513, 0x167E328C, 0x1C217FF9,
|
|
0x02364B1C, 0x08690669, 0x1688D1F6, 0x1CD79C83, 0x16F3A04B, 0x1CACED3E, 0x024D3AA1, 0x081277D4,
|
|
0x03DB8DE8, 0x0984C09D, 0x17651702, 0x1D3A5A77, 0x171E66BF, 0x1D412BCA, 0x03A0FC55, 0x09FFB120,
|
|
0x17E885C5, 0x1DB7C8B0, 0x03561F2F, 0x0909525A, 0x032D6E92, 0x097223E7, 0x1793F478, 0x1DCCB90D,
|
|
0x11B258E1, 0x1BED1594, 0x050CC20B, 0x0F538F7E, 0x0577B3B6, 0x0F28FEC3, 0x11C9295C, 0x1B966429,
|
|
0x058150CC, 0x0FDE1DB9, 0x113FCA26, 0x1B608753, 0x1144BB9B, 0x1B1BF6EE, 0x05FA2171, 0x0FA56C04,
|
|
0x046C9638, 0x0E33DB4D, 0x10D20CD2, 0x1A8D41A7, 0x10A97D6F, 0x1AF6301A, 0x0417E785, 0x0E48AAF0,
|
|
0x105F9E15, 0x1A00D360, 0x04E104FF, 0x0EBE498A, 0x049A7542, 0x0EC53837, 0x1024EFA8, 0x1A7BA2DD,
|
|
0x07B71BD0, 0x0DE856A5, 0x1309813A, 0x1956CC4F, 0x1372F087, 0x192DBDF2, 0x07CC6A6D, 0x0D932718,
|
|
0x138413FD, 0x19DB5E88, 0x073A8917, 0x0D65C462, 0x0741F8AA, 0x0D1EB5DF, 0x13FF6240, 0x19A02F35,
|
|
0x1269D509, 0x1836987C, 0x06D74FE3, 0x0C880296, 0x06AC3E5E, 0x0CF3732B, 0x1212A4B4, 0x184DE9C1,
|
|
0x065ADD24, 0x0C059051, 0x12E447CE, 0x18BB0ABB, 0x129F3673, 0x18C07B06, 0x0621AC99, 0x0C7EE1EC,
|
|
0x1EDC6F41, 0x14832234, 0x0A62F5AB, 0x003DB8DE, 0x0A198416, 0x0046C963, 0x1EA71EFC, 0x14F85389,
|
|
0x0AEF676C, 0x00B02A19, 0x1E51FD86, 0x140EB0F3, 0x1E2A8C3B, 0x1475C14E, 0x0A9416D1, 0x00CB5BA4,
|
|
0x0B02A198, 0x015DECED, 0x1FBC3B72, 0x15E37607, 0x1FC74ACF, 0x159807BA, 0x0B79D025, 0x01269D50,
|
|
0x1F31A9B5, 0x156EE4C0, 0x0B8F335F, 0x01D07E2A, 0x0BF442E2, 0x01AB0F97, 0x1F4AD808, 0x1515957D,
|
|
0x08D92C70, 0x02866105, 0x1C67B69A, 0x1638FBEF, 0x1C1CC727, 0x16438A52, 0x08A25DCD, 0x02FD10B8,
|
|
0x1CEA245D, 0x16B56928, 0x0854BEB7, 0x020BF3C2, 0x082FCF0A, 0x0270827F, 0x1C9155E0, 0x16CE1895,
|
|
0x1D07E2A9, 0x1758AFDC, 0x09B97843, 0x03E63536, 0x09C209FE, 0x039D448B, 0x1D7C9314, 0x1723DE61,
|
|
0x0934EA84, 0x036BA7F1, 0x1D8A706E, 0x17D53D1B, 0x1DF101D3, 0x17AE4CA6, 0x094F9B39, 0x0310D64C,
|
|
0x0F6E37A0, 0x05317AD5, 0x1BD0AD4A, 0x118FE03F, 0x1BABDCF7, 0x11F49182, 0x0F15461D, 0x054A0B68,
|
|
0x1B5D3F8D, 0x110272F8, 0x0FE3A567, 0x05BCE812, 0x0F98D4DA, 0x05C799AF, 0x1B264E30, 0x11790345,
|
|
0x1AB0F979, 0x10EFB40C, 0x0E0E6393, 0x04512EE6, 0x0E75122E, 0x042A5F5B, 0x1ACB88C4, 0x1094C5B1,
|
|
0x0E83F154, 0x04DCBC21, 0x1A3D6BBE, 0x106226CB, 0x1A461A03, 0x10195776, 0x0EF880E9, 0x04A7CD9C,
|
|
0x196B7491, 0x133439E4, 0x0DD5EE7B, 0x078AA30E, 0x0DAE9FC6, 0x07F1D2B3, 0x1910052C, 0x134F4859,
|
|
0x0D587CBC, 0x070731C9, 0x19E6E656, 0x13B9AB23, 0x199D97EB, 0x13C2DA9E, 0x0D230D01, 0x077C4074,
|
|
0x0CB5BA48, 0x06EAF73D, 0x180B20A2, 0x12546DD7, 0x1870511F, 0x122F1C6A, 0x0CCECBF5, 0x06918680,
|
|
0x1886B265, 0x12D9FF10, 0x0C38288F, 0x066765FA, 0x0C435932, 0x061C1447, 0x18FDC3D8, 0x12A28EAD
|
|
};
|
|
|
|
static DWORD CalcCRCInternal(BYTE* data, DWORD size) {
|
|
DWORD crc = 0xFFFFFFFF;
|
|
for (DWORD i = 0; i < size; i++) {
|
|
crc = CRC_table[(((BYTE)(crc)) ^ data[i])] ^ (crc >> 8);
|
|
}
|
|
return crc ^ 0xFFFFFFFF;
|
|
}
|
|
|
|
static bool CheckExtraCRC(DWORD crc) {
|
|
auto extraCrcList = IniReader::GetListDefaultConfig("Debugging", "ExtraCRC", "", ',');
|
|
if (!extraCrcList.empty()) {
|
|
return std::any_of(extraCrcList.begin(), extraCrcList.end(), [crc](const std::string& testCrcStr) {
|
|
auto testedCrc = strtoul(testCrcStr.c_str(), 0, 16);
|
|
return testedCrc && crc == testedCrc; // return for lambda
|
|
});
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CRC(const char* filepath) {
|
|
char buf[512];
|
|
|
|
HANDLE h = CreateFileA(filepath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
ExitMessageFail("Cannot open the game executable for CRC check.");
|
|
return false;
|
|
}
|
|
|
|
DWORD size = GetFileSize(h, 0);
|
|
|
|
DWORD crc;
|
|
BYTE* bytes = new BYTE[size];
|
|
ReadFile(h, bytes, size, &crc, 0);
|
|
CloseHandle(h);
|
|
|
|
crc = CalcCRCInternal(bytes, size);
|
|
delete[] bytes;
|
|
|
|
for (int i = 0; i < sizeof(ExpectedCRC) / 4; i++) {
|
|
if (crc == ExpectedCRC[i]) return true;
|
|
}
|
|
|
|
Retry:
|
|
bool matchedCRC = CheckExtraCRC(crc);
|
|
if (!matchedCRC) {
|
|
sprintf_s(buf, "You're trying to use sfall with an incompatible version of Fallout.\n"
|
|
"Was expecting '" TARGETVERSION "'.\n\n"
|
|
"%s has an unexpected CRC.\nExpected 0x%x but got 0x%x.", filepath, ExpectedCRC[0], crc);
|
|
|
|
if (size == ExpectedSize) {
|
|
switch (MessageBoxA(0, buf, "CRC Mismatch", MB_TASKMODAL | MB_ICONWARNING | MB_ABORTRETRYIGNORE)) {
|
|
case IDABORT:
|
|
ExitProcess(1);
|
|
break;
|
|
case IDRETRY:
|
|
goto Retry;
|
|
}
|
|
return true;
|
|
}
|
|
ExitMessageFail(buf);
|
|
}
|
|
return matchedCRC;
|
|
}
|
|
|
|
}
|