1+ #include " Patches.h"
2+ #include " Signatures.h"
3+ #include " ../common.h"
4+ #include " ../utils/plat.h"
5+ #include " ../files/Files.h"
6+ #include " ../configuration/Configuration.h"
7+
8+ #include < rapidjson/document.h>
9+ #include < rapidjson/error/en.h>
10+
11+ #define HAS_MEMBER (DOCUMENT, MEMBER_NAME, MEMBER_PATH ) \
12+ if (!DOCUMENT.HasMember(MEMBER_NAME)) \
13+ { \
14+ PatchesError (string_format (" The field \" %s\" doesn't exists." , MEMBER_PATH)); \
15+ continue ; \
16+ }
17+
18+ #define IS_STRING (DOCUMENT, MEMBER_NAME, MEMBER_PATH ) \
19+ if (!DOCUMENT[MEMBER_NAME].IsString()) \
20+ { \
21+ PatchesError (string_format (" The field \" %s\" is not a string." , MEMBER_PATH)); \
22+ continue ; \
23+ }
24+
25+ byte *HexToByte (const char *src, size_t &length);
26+
27+ void PatchesError (std::string text)
28+ {
29+ if (!g_SMAPI)
30+ return ;
31+
32+ PRINTF (" Patches" , " %s\n " , text.c_str ());
33+ }
34+
35+ void Patches::LoadPatches ()
36+ {
37+ rapidjson::Document patchesFile;
38+ patchesFile.Parse (Files::Read (" addons/swiftly/gamedata/patches.json" ).c_str ());
39+ if (patchesFile.HasParseError ())
40+ return PatchesError (string_format (" A parsing error has been detected.\n Error (offset %u): %s\n " , (unsigned )patchesFile.GetErrorOffset (), GetParseError_En (patchesFile.GetParseError ())));
41+
42+ if (patchesFile.IsArray ())
43+ return PatchesError (" Patches file cannot be an array." );
44+
45+ for (auto it = patchesFile.MemberBegin (); it != patchesFile.MemberEnd (); ++it)
46+ {
47+ std::string name = it->name .GetString ();
48+
49+ HAS_MEMBER (it->value , " signature" , string_format (" %s.signature" , name))
50+ HAS_MEMBER (it->value , " windows" , string_format (" %s.windows" , name))
51+ HAS_MEMBER (it->value , " linux" , string_format (" %s.linux" , name))
52+
53+ IS_STRING (it->value , " signature" , string_format (" %s.signature" , name))
54+ IS_STRING (it->value , " windows" , string_format (" %s.windows" , name))
55+ IS_STRING (it->value , " linux" , string_format (" %s.linux" , name))
56+
57+ std::string signature = it->value [" signature" ].GetString ();
58+ if (!g_Signatures->Exists (signature))
59+ {
60+ PatchesError (string_format (" %s: Signature '%s' does not exists in signatures file.\n " , name.c_str (), signature.c_str ()));
61+ continue ;
62+ }
63+
64+ this ->patches .insert (std::make_pair (name, std::string (it->value [WIN_LINUX (" windows" , " linux" )].GetString ())));
65+ this ->signatures .insert (std::make_pair (name, signature));
66+ }
67+ }
68+
69+ void Patches::PerformPatch (std::string patch_name)
70+ {
71+ if (this ->patches .find (patch_name) == this ->patches .end ())
72+ {
73+ PRINTF (" Patch" , " Invalid patch name: \" %s\" .\n " , patch_name.c_str ());
74+ return ;
75+ }
76+
77+ void *patchAddress = g_Signatures->FetchRawSignature (this ->signatures .at (patch_name));
78+
79+ size_t iLength = 0 ;
80+ byte *patch = HexToByte (this ->patches .at (patch_name).c_str (), iLength);
81+
82+ Plat_WriteMemory (patchAddress, (byte *)patch, iLength);
83+ PRINTF (" Patch" , " Patched \" %s\" using signature \" %s\" .\n " , patch_name.c_str (), this ->signatures .at (patch_name).c_str ());
84+ }
85+
86+ void Patches::PerformPatches ()
87+ {
88+ if (g_Config->HasKey (" core.patchesToPerform" ))
89+ {
90+ std::vector<std::string> patchesToPerform = explode (g_Config->FetchValue <std::string>(" core.patchesToPerform" ), " " );
91+
92+ uint32_t patchesPerformed = 0 ;
93+ for (std::string &patchName : patchesToPerform)
94+ {
95+ if (patchName == " " )
96+ continue ;
97+
98+ this ->PerformPatch (patchName);
99+ ++patchesPerformed;
100+ }
101+
102+ PRINTF (" Patch" , " Patches performed: %02d.\n " , patchesPerformed);
103+ patchesToPerform.clear ();
104+ }
105+ }
0 commit comments