├── .editorconfig ├── .gitattributes ├── .gitignore ├── ModLoaderCommon.sln └── ModLoaderCommon ├── CodeParser.cpp ├── CodeParser.hpp ├── FileSystem.cpp ├── FileSystem.h ├── IniFile.cpp ├── IniFile.hpp ├── ModLoaderCommon.vcxproj ├── ModLoaderCommon.vcxproj.filters ├── ReadMe.txt ├── TextConv.cpp ├── TextConv.hpp ├── Utils.hpp ├── stdafx.cpp ├── stdafx.h └── targetver.h /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | [*.{c,h,cpp,hpp}] 3 | indent_style=tab -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml 190 | *.db 191 | *.opendb 192 | /.vs/ 193 | *.dtbcache 194 | -------------------------------------------------------------------------------- /ModLoaderCommon.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35312.102 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModLoaderCommon", "ModLoaderCommon\ModLoaderCommon.vcxproj", "{EC0293F5-4BCF-46B2-8133-18CAEA141C5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|Win32 = Debug|Win32 12 | Release|Any CPU = Release|Any CPU 13 | Release|Win32 = Release|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Any CPU.ActiveCfg = Debug|Win32 17 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Win32.ActiveCfg = Debug|Win32 18 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Win32.Build.0 = Debug|Win32 19 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Any CPU.ActiveCfg = Release|Win32 20 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Win32.ActiveCfg = Release|Win32 21 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Win32.Build.0 = Release|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(ExtensibilityGlobals) = postSolution 27 | SolutionGuid = {1220F2E5-23F7-481B-8FC6-B01679392B62} 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /ModLoaderCommon/CodeParser.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * Code file parser. 4 | */ 5 | 6 | #include "stdafx.h" 7 | #include "CodeParser.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | using std::istream; 13 | using std::ifstream; 14 | using std::list; 15 | using std::string; 16 | #ifdef _MSC_VER 17 | using std::wstring; 18 | #endif /* _MSC_VER */ 19 | using std::vector; 20 | 21 | CodeParser::CodeParser(const string& filename) 22 | { 23 | readCodes(filename); 24 | } 25 | 26 | #ifdef _MSC_VER 27 | CodeParser::CodeParser(const wstring& filename) 28 | { 29 | readCodes(filename); 30 | } 31 | #endif /* _MSC_VER */ 32 | 33 | CodeParser::CodeParser(istream& f) 34 | { 35 | readCodes(f); 36 | } 37 | 38 | CodeParser::CodeParser() 39 | { 40 | } 41 | 42 | CodeParser::~CodeParser() 43 | { 44 | clear(); 45 | } 46 | 47 | void* CodeParser::GetAddress(const Code& code, valuetype* regs) 48 | { 49 | void* addr = code.address; 50 | if (addr < (void *)16) 51 | addr = ®s[(int)addr]; 52 | if (!code.pointer) 53 | return addr; 54 | addr = *(void **)addr; 55 | if (code.offsetcount == 0 || addr == nullptr) 56 | return addr; 57 | for (int i = 0; i < code.offsetcount - 1; i++) 58 | { 59 | addr = (void *)((uint32_t)addr + code.offsets[i]); 60 | addr = *(void **)addr; 61 | if (addr == nullptr) 62 | return nullptr; 63 | } 64 | addr = (void *)((uint32_t)addr + code.offsets[code.offsetcount - 1]); 65 | return addr; 66 | } 67 | 68 | #define addr_add(s) addr=(valuetype*)(s+(uint8_t*)addr) 69 | 70 | #define ifcode(size, op) \ 71 | do { \ 72 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 73 | { \ 74 | cond &= addr->u##size op it->value.u##size; \ 75 | addr_add(size/8); \ 76 | } \ 77 | if (cond) \ 78 | regnum = processCodeList_int(it->trueCodes, regnum); \ 79 | else \ 80 | regnum = processCodeList_int(it->falseCodes, regnum); \ 81 | } while (0) 82 | 83 | #define ifcodes(size, op) \ 84 | do { \ 85 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 86 | { \ 87 | cond &= addr->s##size op it->value.s##size; \ 88 | addr_add(size/8); \ 89 | } \ 90 | if (cond) \ 91 | regnum = processCodeList_int(it->trueCodes, regnum); \ 92 | else \ 93 | regnum = processCodeList_int(it->falseCodes, regnum); \ 94 | } while (0) 95 | 96 | #define ifcodef(op) \ 97 | do { \ 98 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 99 | { \ 100 | cond &= addr->f op it->value.f; \ 101 | addr_add(4); \ 102 | } \ 103 | if (cond) \ 104 | regnum = processCodeList_int(it->trueCodes, regnum); \ 105 | else \ 106 | regnum = processCodeList_int(it->falseCodes, regnum); \ 107 | } while (0) 108 | 109 | #define ifcodereg(size, op) \ 110 | do { \ 111 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 112 | { \ 113 | cond &= addr->u##size op regs[it->value.u8].u##size; \ 114 | addr_add(size/8); \ 115 | } \ 116 | if (cond) \ 117 | regnum = processCodeList_int(it->trueCodes, regnum); \ 118 | else \ 119 | regnum = processCodeList_int(it->falseCodes, regnum); \ 120 | } while (0) 121 | 122 | #define ifcoderegs(size, op) \ 123 | do { \ 124 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 125 | { \ 126 | cond &= addr->s##size op regs[it->value.u8].s##size; \ 127 | addr_add(size/8); \ 128 | } \ 129 | if (cond) \ 130 | regnum = processCodeList_int(it->trueCodes, regnum); \ 131 | else \ 132 | regnum = processCodeList_int(it->falseCodes, regnum); \ 133 | } while (0) 134 | 135 | #define ifcoderegf(op) \ 136 | do { \ 137 | for (uint32_t i = 0; i < it->repeatcount; i++) \ 138 | { \ 139 | cond &= addr->f op regs[it->value.u8].f; \ 140 | addr_add(4); \ 141 | } \ 142 | if (cond) \ 143 | regnum = processCodeList_int(it->trueCodes, regnum); \ 144 | else \ 145 | regnum = processCodeList_int(it->falseCodes, regnum); \ 146 | } while (0) 147 | 148 | inline BOOL WriteData(void* writeaddress, const void* data, SIZE_T datasize, SIZE_T* byteswritten) 149 | { 150 | return WriteProcessMemory(GetCurrentProcess(), writeaddress, data, datasize, byteswritten); 151 | } 152 | 153 | inline BOOL WriteData(void* writeaddress, const void* data, SIZE_T datasize) 154 | { 155 | return WriteData(writeaddress, data, datasize, nullptr); 156 | } 157 | 158 | template 159 | inline BOOL WriteData(T const* writeaddress, const T data, SIZE_T* byteswritten) 160 | { 161 | return WriteData((void*)writeaddress, (void*)&data, (SIZE_T)sizeof(data), byteswritten); 162 | } 163 | 164 | template 165 | inline BOOL WriteData(T const* writeaddress, const T data) 166 | { 167 | return WriteData(writeaddress, data, nullptr); 168 | } 169 | 170 | template 171 | inline BOOL WriteData(T* writeaddress, const T& data, SIZE_T* byteswritten) 172 | { 173 | return WriteData(writeaddress, &data, sizeof(data), byteswritten); 174 | } 175 | 176 | template 177 | inline BOOL WriteData(T* writeaddress, const T& data) 178 | { 179 | return WriteData(writeaddress, data, nullptr); 180 | } 181 | 182 | template 183 | inline BOOL WriteData(void* writeaddress, const T (&data)[N], SIZE_T* byteswritten) 184 | { 185 | return WriteData(writeaddress, data, sizeof(T) * N, byteswritten); 186 | } 187 | 188 | template 189 | inline BOOL WriteData(void* writeaddress, const T (&data)[N]) 190 | { 191 | return WriteData(writeaddress, data, nullptr); 192 | } 193 | 194 | /** 195 | * Write a repeated byte to an arbitrary address. 196 | * @param address [in] Address. 197 | * @param data [in] Byte to write. 198 | * @param count [in] Number of repetitions. 199 | * @param byteswritten [out, opt] Number of bytes written. 200 | * @return Nonzero on success; 0 on error (check GetLastError()). 201 | */ 202 | inline BOOL WriteData(void* address, const char data, int count, SIZE_T* byteswritten) 203 | { 204 | char* buf = new char[count]; 205 | memset(buf, data, count); 206 | int result = WriteData(address, buf, count, byteswritten); 207 | delete[] buf; 208 | return result; 209 | } 210 | 211 | /** 212 | * Write a repeated byte to an arbitrary address. 213 | * @param address [in] Address. 214 | * @param data [in] Byte to write. 215 | * @param count [in] Number of repetitions. 216 | * @return Nonzero on success; 0 on error (check GetLastError()). 217 | */ 218 | inline BOOL WriteData(void* address, char data, int count) 219 | { 220 | return WriteData(address, data, count, nullptr); 221 | } 222 | 223 | /** 224 | * Write a JMP instruction to an arbitrary address. 225 | * @param writeaddress Address to insert the JMP instruction. 226 | * @param funcaddress Address to JMP to. 227 | * @return Nonzero on success; 0 on error (check GetLastError()). 228 | */ 229 | static inline BOOL WriteJump(void* writeaddress, void* funcaddress) 230 | { 231 | uint8_t data[5]; 232 | data[0] = 0xE9; // JMP DWORD (relative) 233 | *(int32_t*)(data + 1) = (uint32_t)funcaddress - ((uint32_t)writeaddress + 5); 234 | return WriteData(writeaddress, data); 235 | } 236 | 237 | /** 238 | * Write a CALL instruction to an arbitrary address. 239 | * @param writeaddress Address to insert the CALL instruction. 240 | * @param funcaddress Address to CALL. 241 | * @return Nonzero on success; 0 on error (check GetLastError()). 242 | */ 243 | static inline BOOL WriteCall(void* writeaddress, void* funcaddress) 244 | { 245 | uint8_t data[5]; 246 | data[0] = 0xE8; // CALL DWORD (relative) 247 | *(int32_t*)(data + 1) = (uint32_t)funcaddress - ((uint32_t)writeaddress + 5); 248 | return WriteData(writeaddress, data); 249 | } 250 | 251 | template 252 | inline void writecode(T* address, uint32_t repeatcount, T data) 253 | { 254 | for (uint32_t i = 0; i < repeatcount; i++) 255 | { 256 | WriteData(address, data); 257 | ++address; 258 | } 259 | } 260 | 261 | template 262 | inline void addcode(T* address, uint32_t repeatcount, T data) 263 | { 264 | for (uint32_t i = 0; i < repeatcount; i++) 265 | { 266 | WriteData(address, (T)(*address + data)); 267 | ++address; 268 | } 269 | } 270 | 271 | template 272 | inline void subcode(T* address, uint32_t repeatcount, T data) 273 | { 274 | for (uint32_t i = 0; i < repeatcount; i++) 275 | { 276 | WriteData(address, (T)(*address - data)); 277 | ++address; 278 | } 279 | } 280 | 281 | template 282 | inline void mulcode(T* address, uint32_t repeatcount, T data) 283 | { 284 | for (uint32_t i = 0; i < repeatcount; i++) 285 | { 286 | WriteData(address, (T)(*address * data)); 287 | ++address; 288 | } 289 | } 290 | 291 | template 292 | inline void divcode(T* address, uint32_t repeatcount, T data) 293 | { 294 | for (uint32_t i = 0; i < repeatcount; i++) 295 | { 296 | WriteData(address, (T)(*address / data)); 297 | ++address; 298 | } 299 | } 300 | 301 | template 302 | inline void modcode(T* address, uint32_t repeatcount, T data) 303 | { 304 | for (uint32_t i = 0; i < repeatcount; i++) 305 | { 306 | WriteData(address, (T)(*address % data)); 307 | ++address; 308 | } 309 | } 310 | 311 | template 312 | inline void shlcode(T* address, uint32_t repeatcount, T data) 313 | { 314 | for (uint32_t i = 0; i < repeatcount; i++) 315 | { 316 | WriteData(address, (T)(*address << data)); 317 | ++address; 318 | } 319 | } 320 | 321 | template 322 | inline void shrcode(T* address, uint32_t repeatcount, T data) 323 | { 324 | for (uint32_t i = 0; i < repeatcount; i++) 325 | { 326 | WriteData(address, (T)(*address >> data)); 327 | ++address; 328 | } 329 | } 330 | 331 | template 332 | inline void andcode(T* address, uint32_t repeatcount, T data) 333 | { 334 | for (uint32_t i = 0; i < repeatcount; i++) 335 | { 336 | WriteData(address, (T)(*address & data)); 337 | ++address; 338 | } 339 | } 340 | 341 | template 342 | inline void orcode(T* address, uint32_t repeatcount, T data) 343 | { 344 | for (uint32_t i = 0; i < repeatcount; i++) 345 | { 346 | WriteData(address, (T)(*address | data)); 347 | ++address; 348 | } 349 | } 350 | 351 | template 352 | inline void xorcode(T* address, uint32_t repeatcount, T data) 353 | { 354 | for (uint32_t i = 0; i < repeatcount; i++) 355 | { 356 | WriteData(address, (T)(*address ^ data)); 357 | ++address; 358 | } 359 | } 360 | 361 | inline uint32_t _round(float num) 362 | { 363 | return (uint32_t)(num > 0 ? num + 0.5 : ceil(num - 0.5)); 364 | } 365 | 366 | /** 367 | * Process a code list. (Internal recursive function) 368 | * @param codes Code list. 369 | * @param regnum Next register number. 370 | * @return Last register number used. 371 | */ 372 | int CodeParser::processCodeList_int(const list& codes, int regnum) 373 | { 374 | for (auto it = codes.begin(); it != codes.end(); ++it) 375 | { 376 | if (it->newregs) 377 | regnum++; 378 | valuetype* regs = nullptr; 379 | if (regnum >= 0) 380 | regs = m_registers[regnum]; 381 | 382 | void* address = GetAddress(*it, regs); 383 | auto* addr = (valuetype*)address; 384 | 385 | if (it->type != ifkbkey && address == nullptr) 386 | { 387 | if (distance(it->falseCodes.begin(), it->falseCodes.end()) > 0) 388 | regnum = processCodeList_int(it->falseCodes, regnum); 389 | continue; 390 | } 391 | 392 | bool cond = true; 393 | switch (it->type) 394 | { 395 | case write8: 396 | writecode(&addr->u8, it->repeatcount, it->value.u8); 397 | break; 398 | case write16: 399 | writecode(&addr->u16, it->repeatcount, it->value.u16); 400 | break; 401 | case write32: 402 | case writefloat: 403 | writecode(&addr->u32, it->repeatcount, it->value.u32); 404 | break; 405 | case add8: 406 | addcode(&addr->u8, it->repeatcount, it->value.u8); 407 | break; 408 | case add16: 409 | addcode(&addr->u16, it->repeatcount, it->value.u16); 410 | break; 411 | case add32: 412 | addcode(&addr->u32, it->repeatcount, it->value.u32); 413 | break; 414 | case addfloat: 415 | addcode(&addr->f, it->repeatcount, it->value.f); 416 | break; 417 | case sub8: 418 | subcode(&addr->u8, it->repeatcount, it->value.u8); 419 | break; 420 | case sub16: 421 | subcode(&addr->u16, it->repeatcount, it->value.u16); 422 | break; 423 | case sub32: 424 | subcode(&addr->u32, it->repeatcount, it->value.u32); 425 | break; 426 | case subfloat: 427 | subcode(&addr->f, it->repeatcount, it->value.f); 428 | break; 429 | case mulu8: 430 | mulcode(&addr->u8, it->repeatcount, it->value.u8); 431 | break; 432 | case mulu16: 433 | mulcode(&addr->u16, it->repeatcount, it->value.u16); 434 | break; 435 | case mulu32: 436 | mulcode(&addr->u32, it->repeatcount, it->value.u32); 437 | break; 438 | case mulfloat: 439 | mulcode(&addr->f, it->repeatcount, it->value.f); 440 | break; 441 | case muls8: 442 | mulcode(&addr->s8, it->repeatcount, it->value.s8); 443 | break; 444 | case muls16: 445 | mulcode(&addr->s16, it->repeatcount, it->value.s16); 446 | break; 447 | case muls32: 448 | mulcode(&addr->s32, it->repeatcount, it->value.s32); 449 | break; 450 | case divu8: 451 | divcode(&addr->u8, it->repeatcount, it->value.u8); 452 | break; 453 | case divu16: 454 | divcode(&addr->u16, it->repeatcount, it->value.u16); 455 | break; 456 | case divu32: 457 | divcode(&addr->u32, it->repeatcount, it->value.u32); 458 | break; 459 | case divfloat: 460 | divcode(&addr->f, it->repeatcount, it->value.f); 461 | break; 462 | case divs8: 463 | divcode(&addr->s8, it->repeatcount, it->value.s8); 464 | break; 465 | case divs16: 466 | divcode(&addr->s16, it->repeatcount, it->value.s16); 467 | break; 468 | case divs32: 469 | divcode(&addr->s32, it->repeatcount, it->value.s32); 470 | break; 471 | case modu8: 472 | modcode(&addr->u8, it->repeatcount, it->value.u8); 473 | break; 474 | case modu16: 475 | modcode(&addr->u16, it->repeatcount, it->value.u16); 476 | break; 477 | case modu32: 478 | modcode(&addr->u32, it->repeatcount, it->value.u32); 479 | break; 480 | case mods8: 481 | modcode(&addr->s8, it->repeatcount, it->value.s8); 482 | break; 483 | case mods16: 484 | modcode(&addr->s16, it->repeatcount, it->value.s16); 485 | break; 486 | case mods32: 487 | modcode(&addr->s32, it->repeatcount, it->value.s32); 488 | break; 489 | case shl8: 490 | shlcode(&addr->u8, it->repeatcount, it->value.u8); 491 | break; 492 | case shl16: 493 | shlcode(&addr->u16, it->repeatcount, it->value.u16); 494 | break; 495 | case shl32: 496 | shlcode(&addr->u32, it->repeatcount, it->value.u32); 497 | break; 498 | case shru8: 499 | shrcode(&addr->u8, it->repeatcount, it->value.u8); 500 | break; 501 | case shru16: 502 | shrcode(&addr->u16, it->repeatcount, it->value.u16); 503 | break; 504 | case shru32: 505 | shrcode(&addr->u32, it->repeatcount, it->value.u32); 506 | break; 507 | case shrs8: 508 | shrcode(&addr->s8, it->repeatcount, it->value.s8); 509 | break; 510 | case shrs16: 511 | shrcode(&addr->s16, it->repeatcount, it->value.s16); 512 | break; 513 | case shrs32: 514 | shrcode(&addr->s32, it->repeatcount, it->value.s32); 515 | break; 516 | case rol8: 517 | for (uint32_t i = 0; i < it->repeatcount; i++) 518 | { 519 | WriteData(&addr->u8, (uint8_t)(_rotl8(addr->u8, it->value.u8))); 520 | addr_add(1); 521 | } 522 | break; 523 | case rol16: 524 | for (uint32_t i = 0; i < it->repeatcount; i++) 525 | { 526 | WriteData(&addr->u16, (uint16_t)(_rotl16(addr->u16, it->value.u8))); 527 | addr_add(2); 528 | } 529 | break; 530 | case rol32: 531 | for (uint32_t i = 0; i < it->repeatcount; i++) 532 | { 533 | WriteData(&addr->u32, (uint32_t)(_rotl(addr->u32, it->value.s32))); 534 | addr_add(4); 535 | } 536 | break; 537 | case ror8: 538 | for (uint32_t i = 0; i < it->repeatcount; i++) 539 | { 540 | WriteData(&addr->u8, (uint8_t)(_rotr8(addr->u8, it->value.u8))); 541 | addr_add(1); 542 | } 543 | break; 544 | case ror16: 545 | for (uint32_t i = 0; i < it->repeatcount; i++) 546 | { 547 | WriteData(&addr->u16, (uint16_t)(_rotr16(addr->u16, it->value.u8))); 548 | addr_add(2); 549 | } 550 | break; 551 | case ror32: 552 | for (uint32_t i = 0; i < it->repeatcount; i++) 553 | { 554 | WriteData(&addr->u32, (uint32_t)(_rotr(addr->u32, it->value.s32))); 555 | addr_add(4); 556 | } 557 | break; 558 | case and8: 559 | andcode(&addr->u8, it->repeatcount, it->value.u8); 560 | break; 561 | case and16: 562 | andcode(&addr->u16, it->repeatcount, it->value.u16); 563 | break; 564 | case and32: 565 | andcode(&addr->u32, it->repeatcount, it->value.u32); 566 | break; 567 | case or8: 568 | orcode(&addr->u8, it->repeatcount, it->value.u8); 569 | break; 570 | case or16: 571 | orcode(&addr->u16, it->repeatcount, it->value.u16); 572 | break; 573 | case or32: 574 | orcode(&addr->u32, it->repeatcount, it->value.u32); 575 | break; 576 | case xor8: 577 | xorcode(&addr->u8, it->repeatcount, it->value.u8); 578 | break; 579 | case xor16: 580 | xorcode(&addr->u16, it->repeatcount, it->value.u16); 581 | break; 582 | case xor32: 583 | xorcode(&addr->u32, it->repeatcount, it->value.u32); 584 | break; 585 | case writenop: 586 | WriteData(&addr->u8, 0x90u, it->value.u32); 587 | break; 588 | case writejump: 589 | WriteJump(addr, (void*)it->value.u32); 590 | break; 591 | case writecall: 592 | WriteCall(addr, (void*)it->value.u32); 593 | break; 594 | case writeoff: 595 | WriteData(&addr->u32, it->repeatcount, it->value.u32 + offset); 596 | break; 597 | case ifeq8: 598 | ifcode(8, ==); 599 | break; 600 | case ifeq16: 601 | ifcode(16, ==); 602 | break; 603 | case ifeq32: 604 | ifcode(32, ==); 605 | break; 606 | case ifeqfloat: 607 | ifcodef(==); 608 | break; 609 | case ifne8: 610 | ifcode(8, !=); 611 | break; 612 | case ifne16: 613 | ifcode(16, !=); 614 | break; 615 | case ifne32: 616 | ifcode(32, !=); 617 | break; 618 | case ifnefloat: 619 | ifcodef(!=); 620 | break; 621 | case ifltu8: 622 | ifcode(8, <); 623 | break; 624 | case ifltu16: 625 | ifcode(16, <); 626 | break; 627 | case ifltu32: 628 | ifcode(32, <); 629 | break; 630 | case ifltfloat: 631 | ifcodef(<); 632 | break; 633 | case iflts8: 634 | ifcodes(8, <); 635 | break; 636 | case iflts16: 637 | ifcodes(16, <); 638 | break; 639 | case iflts32: 640 | ifcodes(32, <); 641 | break; 642 | case ifltequ8: 643 | ifcode(8, <=); 644 | break; 645 | case ifltequ16: 646 | ifcode(16, <=); 647 | break; 648 | case ifltequ32: 649 | ifcode(32, <=); 650 | break; 651 | case iflteqfloat: 652 | ifcodef(<=); 653 | break; 654 | case iflteqs8: 655 | ifcodes(8, <=); 656 | break; 657 | case iflteqs16: 658 | ifcodes(16, <=); 659 | break; 660 | case iflteqs32: 661 | ifcodes(32, <=); 662 | break; 663 | case ifgtu8: 664 | ifcode(8, >); 665 | break; 666 | case ifgtu16: 667 | ifcode(16, >); 668 | break; 669 | case ifgtu32: 670 | ifcode(32, >); 671 | break; 672 | case ifgtfloat: 673 | ifcodef(>); 674 | break; 675 | case ifgts8: 676 | ifcodes(8, >); 677 | break; 678 | case ifgts16: 679 | ifcodes(16, >); 680 | break; 681 | case ifgts32: 682 | ifcodes(32, >); 683 | break; 684 | case ifgtequ8: 685 | ifcode(8, >=); 686 | break; 687 | case ifgtequ16: 688 | ifcode(16, >=); 689 | break; 690 | case ifgtequ32: 691 | ifcode(32, >=); 692 | break; 693 | case ifgteqfloat: 694 | ifcodef(>=); 695 | break; 696 | case ifgteqs8: 697 | ifcodes(8, >=); 698 | break; 699 | case ifgteqs16: 700 | ifcodes(16, >=); 701 | break; 702 | case ifgteqs32: 703 | ifcodes(32, >=); 704 | break; 705 | case ifmask8: 706 | for (uint32_t i = 0; i < it->repeatcount; i++) 707 | { 708 | cond &= (addr->u8 & it->value.u8) == it->value.u8; 709 | addr_add(1); 710 | } 711 | if (cond) 712 | { 713 | regnum = processCodeList_int(it->trueCodes, regnum); 714 | } 715 | else 716 | { 717 | regnum = processCodeList_int(it->falseCodes, regnum); 718 | } 719 | break; 720 | case ifmask16: 721 | for (uint32_t i = 0; i < it->repeatcount; i++) 722 | { 723 | cond &= (addr->u16 & it->value.u16) == it->value.u16; 724 | addr_add(2); 725 | } 726 | if (cond) 727 | { 728 | regnum = processCodeList_int(it->trueCodes, regnum); 729 | } 730 | else 731 | { 732 | regnum = processCodeList_int(it->falseCodes, regnum); 733 | } 734 | break; 735 | case ifmask32: 736 | for (uint32_t i = 0; i < it->repeatcount; i++) 737 | { 738 | cond &= (addr->u32 & it->value.u32) == it->value.u32; 739 | addr_add(4); 740 | } 741 | if (cond) 742 | { 743 | regnum = processCodeList_int(it->trueCodes, regnum); 744 | } 745 | else 746 | { 747 | regnum = processCodeList_int(it->falseCodes, regnum); 748 | } 749 | break; 750 | case ifkbkey: 751 | if (GetAsyncKeyState(it->value.s32)) 752 | { 753 | regnum = processCodeList_int(it->trueCodes, regnum); 754 | } 755 | else 756 | { 757 | regnum = processCodeList_int(it->falseCodes, regnum); 758 | } 759 | break; 760 | case readreg8: 761 | for (uint32_t i = 0; i < it->repeatcount; i++) 762 | { 763 | regs[it->value.u8 + i].u8 = addr->u8; 764 | addr_add(1); 765 | } 766 | break; 767 | case readreg16: 768 | for (uint32_t i = 0; i < it->repeatcount; i++) 769 | { 770 | regs[it->value.u8 + i].u16 = addr->u16; 771 | addr_add(2); 772 | } 773 | break; 774 | case readreg32: 775 | for (uint32_t i = 0; i < it->repeatcount; i++) 776 | { 777 | regs[it->value.u8 + i].u32 = addr->u32; 778 | addr_add(4); 779 | } 780 | break; 781 | case writereg8: 782 | writecode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 783 | break; 784 | case writereg16: 785 | writecode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 786 | break; 787 | case writereg32: 788 | writecode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 789 | break; 790 | case addreg8: 791 | addcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 792 | break; 793 | case addreg16: 794 | addcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 795 | break; 796 | case addreg32: 797 | addcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 798 | break; 799 | case addregfloat: 800 | addcode(&addr->f, it->repeatcount, regs[it->value.u8].f); 801 | break; 802 | case subreg8: 803 | subcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 804 | break; 805 | case subreg16: 806 | subcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 807 | break; 808 | case subreg32: 809 | subcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 810 | break; 811 | case subregfloat: 812 | subcode(&addr->f, it->repeatcount, regs[it->value.u8].f); 813 | break; 814 | case mulregu8: 815 | mulcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 816 | break; 817 | case mulregu16: 818 | mulcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 819 | break; 820 | case mulregu32: 821 | mulcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 822 | break; 823 | case mulregfloat: 824 | mulcode(&addr->f, it->repeatcount, regs[it->value.u8].f); 825 | break; 826 | case mulregs8: 827 | mulcode(&addr->s8, it->repeatcount, regs[it->value.u8].s8); 828 | break; 829 | case mulregs16: 830 | mulcode(&addr->s16, it->repeatcount, regs[it->value.u8].s16); 831 | break; 832 | case mulregs32: 833 | mulcode(&addr->s32, it->repeatcount, regs[it->value.u8].s32); 834 | break; 835 | case divregu8: 836 | divcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 837 | break; 838 | case divregu16: 839 | divcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 840 | break; 841 | case divregu32: 842 | divcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 843 | break; 844 | case divregfloat: 845 | divcode(&addr->f, it->repeatcount, regs[it->value.u8].f); 846 | break; 847 | case divregs8: 848 | divcode(&addr->s8, it->repeatcount, regs[it->value.u8].s8); 849 | break; 850 | case divregs16: 851 | divcode(&addr->s16, it->repeatcount, regs[it->value.u8].s16); 852 | break; 853 | case divregs32: 854 | divcode(&addr->s32, it->repeatcount, regs[it->value.u8].s32); 855 | break; 856 | case modregu8: 857 | modcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 858 | break; 859 | case modregu16: 860 | modcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 861 | break; 862 | case modregu32: 863 | modcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 864 | break; 865 | case modregs8: 866 | modcode(&addr->s8, it->repeatcount, regs[it->value.u8].s8); 867 | break; 868 | case modregs16: 869 | modcode(&addr->s16, it->repeatcount, regs[it->value.u8].s16); 870 | break; 871 | case modregs32: 872 | modcode(&addr->s32, it->repeatcount, regs[it->value.u8].s32); 873 | break; 874 | case shlreg8: 875 | shlcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 876 | break; 877 | case shlreg16: 878 | shlcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 879 | break; 880 | case shlreg32: 881 | shlcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 882 | break; 883 | case shrregu8: 884 | shrcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 885 | break; 886 | case shrregu16: 887 | shrcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 888 | break; 889 | case shrregu32: 890 | shrcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 891 | break; 892 | case shrregs8: 893 | shrcode(&addr->s8, it->repeatcount, regs[it->value.u8].s8); 894 | break; 895 | case shrregs16: 896 | shrcode(&addr->s16, it->repeatcount, regs[it->value.u8].s16); 897 | break; 898 | case shrregs32: 899 | shrcode(&addr->s32, it->repeatcount, regs[it->value.u8].s32); 900 | break; 901 | case rolreg8: 902 | for (uint32_t i = 0; i < it->repeatcount; i++) 903 | { 904 | WriteData(&addr->u8, (uint8_t)(_rotl8(addr->u8, regs[it->value.u8].u8))); 905 | addr_add(1); 906 | } 907 | break; 908 | case rolreg16: 909 | for (uint32_t i = 0; i < it->repeatcount; i++) 910 | { 911 | WriteData(&addr->u16, (uint16_t)(_rotl16(addr->u16, regs[it->value.u8].u8))); 912 | addr_add(2); 913 | } 914 | break; 915 | case rolreg32: 916 | for (uint32_t i = 0; i < it->repeatcount; i++) 917 | { 918 | WriteData(&addr->u32, (uint32_t)(_rotl(addr->u32, regs[it->value.u8].s32))); 919 | addr_add(4); 920 | } 921 | break; 922 | case rorreg8: 923 | for (uint32_t i = 0; i < it->repeatcount; i++) 924 | { 925 | WriteData(&addr->u8, (uint8_t)(_rotr8(addr->u8, regs[it->value.u8].u8))); 926 | addr_add(1); 927 | } 928 | break; 929 | case rorreg16: 930 | for (uint32_t i = 0; i < it->repeatcount; i++) 931 | { 932 | WriteData(&addr->u16, (uint16_t)(_rotr16(addr->u16, regs[it->value.u8].u8))); 933 | addr_add(2); 934 | } 935 | break; 936 | case rorreg32: 937 | for (uint32_t i = 0; i < it->repeatcount; i++) 938 | { 939 | WriteData(&addr->u32, (uint32_t)(_rotr(addr->u32, regs[it->value.u8].s32))); 940 | addr_add(4); 941 | } 942 | break; 943 | case andreg8: 944 | andcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 945 | break; 946 | case andreg16: 947 | andcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 948 | break; 949 | case andreg32: 950 | andcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 951 | break; 952 | case orreg8: 953 | orcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 954 | break; 955 | case orreg16: 956 | orcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 957 | break; 958 | case orreg32: 959 | orcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 960 | break; 961 | case xorreg8: 962 | xorcode(&addr->u8, it->repeatcount, regs[it->value.u8].u8); 963 | break; 964 | case xorreg16: 965 | xorcode(&addr->u16, it->repeatcount, regs[it->value.u8].u16); 966 | break; 967 | case xorreg32: 968 | xorcode(&addr->u32, it->repeatcount, regs[it->value.u8].u32); 969 | break; 970 | case writenopreg: 971 | WriteData(&addr->u8, 0x90u, regs[it->value.u8].u32); 972 | break; 973 | case ifeqreg8: 974 | ifcodereg(8, ==); 975 | break; 976 | case ifeqreg16: 977 | ifcodereg(16, ==); 978 | break; 979 | case ifeqreg32: 980 | ifcodereg(32, ==); 981 | break; 982 | case ifeqregfloat: 983 | ifcoderegf(==); 984 | break; 985 | case ifnereg8: 986 | ifcodereg(8, !=); 987 | break; 988 | case ifnereg16: 989 | ifcodereg(16, !=); 990 | break; 991 | case ifnereg32: 992 | ifcodereg(32, !=); 993 | break; 994 | case ifneregfloat: 995 | ifcoderegf(!=); 996 | break; 997 | case ifltregu8: 998 | ifcodereg(8, <); 999 | break; 1000 | case ifltregu16: 1001 | ifcodereg(16, <); 1002 | break; 1003 | case ifltregu32: 1004 | ifcodereg(32, <); 1005 | break; 1006 | case ifltregfloat: 1007 | ifcoderegf(<); 1008 | break; 1009 | case ifltregs8: 1010 | ifcoderegs(8, <); 1011 | break; 1012 | case ifltregs16: 1013 | ifcoderegs(16, <); 1014 | break; 1015 | case ifltregs32: 1016 | ifcoderegs(32, <); 1017 | break; 1018 | case iflteqregu8: 1019 | ifcodereg(8, <=); 1020 | break; 1021 | case iflteqregu16: 1022 | ifcodereg(16, <=); 1023 | break; 1024 | case iflteqregu32: 1025 | ifcodereg(32, <=); 1026 | break; 1027 | case iflteqregfloat: 1028 | ifcoderegf(<=); 1029 | break; 1030 | case iflteqregs8: 1031 | ifcoderegs(8, <=); 1032 | break; 1033 | case iflteqregs16: 1034 | ifcoderegs(16, <=); 1035 | break; 1036 | case iflteqregs32: 1037 | ifcoderegs(32, <=); 1038 | break; 1039 | case ifgtregu8: 1040 | ifcodereg(8, >); 1041 | break; 1042 | case ifgtregu16: 1043 | ifcodereg(16, >); 1044 | break; 1045 | case ifgtregu32: 1046 | ifcodereg(32, >); 1047 | break; 1048 | case ifgtregfloat: 1049 | ifcoderegf(>); 1050 | break; 1051 | case ifgtregs8: 1052 | ifcoderegs(8, >); 1053 | break; 1054 | case ifgtregs16: 1055 | ifcoderegs(16, >); 1056 | break; 1057 | case ifgtregs32: 1058 | ifcoderegs(32, >); 1059 | break; 1060 | case ifgteqregu8: 1061 | ifcodereg(8, >=); 1062 | break; 1063 | case ifgteqregu16: 1064 | ifcodereg(16, >=); 1065 | break; 1066 | case ifgteqregu32: 1067 | ifcodereg(32, >=); 1068 | break; 1069 | case ifgteqregfloat: 1070 | ifcoderegf(>=); 1071 | break; 1072 | case ifgteqregs8: 1073 | ifcoderegs(8, >=); 1074 | break; 1075 | case ifgteqregs16: 1076 | ifcoderegs(16, >=); 1077 | break; 1078 | case ifgteqregs32: 1079 | ifcoderegs(32, >=); 1080 | break; 1081 | case ifmaskreg8: 1082 | for (uint32_t i = 0; i < it->repeatcount; i++) 1083 | { 1084 | cond &= (addr->u8 & it->value.u8) == regs[it->value.u8].u8; 1085 | addr_add(1); 1086 | } 1087 | if (cond) 1088 | { 1089 | regnum = processCodeList_int(it->trueCodes, regnum); 1090 | } 1091 | else 1092 | { 1093 | regnum = processCodeList_int(it->falseCodes, regnum); 1094 | } 1095 | break; 1096 | case ifmaskreg16: 1097 | for (uint32_t i = 0; i < it->repeatcount; i++) 1098 | { 1099 | cond &= (addr->u16 & it->value.u16) == regs[it->value.u8].u16; 1100 | addr_add(2); 1101 | } 1102 | if (cond) 1103 | { 1104 | regnum = processCodeList_int(it->trueCodes, regnum); 1105 | } 1106 | else 1107 | { 1108 | regnum = processCodeList_int(it->falseCodes, regnum); 1109 | } 1110 | break; 1111 | case ifmaskreg32: 1112 | for (uint32_t i = 0; i < it->repeatcount; i++) 1113 | { 1114 | cond &= (addr->u32 & it->value.u32) == regs[it->value.u8].u32; 1115 | addr_add(4); 1116 | } 1117 | if (cond) 1118 | { 1119 | regnum = processCodeList_int(it->trueCodes, regnum); 1120 | } 1121 | else 1122 | { 1123 | regnum = processCodeList_int(it->falseCodes, regnum); 1124 | } 1125 | break; 1126 | case s8tos32: 1127 | addr->s32 = addr->s8; 1128 | break; 1129 | case s16tos32: 1130 | addr->s32 = addr->s16; 1131 | break; 1132 | case s32tofloat: 1133 | for (uint32_t i = 0; i < it->repeatcount; i++) 1134 | { 1135 | addr->f = (float)addr->s32++; 1136 | addr_add(4); 1137 | } 1138 | break; 1139 | case u32tofloat: 1140 | for (uint32_t i = 0; i < it->repeatcount; i++) 1141 | { 1142 | addr->f = (float)addr->u32++; 1143 | addr_add(4); 1144 | } 1145 | break; 1146 | case floattos32: 1147 | for (uint32_t i = 0; i < it->repeatcount; i++) 1148 | { 1149 | addr->s32 = _round(addr->f++); 1150 | addr_add(4); 1151 | } 1152 | break; 1153 | case floattou32: 1154 | for (uint32_t i = 0; i < it->repeatcount; i++) 1155 | { 1156 | addr->u32 = _round(addr->f++); 1157 | addr_add(4); 1158 | } 1159 | break; 1160 | default: 1161 | // Invalid opcode. 1162 | // TODO: Show an error message. 1163 | break; 1164 | } 1165 | } 1166 | 1167 | return regnum; 1168 | } 1169 | 1170 | /** 1171 | * Process the code list. 1172 | */ 1173 | void CodeParser::processCodeList() 1174 | { 1175 | processCodeList_int(m_codes, -1); 1176 | } 1177 | 1178 | /** 1179 | * Sets a base offset for all codes. 1180 | * Call this before loading the code list. 1181 | */ 1182 | void CodeParser::setOffset(ptrdiff_t offset) 1183 | { 1184 | this->offset = offset; 1185 | } 1186 | 1187 | /** 1188 | * Read codes from a code file. 1189 | * This will clear all loaded codes before loading new codes. 1190 | * @param filename Code file. 1191 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 1192 | */ 1193 | int CodeParser::readCodes(const string& filename) 1194 | { 1195 | clear(); 1196 | ifstream stream(filename, ifstream::binary); 1197 | if (!stream.is_open()) 1198 | return -ENOENT; 1199 | 1200 | return readCodes(stream); 1201 | } 1202 | 1203 | #ifdef _MSC_VER 1204 | /** 1205 | * Read codes from a code file. 1206 | * This will clear all loaded codes before loading new codes. 1207 | * @param filename Code file. 1208 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 1209 | */ 1210 | int CodeParser::readCodes(const wstring& filename) 1211 | { 1212 | clear(); 1213 | ifstream stream(filename, ifstream::binary); 1214 | if (!stream.is_open()) 1215 | return -ENOENT; 1216 | 1217 | return readCodes(stream); 1218 | } 1219 | #endif /* _MSC_VER */ 1220 | 1221 | /** 1222 | * Read codes from a code file. 1223 | * @param stream Code file. 1224 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 1225 | */ 1226 | int CodeParser::readCodes(istream& stream) 1227 | { 1228 | // Clear the codes first. 1229 | clear(); 1230 | 1231 | // Check for the magic number. 1232 | static const char codemagic[6] = { 'c', 'o', 'd', 'e', 'v', '5' }; 1233 | char buf[sizeof(codemagic)]; 1234 | stream.read(buf, sizeof(buf)); 1235 | if (memcmp(buf, codemagic, sizeof(codemagic)) != 0) 1236 | return -EINVAL; 1237 | 1238 | // Get the number of codes defined in the file header. 1239 | // This might not be equal to the number of codes in the file. 1240 | int codecount_header; 1241 | stream.read((char*)&codecount_header, sizeof(codecount_header)); 1242 | 1243 | // Read the codes. 1244 | // TODO: Check for codeeof? 1245 | readCodes_int(stream, m_codes); 1246 | 1247 | // Return the number of codes read. 1248 | return (int)m_codes.size(); 1249 | } 1250 | 1251 | /** 1252 | * Read codes from a code file. 1253 | * Internal recursive function; used for internal code lists. 1254 | * @param stream [in] Code file. 1255 | * @param clist [out] Code list. 1256 | * @return 0 when completed; codeeof on EOF; _else or endif while processing. 1257 | */ 1258 | unsigned char CodeParser::readCodes_int(istream& stream, list& clist) 1259 | { 1260 | while (true) 1261 | { 1262 | uint8_t t = stream.get(); 1263 | if (t == codeeof || t == _else || t == endif) 1264 | return t; 1265 | 1266 | Code code = {}; 1267 | if (t == newregs) 1268 | { 1269 | code.newregs = true; 1270 | auto regs = new valuetype[16]; 1271 | memset(regs, 0, sizeof(valuetype) * 16); 1272 | m_registers.push_back(regs); 1273 | // FIXME: continue; instead? 1274 | t = stream.get(); 1275 | } 1276 | 1277 | code.type = (CodeType)t; 1278 | uintptr_t addr; 1279 | stream.read((char *)&addr, sizeof(uintptr_t)); 1280 | code.pointer = (addr & 0x80000000u) == 0x80000000u; 1281 | addr &= 0x7FFFFFFF; 1282 | if (addr >= 16) 1283 | addr += offset; 1284 | code.address = (void*)addr; 1285 | if (code.pointer) 1286 | { 1287 | code.offsetcount = stream.get(); 1288 | code.offsets = new int[code.offsetcount]; 1289 | for (int i = 0; i < code.offsetcount; i++) 1290 | { 1291 | stream.read((char*)& code.offsets[i], sizeof(int32_t)); 1292 | } 1293 | } 1294 | 1295 | stream.read((char *)&code.value, sizeof(code.value)); 1296 | stream.read((char *)&code.repeatcount, sizeof(uint32_t)); 1297 | if ((code.type >= ifeq8 && code.type <= ifkbkey) || 1298 | (code.type >= ifeqreg8 && code.type <= ifmaskreg32)) 1299 | { 1300 | switch (readCodes_int(stream, code.trueCodes)) 1301 | { 1302 | case _else: 1303 | if (readCodes_int(stream, code.falseCodes) == codeeof) 1304 | { 1305 | return codeeof; 1306 | } 1307 | break; 1308 | case codeeof: 1309 | return codeeof; 1310 | } 1311 | } 1312 | 1313 | clist.push_back(code); 1314 | } 1315 | 1316 | // Finished parsing codes. 1317 | return 0; 1318 | } 1319 | 1320 | /** 1321 | * Clear the loaded codes. 1322 | */ 1323 | void CodeParser::clear() 1324 | { 1325 | // m_code doesn't have any allocated memory. 1326 | m_codes.clear(); 1327 | 1328 | // m_registers does have allocated memory. 1329 | for (auto& m_register : m_registers) 1330 | { 1331 | // Allocated using new valuetype[16]; 1332 | delete[] m_register; 1333 | } 1334 | 1335 | m_registers.clear(); 1336 | } 1337 | -------------------------------------------------------------------------------- /ModLoaderCommon/CodeParser.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * Code file parser. 4 | */ 5 | 6 | #ifndef CODEPARSER_HPP 7 | #define CODEPARSER_HPP 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class CodeParser 16 | { 17 | public: 18 | CodeParser(const std::string& filename); 19 | #ifdef _MSC_VER 20 | CodeParser(const std::wstring& filename); 21 | #endif /* _MSC VER */ 22 | CodeParser(std::istream& f); 23 | CodeParser(); 24 | ~CodeParser(); 25 | 26 | // Disable the copy and assign constructors. 27 | CodeParser(const CodeParser&) = delete; 28 | CodeParser& operator=(const CodeParser&) = delete; 29 | 30 | /** 31 | * Opcodes for the cheat code system. 32 | */ 33 | enum CodeType : uint8_t 34 | { 35 | write8, write16, write32, writefloat, 36 | add8, add16, add32, addfloat, 37 | sub8, sub16, sub32, subfloat, 38 | mulu8, mulu16, mulu32, mulfloat, 39 | muls8, muls16, muls32, 40 | divu8, divu16, divu32, divfloat, 41 | divs8, divs16, divs32, 42 | modu8, modu16, modu32, 43 | mods8, mods16, mods32, 44 | shl8, shl16, shl32, 45 | shru8, shru16, shru32, 46 | shrs8, shrs16, shrs32, 47 | rol8, rol16, rol32, 48 | ror8, ror16, ror32, 49 | and8, and16, and32, 50 | or8, or16, or32, 51 | xor8, xor16, xor32, 52 | writenop, 53 | writejump, 54 | writecall, 55 | writeoff, 56 | ifeq8, ifeq16, ifeq32, ifeqfloat, 57 | ifne8, ifne16, ifne32, ifnefloat, 58 | ifltu8, ifltu16, ifltu32, ifltfloat, 59 | iflts8, iflts16, iflts32, 60 | ifltequ8, ifltequ16, ifltequ32, iflteqfloat, 61 | iflteqs8, iflteqs16, iflteqs32, 62 | ifgtu8, ifgtu16, ifgtu32, ifgtfloat, 63 | ifgts8, ifgts16, ifgts32, 64 | ifgtequ8, ifgtequ16, ifgtequ32, ifgteqfloat, 65 | ifgteqs8, ifgteqs16, ifgteqs32, 66 | ifmask8, ifmask16, ifmask32, 67 | ifkbkey, 68 | readreg8, readreg16, readreg32, 69 | writereg8, writereg16, writereg32, 70 | addreg8, addreg16, addreg32, addregfloat, 71 | subreg8, subreg16, subreg32, subregfloat, 72 | mulregu8, mulregu16, mulregu32, mulregfloat, 73 | mulregs8, mulregs16, mulregs32, 74 | divregu8, divregu16, divregu32, divregfloat, 75 | divregs8, divregs16, divregs32, 76 | modregu8, modregu16, modregu32, 77 | modregs8, modregs16, modregs32, 78 | shlreg8, shlreg16, shlreg32, 79 | shrregu8, shrregu16, shrregu32, 80 | shrregs8, shrregs16, shrregs32, 81 | rolreg8, rolreg16, rolreg32, 82 | rorreg8, rorreg16, rorreg32, 83 | andreg8, andreg16, andreg32, 84 | orreg8, orreg16, orreg32, 85 | xorreg8, xorreg16, xorreg32, 86 | writenopreg, 87 | ifeqreg8, ifeqreg16, ifeqreg32, ifeqregfloat, 88 | ifnereg8, ifnereg16, ifnereg32, ifneregfloat, 89 | ifltregu8, ifltregu16, ifltregu32, ifltregfloat, 90 | ifltregs8, ifltregs16, ifltregs32, 91 | iflteqregu8, iflteqregu16, iflteqregu32, iflteqregfloat, 92 | iflteqregs8, iflteqregs16, iflteqregs32, 93 | ifgtregu8, ifgtregu16, ifgtregu32, ifgtregfloat, 94 | ifgtregs8, ifgtregs16, ifgtregs32, 95 | ifgteqregu8, ifgteqregu16, ifgteqregu32, ifgteqregfloat, 96 | ifgteqregs8, ifgteqregs16, ifgteqregs32, 97 | ifmaskreg8, ifmaskreg16, ifmaskreg32, 98 | s8tos32, s16tos32, s32tofloat, u32tofloat, floattos32, floattou32, 99 | _else, 100 | endif, 101 | newregs, 102 | 103 | // End of file 104 | codeeof = 0xFF 105 | }; 106 | 107 | /** 108 | * Union of all possible types of values. 109 | */ 110 | union valuetype 111 | { 112 | uint32_t u32; 113 | int32_t s32; 114 | uint16_t u16; 115 | int16_t s16; 116 | uint8_t u8; 117 | int8_t s8; 118 | float f; 119 | }; 120 | 121 | /** 122 | * Code struct. 123 | */ 124 | struct Code 125 | { 126 | bool newregs; 127 | CodeType type; 128 | void* address; 129 | bool pointer; 130 | int offsetcount; 131 | int32_t* offsets; 132 | valuetype value; 133 | uint32_t repeatcount; 134 | std::list trueCodes; 135 | std::list falseCodes; 136 | }; 137 | 138 | protected: 139 | static void* GetAddress(const Code& code, valuetype* regs); 140 | 141 | /** 142 | * Process a code list. (Internal recursive function) 143 | * @param codes Code list. 144 | * @param regnum Next register number. 145 | * @return Last register number used. 146 | */ 147 | int processCodeList_int(const std::list& codes, int regnum); 148 | 149 | public: 150 | /** 151 | * Process the code list. 152 | */ 153 | void processCodeList(); 154 | /** 155 | * Sets a base offset for all codes. 156 | * Call this before loading the code list. 157 | */ 158 | void setOffset(ptrdiff_t offset); 159 | 160 | public: 161 | /** 162 | * Read codes from a code file. 163 | * This will clear all loaded codes before loading new codes. 164 | * @param filename Code file. 165 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 166 | */ 167 | int readCodes(const std::string& filename); 168 | 169 | #ifdef _MSC_VER 170 | /** 171 | * Read codes from a code file. 172 | * This will clear all loaded codes before loading new codes. 173 | * @param filename Code file. 174 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 175 | */ 176 | int readCodes(const std::wstring& filename); 177 | #endif /* _MSC_VER */ 178 | 179 | /** 180 | * Read codes from a code file. 181 | * This will clear all loaded codes before loading new codes. 182 | * @param stream Code file. 183 | * @return Number of codes read on success; -ENOENT if stream is closed; -EINVAL if file is invalid. 184 | */ 185 | int readCodes(std::istream& stream); 186 | 187 | protected: 188 | /** 189 | * Read codes from a code file. 190 | * Internal recursive function; used for internal code lists. 191 | * @param stream [in] Code file. 192 | * @param clist [out] Code list. 193 | * @return 0 when completed; codeeof on EOF; _else or endif while processing. 194 | */ 195 | unsigned char readCodes_int(std::istream& stream, std::list& clist); 196 | 197 | /** 198 | * Clear the loaded codes. 199 | */ 200 | void clear(); 201 | 202 | protected: 203 | /** 204 | * Register sets. 205 | * Each element is a pointer to 16 valuetypes. 206 | */ 207 | std::vector m_registers; 208 | 209 | /** 210 | * All loaded codes. 211 | */ 212 | std::list m_codes; 213 | 214 | /** 215 | * Offset to be added to each code's address. 216 | */ 217 | ptrdiff_t offset = 0; 218 | }; 219 | 220 | #endif /* CODEPARSER_HPP */ 221 | -------------------------------------------------------------------------------- /ModLoaderCommon/FileSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | #include "FileSystem.h" 6 | 7 | using std::string; 8 | using std::wstring; 9 | 10 | bool Exists(const wstring& path) 11 | { 12 | return GetFileAttributesW(path.c_str()) != INVALID_FILE_ATTRIBUTES; 13 | } 14 | 15 | bool Exists(const string& path) 16 | { 17 | return GetFileAttributesA(path.c_str()) != INVALID_FILE_ATTRIBUTES; 18 | } 19 | 20 | bool IsDirectory(const wstring& path) 21 | { 22 | const DWORD attrs = GetFileAttributesW(path.c_str()); 23 | return (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)); 24 | } 25 | 26 | bool IsDirectory(const string& path) 27 | { 28 | const DWORD attrs = GetFileAttributesA(path.c_str()); 29 | return (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)); 30 | } 31 | 32 | bool IsFile(const wstring& path) 33 | { 34 | const DWORD attrs = GetFileAttributesW(path.c_str()); 35 | return (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY)); 36 | } 37 | 38 | bool IsFile(const string& path) 39 | { 40 | const DWORD attrs = GetFileAttributesA(path.c_str()); 41 | return (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY)); 42 | } 43 | 44 | string GetDirectory(const string& path) 45 | { 46 | auto slash = path.find_last_of("/\\"); 47 | if (slash == string::npos) 48 | { 49 | return string(); 50 | } 51 | 52 | if (slash != path.size() - 1) 53 | { 54 | return path.substr(0, slash); 55 | } 56 | 57 | auto last = slash; 58 | slash = path.find_last_of("/\\", last); 59 | if (slash == string::npos) 60 | { 61 | return string(); 62 | } 63 | 64 | return path.substr(last); 65 | } 66 | 67 | wstring GetDirectory(const wstring& path) 68 | { 69 | auto slash = path.find_last_of(L"/\\"); 70 | if (slash == string::npos) 71 | { 72 | return wstring(); 73 | } 74 | 75 | if (slash != path.size() - 1) 76 | { 77 | return path.substr(0, slash); 78 | } 79 | 80 | auto last = slash; 81 | slash = path.find_last_of(L"/\\", last); 82 | if (slash == string::npos) 83 | { 84 | return wstring(); 85 | } 86 | 87 | return path.substr(last); 88 | } 89 | 90 | string GetBaseName(const string& path) 91 | { 92 | auto slash = path.find_last_of("/\\"); 93 | if (slash == string::npos) 94 | { 95 | return path; 96 | } 97 | 98 | if (slash != path.size() - 1) 99 | { 100 | return path.substr(slash + 1); 101 | } 102 | 103 | auto last = slash - 1; 104 | slash = path.find_last_of("/\\", last); 105 | return (!slash || slash == string::npos) ? string() : path.substr(slash + 1, last - slash); 106 | } 107 | 108 | void StripExtension(string& path) 109 | { 110 | auto dot = path.rfind('.'); 111 | if (dot != string::npos) 112 | { 113 | path.resize(dot); 114 | } 115 | } 116 | 117 | string GetExtension(const string& path, bool includeDot) 118 | { 119 | auto dot = path.rfind('.'); 120 | if (dot == string::npos) 121 | { 122 | return string(); 123 | } 124 | 125 | if (!includeDot) 126 | { 127 | ++dot; 128 | } 129 | 130 | return path.substr(dot); 131 | } 132 | 133 | /** 134 | * Replace the extension of the specified filename. 135 | * @param filename [in/out] Filename. 136 | * @param ext [in] New extension, with leading dot. 137 | */ 138 | void ReplaceFileExtension(string& filename, const char* ext) 139 | { 140 | assert(ext != nullptr); 141 | 142 | // Find the last '.'. 143 | size_t dot = filename.rfind('.'); 144 | if (dot == string::npos) 145 | { 146 | // No dot; no extension. 147 | return; 148 | } 149 | 150 | // Find the last '/' or '\\'. 151 | size_t bs = filename.find_last_of("/\\"); 152 | if (bs != string::npos && bs > dot) 153 | { 154 | // Dot is before the last slash. 155 | // No extension. 156 | return; 157 | } 158 | 159 | // Check for ext containing a '.' 160 | if (ext[0] != '.') 161 | dot++; 162 | 163 | // Resize to the dot, then add ext. 164 | filename.resize(dot); 165 | filename.append(ext); 166 | } 167 | -------------------------------------------------------------------------------- /ModLoaderCommon/FileSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool Exists(const std::wstring& path); 5 | bool Exists(const std::string& path); 6 | 7 | bool IsDirectory(const std::wstring& path); 8 | bool IsDirectory(const std::string& path); 9 | 10 | bool IsFile(const std::wstring& path); 11 | bool IsFile(const std::string& path); 12 | 13 | inline bool DirectoryExists(const std::wstring& path) 14 | { 15 | return Exists(path) && IsDirectory(path); 16 | } 17 | 18 | inline bool DirectoryExists(const std::string& path) 19 | { 20 | return Exists(path) && IsDirectory(path); 21 | } 22 | 23 | inline bool FileExists(const std::wstring& path) 24 | { 25 | return Exists(path) && IsFile(path); 26 | } 27 | 28 | inline bool FileExists(const std::string& path) 29 | { 30 | return Exists(path) && IsFile(path); 31 | } 32 | 33 | std::string GetDirectory(const std::string& path); 34 | std::wstring GetDirectory(const std::wstring& path); 35 | std::string GetBaseName(const std::string& path); 36 | void StripExtension(std::string& path); 37 | std::string GetExtension(const std::string& path, bool includeDot = false); 38 | 39 | /** 40 | * Replace the extension of the specified filename. 41 | * @param filename [in/out] Filename. 42 | * @param ext [in] New extension, with leading dot. 43 | */ 44 | void ReplaceFileExtension(std::string& filename, const char* ext); 45 | -------------------------------------------------------------------------------- /ModLoaderCommon/IniFile.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * INI file parser. 4 | */ 5 | 6 | #include "stdafx.h" 7 | #include "IniFile.hpp" 8 | #include "TextConv.hpp" 9 | 10 | // Needed for CP_UTF8 if stdafx.h doesn't have windows.h. 11 | #ifndef WIN32_LEAN_AND_MEAN 12 | # define WIN32_LEAN_AND_MEAN 13 | #endif 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using std::transform; 22 | using std::string; 23 | using std::unordered_map; 24 | using std::wstring; 25 | 26 | /** IniGroup **/ 27 | 28 | /** 29 | * Check if the INI group has the specified key. 30 | * @param key Key. 31 | * @return True if the key exists; false if not. 32 | */ 33 | bool IniGroup::hasKey(const string& key) const 34 | { 35 | return (m_data.find(key) != m_data.end()); 36 | } 37 | 38 | /** 39 | * Check if the INI group has the specified key with a non-empty value. 40 | * @param key Key. 41 | * @return True if the key exists; false if not or value is empty. 42 | */ 43 | bool IniGroup::hasKeyNonEmpty(const string& key) const 44 | { 45 | auto iter = m_data.find(key); 46 | if (iter == m_data.end()) 47 | return false; 48 | 49 | return !iter->second.empty(); 50 | } 51 | 52 | const unordered_map* IniGroup::data() const 53 | { 54 | return &m_data; 55 | } 56 | 57 | /** 58 | * Get a string value from the INI group. 59 | * @param key Key. 60 | * @param def Default value. 61 | * @return String value. 62 | */ 63 | string IniGroup::getString(const string& key, const string& def) const 64 | { 65 | auto iter = m_data.find(key); 66 | return (iter != m_data.end() ? iter->second : def); 67 | } 68 | 69 | /** 70 | * Get a wide string value from the INI group. 71 | * INI strings are converted from UTF-8 to UTF-16. 72 | * @param key Key. 73 | * @param def Default value. 74 | * @return Wide string value. 75 | */ 76 | wstring IniGroup::getWString(const string& key, const wstring& def) const 77 | { 78 | auto iter = m_data.find(key); 79 | if (iter == m_data.end()) 80 | return def; 81 | 82 | // Convert the string from UTF-8 to UTF-16. 83 | return MBStoUTF16(iter->second, CP_UTF8); 84 | } 85 | 86 | /** 87 | * Get a boolean value from the INI group. 88 | * @param key Key. 89 | * @param def Default value. 90 | * @return Boolean value. 91 | */ 92 | bool IniGroup::getBool(const string& key, bool def) const 93 | { 94 | auto iter = m_data.find(key); 95 | if (iter == m_data.end()) 96 | return def; 97 | 98 | return (!stricmp(iter->second.c_str(), "true")); 99 | } 100 | 101 | /** 102 | * Get an integer value from the INI group. 103 | * @param key Key. 104 | * @param radix Radix. 105 | * @param def Default value. 106 | * @return Integer value. 107 | */ 108 | int IniGroup::getIntRadix(const string& key, int radix, int def) const 109 | { 110 | auto iter = m_data.find(key); 111 | if (iter == m_data.end()) 112 | return def; 113 | 114 | try 115 | { 116 | return (int)std::stoll(iter->second, nullptr, radix); 117 | } 118 | catch (std::invalid_argument const& ex) 119 | { 120 | return def; 121 | } 122 | catch (std::out_of_range const& ex) 123 | { 124 | return def; 125 | } 126 | } 127 | 128 | /** 129 | * Get an integer value from the INI group. 130 | * @param key Key. 131 | * @param def Default value. 132 | * @return Integer value. 133 | */ 134 | int IniGroup::getInt(const string& key, int def) const 135 | { 136 | return getIntRadix(key, 10, def); 137 | } 138 | 139 | /** 140 | * Get a floating-point value from the INI group. 141 | * @param key Key. 142 | * @param def Default value. 143 | * @return Floating-point value. 144 | */ 145 | float IniGroup::getFloat(const string& key, float def) const 146 | { 147 | auto iter = m_data.find(key); 148 | if (iter == m_data.end()) 149 | return def; 150 | 151 | return std::stof(iter->second); 152 | } 153 | 154 | /** 155 | * Set a string value in the INI group. 156 | * @param key Key. 157 | * @param val Value. 158 | */ 159 | void IniGroup::setString(const string& key, const string& val) 160 | { 161 | m_data[key] = val; 162 | } 163 | 164 | /** 165 | * Set a wide string value in the INI group. 166 | * INI strings are converted from UTF-8 to UTF-16. 167 | * @param key Key. 168 | * @param val Value. 169 | */ 170 | void IniGroup::setWString(const string& key, const wstring& val) 171 | { 172 | m_data[key] = UTF16toMBS(val, CP_UTF8); 173 | } 174 | 175 | /** 176 | * Set a boolean value in the INI group. 177 | * @param key Key. 178 | * @param val Value. 179 | */ 180 | void IniGroup::setBool(const string& key, bool val) 181 | { 182 | string str; 183 | if (val) 184 | str = "True"; 185 | else 186 | str = "False"; 187 | m_data[key] = str; 188 | } 189 | 190 | /** 191 | * Set an integer value in the INI group. 192 | * @param key Key. 193 | * @param radix Radix. 194 | * @param val Value. 195 | */ 196 | void IniGroup::setIntRadix(const string& key, int radix, int val) 197 | { 198 | char buf[sizeof(int) * 8 + 1]; 199 | #ifdef _MSC_VER 200 | itoa(val, buf, radix); 201 | #else 202 | switch (radix) 203 | { 204 | case 8: 205 | snprintf(buf, LengthOfArray(buf), "%o", val); 206 | break; 207 | case 16: 208 | snprintf(buf, LengthOfArray(buf), "%x", val); 209 | break; 210 | default: 211 | snprintf(buf, LengthOfArray(buf), "%d", val); 212 | break; 213 | } 214 | #endif 215 | m_data[key] = buf; 216 | } 217 | 218 | /** 219 | * Set an integer value in the INI group. 220 | * @param key Key. 221 | * @param val Value. 222 | */ 223 | void IniGroup::setInt(const string& key, int val) 224 | { 225 | m_data[key] = std::to_string(val); 226 | } 227 | 228 | /** 229 | * Set a floating-point value in the INI group. 230 | * @param key Key. 231 | * @param val Value. 232 | */ 233 | void IniGroup::setFloat(const string& key, float val) 234 | { 235 | m_data[key] = std::to_string(val); 236 | } 237 | 238 | /** 239 | * Remove a key from the INI group. 240 | * @param key Key. 241 | * @return True if key was found. 242 | */ 243 | bool IniGroup::removeKey(const string& key) 244 | { 245 | if (hasKey(key)) 246 | { 247 | m_data.erase(key); 248 | return true; 249 | } 250 | return false; 251 | } 252 | 253 | IniGroup::iterator IniGroup::begin() 254 | { 255 | return m_data.begin(); 256 | } 257 | 258 | IniGroup::const_iterator IniGroup::cbegin() const 259 | { 260 | return m_data.cbegin(); 261 | } 262 | 263 | IniGroup::iterator IniGroup::end() 264 | { 265 | return m_data.end(); 266 | } 267 | 268 | IniGroup::const_iterator IniGroup::cend() const 269 | { 270 | return m_data.cend(); 271 | } 272 | 273 | /** IniFile **/ 274 | 275 | IniFile::IniFile(const string& filename) 276 | { 277 | FILE* f = fopen(filename.c_str(), "r"); 278 | if (!f) 279 | return; 280 | load(f); 281 | fclose(f); 282 | } 283 | 284 | IniFile::IniFile(const wstring& filename) 285 | { 286 | FILE* f = _wfopen(filename.c_str(), L"r"); 287 | if (!f) 288 | return; 289 | load(f); 290 | fclose(f); 291 | } 292 | 293 | IniFile::IniFile(const char* filename) 294 | { 295 | FILE* f = fopen(filename, "r"); 296 | if (!f) 297 | return; 298 | load(f); 299 | fclose(f); 300 | } 301 | 302 | IniFile::IniFile(const wchar_t* filename) 303 | { 304 | FILE* f = _wfopen(filename, L"r"); 305 | if (!f) 306 | return; 307 | load(f); 308 | fclose(f); 309 | } 310 | 311 | IniFile::IniFile(FILE* f) 312 | { 313 | load(f); 314 | } 315 | 316 | IniFile::~IniFile() 317 | { 318 | clear(); 319 | } 320 | 321 | /** 322 | * Get an INI group. 323 | * @param section Section. 324 | * @return INI group, or nullptr if not found. 325 | */ 326 | IniGroup* IniFile::getGroup(const string& section) 327 | { 328 | auto iter = m_groups.find(section); 329 | return (iter != m_groups.end() ? iter->second : nullptr); 330 | } 331 | 332 | /** 333 | * Get an INI group. 334 | * @param section Section. 335 | * @return INI group, or nullptr if not found. 336 | */ 337 | const IniGroup* IniFile::getGroup(const string& section) const 338 | { 339 | auto iter = m_groups.find(section); 340 | return (iter != m_groups.end() ? iter->second : nullptr); 341 | } 342 | 343 | /** 344 | * Create an INI group, or retrieve an existing group. 345 | * @param section Section. 346 | * @return INI group. 347 | */ 348 | IniGroup* IniFile::createGroup(const string& section) 349 | { 350 | auto iter = m_groups.find(section); 351 | if (iter != m_groups.end()) 352 | return iter->second; 353 | auto* group = new IniGroup(); 354 | m_groups[section] = group; 355 | return group; 356 | } 357 | 358 | /** 359 | * Check if the INI file has the specified group. 360 | * @param section Section. 361 | * @return True if the section exists; false if not. 362 | */ 363 | bool IniFile::hasGroup(const string& section) const 364 | { 365 | return (m_groups.find(section) != m_groups.end()); 366 | } 367 | 368 | /** 369 | * Check if the INI file has the specified key. 370 | * @param section Section. 371 | * @param key Key. 372 | * @return True if the key exists; false if not. 373 | */ 374 | bool IniFile::hasKey(const string& section, const string& key) const 375 | { 376 | auto iter = m_groups.find(section); 377 | if (iter == m_groups.end()) 378 | return false; 379 | 380 | return iter->second->hasKey(key); 381 | } 382 | 383 | /** 384 | * Check if the INI file has the specified key with a non-empty value. 385 | * @param section Section. 386 | * @param key Key. 387 | * @return True if the key exists; false if not or value is empty. 388 | */ 389 | bool IniFile::hasKeyNonEmpty(const string& section, const string& key) const 390 | { 391 | auto iter = m_groups.find(section); 392 | if (iter == m_groups.end()) 393 | return false; 394 | 395 | return iter->second->hasKeyNonEmpty(key); 396 | } 397 | 398 | /** 399 | * Get a string value from the INI file. 400 | * @param section Section. 401 | * @param key Key. 402 | * @param def Default value. 403 | * @return String value. 404 | */ 405 | string IniFile::getString(const string& section, const string& key, const string& def) const 406 | { 407 | const IniGroup* group = getGroup(section); 408 | if (!group) 409 | return def; 410 | return group->getString(key, def); 411 | } 412 | 413 | /** 414 | * Get a wide string value from the INI group. 415 | * INI strings are converted from UTF-8 to UTF-16. 416 | * @param section Section. 417 | * @param key Key. 418 | * @param def Default value. 419 | * @return Wide string value. 420 | */ 421 | wstring IniFile::getWString(const string& section, const string& key, const wstring& def) const 422 | { 423 | const IniGroup* group = getGroup(section); 424 | if (!group) 425 | return def; 426 | return group->getWString(key, def); 427 | } 428 | 429 | /** 430 | * Get a boolean value from the INI file. 431 | * @param section Section. 432 | * @param key Key. 433 | * @param def Default value. 434 | * @return Boolean value. 435 | */ 436 | bool IniFile::getBool(const string& section, const string& key, bool def) const 437 | { 438 | const IniGroup* group = getGroup(section); 439 | if (!group) 440 | return def; 441 | return group->getBool(key, def); 442 | } 443 | 444 | /** 445 | * Get an integer value from the INI file. 446 | * @param section Section. 447 | * @param key Key. 448 | * @param radix Radix. 449 | * @param def Default value. 450 | * @return Integer value. 451 | */ 452 | int IniFile::getIntRadix(const string& section, const string& key, int radix, int def) const 453 | { 454 | const IniGroup* group = getGroup(section); 455 | if (!group) 456 | return def; 457 | return group->getIntRadix(key, radix, def); 458 | } 459 | 460 | /** 461 | * Get an integer value from the INI file. 462 | * @param section Section. 463 | * @param key Key. 464 | * @param def Default value. 465 | * @return Integer value. 466 | */ 467 | int IniFile::getInt(const string& section, const string& key, int def) const 468 | { 469 | const IniGroup* group = getGroup(section); 470 | if (!group) 471 | return def; 472 | return group->getInt(key, def); 473 | } 474 | 475 | /** 476 | * Get a floating-point value from the INI file. 477 | * @param section Section. 478 | * @param key Key. 479 | * @param def Default value. 480 | * @return Floating-point value. 481 | */ 482 | float IniFile::getFloat(const string& section, const string& key, float def) const 483 | { 484 | const IniGroup* group = getGroup(section); 485 | if (!group) 486 | return def; 487 | return group->getFloat(key, def); 488 | } 489 | 490 | /** 491 | * Set a string value in the INI file. 492 | * @param section Section. 493 | * @param key Key. 494 | * @param val Value. 495 | */ 496 | void IniFile::setString(const string& section, const string& key, const string& val) 497 | { 498 | createGroup(section)->setString(key, val); 499 | } 500 | 501 | /** 502 | * Set a wide string value in the INI file. 503 | * INI strings are converted from UTF-8 to UTF-16. 504 | * @param section Section. 505 | * @param key Key. 506 | * @param val Value. 507 | */ 508 | void IniFile::setWString(const string& section, const string& key, const wstring& val) 509 | { 510 | createGroup(section)->setWString(key, val); 511 | } 512 | 513 | /** 514 | * Set a boolean value in the INI file. 515 | * @param section Section. 516 | * @param key Key. 517 | * @param val Value. 518 | */ 519 | void IniFile::setBool(const string& section, const string& key, bool val) 520 | { 521 | createGroup(section)->setBool(key, val); 522 | } 523 | 524 | /** 525 | * Set an integer value in the INI file. 526 | * @param section Section. 527 | * @param key Key. 528 | * @param radix Radix. 529 | * @param val Value. 530 | */ 531 | void IniFile::setIntRadix(const string& section, const string& key, int radix, int val) 532 | { 533 | createGroup(section)->setIntRadix(key, radix, val); 534 | } 535 | 536 | /** 537 | * Set an integer value in the INI file. 538 | * @param section Section. 539 | * @param key Key. 540 | * @param val Value. 541 | */ 542 | void IniFile::setInt(const string& section, const string& key, int val) 543 | { 544 | createGroup(section)->setInt(key, val); 545 | } 546 | 547 | /** 548 | * Set a floating-point value in the INI file. 549 | * @param section Section. 550 | * @param key Key. 551 | * @param val Value. 552 | */ 553 | void IniFile::setFloat(const string& section, const string& key, float val) 554 | { 555 | createGroup(section)->setFloat(key, val); 556 | } 557 | 558 | /** 559 | * Remove a section from the INI file. 560 | * @param group Section. 561 | * @return True if section was found. 562 | */ 563 | bool IniFile::removeGroup(const string& group) 564 | { 565 | if (hasGroup(group)) 566 | { 567 | delete m_groups[group]; 568 | m_groups.erase(group); 569 | return true; 570 | } 571 | return false; 572 | } 573 | 574 | /** 575 | * Remove a key from the INI file. 576 | * @param section Section. 577 | * @param key Key. 578 | * @return True if key was found. 579 | */ 580 | bool IniFile::removeKey(const string& section, const string& key) 581 | { 582 | IniGroup* group = getGroup(section); 583 | if (group) 584 | return group->removeKey(key); 585 | return false; 586 | } 587 | 588 | /** 589 | * Save an INI file. 590 | * @param filename Name of file to save to. 591 | */ 592 | void IniFile::save(const string& filename) const 593 | { 594 | FILE* f = fopen(filename.c_str(), "w"); 595 | if (!f) 596 | return; 597 | 598 | save(f); 599 | fclose(f); 600 | } 601 | 602 | /** 603 | * Save an INI file. 604 | * @param filename Name of file to save to. 605 | */ 606 | void IniFile::save(const wstring& filename) const 607 | { 608 | FILE* f = _wfopen(filename.c_str(), L"w"); 609 | if (!f) 610 | return; 611 | 612 | save(f); 613 | fclose(f); 614 | } 615 | 616 | /** 617 | * Save an INI file. 618 | * @param f FILE pointer. (File is not closed after processing.) 619 | */ 620 | void IniFile::save(FILE* f) const 621 | { 622 | std::list> list; 623 | 624 | for (auto it = cbegin(); it != cend(); ++it) 625 | { 626 | if (it->first.empty()) 627 | { 628 | list.emplace_front(it->first, it->second); 629 | } 630 | else 631 | { 632 | list.emplace_back(it->first, it->second); 633 | } 634 | } 635 | 636 | for (const auto& gr : list) 637 | { 638 | if (!gr.first.empty()) 639 | { 640 | fprintf(f, "[%s]\n", escape(gr.first, true, false).c_str()); 641 | } 642 | 643 | for (const auto& kv : *gr.second) 644 | { 645 | fprintf(f, "%s=%s\n", escape(kv.first, false, true).c_str(), escape(kv.second, false, false).c_str()); 646 | } 647 | } 648 | } 649 | 650 | std::unordered_map::iterator IniFile::begin() 651 | { 652 | return m_groups.begin(); 653 | } 654 | 655 | std::unordered_map::const_iterator IniFile::cbegin() const 656 | { 657 | return m_groups.cbegin(); 658 | } 659 | 660 | std::unordered_map::iterator IniFile::end() 661 | { 662 | return m_groups.end(); 663 | } 664 | 665 | std::unordered_map::const_iterator IniFile::cend() const 666 | { 667 | return m_groups.cend(); 668 | } 669 | 670 | /** 671 | * Load an INI file. 672 | * Internal function; called from the constructor. 673 | * @param f FILE pointer. (File is not closed after processing.) 674 | */ 675 | void IniFile::load(FILE* f) 676 | { 677 | clear(); 678 | fseek(f, 0, SEEK_SET); 679 | 680 | // Create an empty group for default settings. 681 | auto* curGroup = new IniGroup(); 682 | m_groups[""] = curGroup; 683 | 684 | // Process the INI file. 685 | while (!feof(f)) 686 | { 687 | char line[1024]; 688 | char* ret = fgets(line, sizeof(line), f); 689 | if (!ret) 690 | break; 691 | const int line_len = (int)strnlen(line, sizeof(line)); 692 | if (line_len == 0) 693 | continue; 694 | 695 | bool startswithbracket = false; 696 | int firstequals = -1; 697 | int endbracket = -1; 698 | 699 | // String can contain escape characters, so 700 | // we need a string buffer. 701 | string sb; 702 | sb.reserve(line_len); 703 | 704 | // Process the line. 705 | for (int c = 0; c < line_len; c++) 706 | { 707 | switch (line[c]) 708 | { 709 | case '\\': // escape character 710 | if (c + 1 >= line_len) 711 | { 712 | // Backslash at the end of the line. 713 | goto appendchar; 714 | } 715 | c++; 716 | switch (line[c]) 717 | { 718 | case 'n': // line feed 719 | sb += '\n'; 720 | break; 721 | case 'r': // carriage return 722 | sb += '\r'; 723 | break; 724 | default: // literal character 725 | goto appendchar; 726 | } 727 | break; 728 | 729 | case '=': 730 | if (firstequals == -1) 731 | firstequals = sb.length(); 732 | goto appendchar; 733 | 734 | case '[': 735 | if (c == 0) 736 | startswithbracket = true; 737 | goto appendchar; 738 | 739 | case ']': 740 | endbracket = sb.length(); 741 | goto appendchar; 742 | 743 | case ';': // comment character 744 | case '\r': // trailing newline (CRLF) 745 | case '\n': // trailing newline (LF) 746 | // Stop processing this line. 747 | c = line_len; 748 | break; 749 | 750 | default: 751 | appendchar: 752 | // Normal character. Append to the string buffer. 753 | sb += line[c]; 754 | break; 755 | } 756 | } 757 | 758 | // Check the string buffer. 759 | if (startswithbracket && endbracket != -1) 760 | { 761 | // New section. 762 | string section = sb.substr(1, endbracket - 1); 763 | auto iter = m_groups.find(section); 764 | if (iter != m_groups.end()) 765 | { 766 | // Section already exists. 767 | // Use the existing section. 768 | curGroup = iter->second; 769 | } 770 | else 771 | { 772 | // New section. 773 | curGroup = new IniGroup(); 774 | m_groups[section] = curGroup; 775 | } 776 | } 777 | else if (!sb.empty()) 778 | { 779 | // Key/value. 780 | string key; 781 | string value; 782 | if (firstequals > -1) 783 | { 784 | key = sb.substr(0, firstequals); 785 | value = sb.substr(firstequals + 1); 786 | } 787 | else 788 | { 789 | key = sb; 790 | } 791 | 792 | // Store the value in the current group. 793 | curGroup->m_data[key] = value; 794 | } 795 | } 796 | } 797 | 798 | /** 799 | * Clear the loaded INI file. 800 | */ 801 | void IniFile::clear() 802 | { 803 | for (auto& m_group : m_groups) 804 | { 805 | delete m_group.second; 806 | } 807 | 808 | m_groups.clear(); 809 | } 810 | 811 | string IniFile::escape(const string& str, bool sec, bool key) 812 | { 813 | string result(str); 814 | 815 | for (size_t i = 0; i < result.size(); i++) 816 | { 817 | switch (result[i]) 818 | { 819 | case '=': 820 | if (key) 821 | result.insert(i++, "\\"); 822 | break; 823 | case '[': 824 | if (key && i == 0) 825 | result.insert(i++, "\\"); 826 | break; 827 | case ']': 828 | if (sec) 829 | result.insert(i++, "\\"); 830 | break; 831 | case '\\': 832 | case ';': 833 | result.insert(i++, "\\"); 834 | break; 835 | case '\n': 836 | result.insert(i++, "\\"); 837 | result[i] = 'n'; 838 | break; 839 | case '\r': 840 | result.insert(i++, "\\"); 841 | result[i] = 'r'; 842 | break; 843 | 844 | default: 845 | break; 846 | } 847 | } 848 | 849 | return result; 850 | } 851 | -------------------------------------------------------------------------------- /ModLoaderCommon/IniFile.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * INI file parser. 4 | */ 5 | 6 | #ifndef INIFILE_H 7 | #define INIFILE_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class IniFile; 14 | 15 | /** 16 | * Individual INI group. 17 | */ 18 | class IniGroup 19 | { 20 | public: 21 | bool hasKey(const std::string& key) const; 22 | bool hasKeyNonEmpty(const std::string& key) const; 23 | 24 | const std::unordered_map* data() const; 25 | 26 | std::string getString(const std::string& key, const std::string& def = std::string()) const; 27 | std::wstring getWString(const std::string& key, const std::wstring& def = std::wstring()) const; 28 | bool getBool(const std::string& key, bool def = false) const; 29 | int getIntRadix(const std::string& key, int radix, int def = 0) const; 30 | int getInt(const std::string& key, int def = 0) const; 31 | float getFloat(const std::string& key, float def = 0) const; 32 | 33 | void setString(const std::string& key, const std::string& val); 34 | void setWString(const std::string& key, const std::wstring& val); 35 | void setBool(const std::string& key, bool val); 36 | void setIntRadix(const std::string& key, int radix, int val); 37 | void setInt(const std::string& key, int val); 38 | void setFloat(const std::string& key, float val); 39 | 40 | bool removeKey(const std::string& key); 41 | 42 | using iterator = std::unordered_map::iterator; 43 | using const_iterator = std::unordered_map::const_iterator; 44 | 45 | iterator begin(); 46 | const_iterator cbegin() const; 47 | iterator end(); 48 | const_iterator cend() const; 49 | 50 | protected: 51 | friend class IniFile; 52 | 53 | /** 54 | * INI section data. 55 | * - Key: Key name. (UTF-8) 56 | * - Value: Value. (UTF-8) 57 | */ 58 | std::unordered_map m_data; 59 | }; 60 | 61 | inline auto begin(IniGroup& x) 62 | { 63 | return x.begin(); 64 | } 65 | 66 | inline auto end(IniGroup& x) 67 | { 68 | return x.end(); 69 | } 70 | 71 | inline auto cbegin(const IniGroup& x) 72 | { 73 | return x.cbegin(); 74 | } 75 | 76 | inline auto cend(const IniGroup& x) 77 | { 78 | return x.cend(); 79 | } 80 | 81 | /** 82 | * INI file. 83 | * Contains multiple INI groups. 84 | */ 85 | class IniFile 86 | { 87 | public: 88 | explicit IniFile(const std::string& filename); 89 | explicit IniFile(const std::wstring& filename); 90 | explicit IniFile(const char* filename); 91 | explicit IniFile(const wchar_t* filename); 92 | explicit IniFile(FILE* f); 93 | ~IniFile(); 94 | 95 | IniGroup* getGroup(const std::string& section); 96 | const IniGroup* getGroup(const std::string& section) const; 97 | IniGroup* createGroup(const std::string& section); 98 | 99 | bool hasGroup(const std::string& section) const; 100 | bool hasKey(const std::string& section, const std::string& key) const; 101 | bool hasKeyNonEmpty(const std::string& section, const std::string& key) const; 102 | 103 | std::string getString(const std::string& section, const std::string& key, const std::string& def = std::string()) const; 104 | std::wstring getWString(const std::string& section, const std::string& key, const std::wstring& def = std::wstring()) const; 105 | bool getBool(const std::string& section, const std::string& key, bool def = false) const; 106 | int getIntRadix(const std::string& section, const std::string& key, int radix, int def = 0) const; 107 | int getInt(const std::string& section, const std::string& key, int def = 0) const; 108 | float getFloat(const std::string& section, const std::string& key, float def = 0) const; 109 | 110 | void setString(const std::string& section, const std::string& key, const std::string& val); 111 | void setWString(const std::string& section, const std::string& key, const std::wstring& val); 112 | void setBool(const std::string& section, const std::string& key, bool val); 113 | void setIntRadix(const std::string& section, const std::string& key, int radix, int val); 114 | void setInt(const std::string& section, const std::string& key, int val); 115 | void setFloat(const std::string& section, const std::string& key, float val); 116 | 117 | bool removeGroup(const std::string& group); 118 | bool removeKey(const std::string& section, const std::string& key); 119 | 120 | void save(const std::string& filename) const; 121 | void save(const std::wstring& filename) const; 122 | void save(FILE* f) const; 123 | 124 | using iterator = std::unordered_map::iterator; 125 | using const_iterator = std::unordered_map::const_iterator; 126 | 127 | iterator begin(); 128 | const_iterator cbegin() const; 129 | iterator end(); 130 | const_iterator cend() const; 131 | 132 | protected: 133 | void load(FILE* f); 134 | void clear(); 135 | static std::string escape(const std::string& str, bool sec, bool key); 136 | 137 | /** 138 | * INI groups. 139 | * - Key: Section name. (UTF-8) 140 | * - Value: IniGroup. 141 | */ 142 | std::unordered_map m_groups; 143 | }; 144 | 145 | inline auto begin(IniFile& x) 146 | { 147 | return x.begin(); 148 | } 149 | 150 | inline auto end(IniFile& x) 151 | { 152 | return x.end(); 153 | } 154 | 155 | inline auto cbegin(const IniFile& x) 156 | { 157 | return x.cbegin(); 158 | } 159 | 160 | inline auto cend(const IniFile& x) 161 | { 162 | return x.cend(); 163 | } 164 | 165 | #endif /* INIFILE_H */ 166 | -------------------------------------------------------------------------------- /ModLoaderCommon/ModLoaderCommon.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B} 15 | Win32Proj 16 | ModLoaderCommon 17 | 8.1 18 | 19 | 20 | 21 | StaticLibrary 22 | true 23 | v141_xp 24 | Unicode 25 | 26 | 27 | StaticLibrary 28 | false 29 | v141_xp 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | $(SolutionDir)bin\ 45 | 46 | 47 | $(SolutionDir)bin\ 48 | 49 | 50 | 51 | Use 52 | Level3 53 | Disabled 54 | _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 55 | 56 | 57 | Windows 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | Use 65 | MaxSpeed 66 | true 67 | true 68 | _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 69 | 70 | 71 | Windows 72 | true 73 | true 74 | true 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Create 95 | Create 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ModLoaderCommon/ModLoaderCommon.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /ModLoaderCommon/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : ModLoaderCommon Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ModLoaderCommon library project for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your ModLoaderCommon application. 9 | 10 | 11 | ModLoaderCommon.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | ModLoaderCommon.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | 25 | ///////////////////////////////////////////////////////////////////////////// 26 | 27 | StdAfx.h, StdAfx.cpp 28 | These files are used to build a precompiled header (PCH) file 29 | named ModLoaderCommon.pch and a precompiled types file named StdAfx.obj. 30 | 31 | ///////////////////////////////////////////////////////////////////////////// 32 | Other notes: 33 | 34 | AppWizard uses "TODO:" comments to indicate parts of the source code you 35 | should add to or customize. 36 | 37 | ///////////////////////////////////////////////////////////////////////////// 38 | -------------------------------------------------------------------------------- /ModLoaderCommon/TextConv.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * Text conversion functions. 4 | */ 5 | 6 | #include "stdafx.h" 7 | #include "TextConv.hpp" 8 | 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | 12 | #define CP_SJIS 932 13 | 14 | /** 15 | * Convert multibyte text to UTF-16. 16 | * @param mbs Multibyte text, null-terminated. 17 | * @param cp Code page. 18 | * @return UTF-16 text (allocated via new[]), or nullptr on error. 19 | */ 20 | wchar_t* MBStoUTF16(const char* mbs, unsigned int cp) 21 | { 22 | int cchWcs = MultiByteToWideChar(cp, 0, mbs, -1, NULL, 0); 23 | if (cchWcs <= 0) 24 | return nullptr; 25 | auto wcs = new wchar_t[cchWcs]; 26 | MultiByteToWideChar(cp, 0, mbs, -1, wcs, cchWcs); 27 | return wcs; 28 | } 29 | 30 | /** 31 | * Convert UTF-16 text to multibyte. 32 | * @param wcs UTF-16 text, null-terminated. 33 | * @param cp Code page. 34 | * @return Multibyte text (allocated via new[]), or nullptr on error. 35 | */ 36 | char* UTF16toMBS(const wchar_t* wcs, unsigned int cp) 37 | { 38 | int cbMbs = WideCharToMultiByte(cp, 0, wcs, -1, NULL, 0, NULL, NULL); 39 | if (cbMbs <= 0) 40 | return nullptr; 41 | auto mbs = new char[cbMbs]; 42 | WideCharToMultiByte(cp, 0, wcs, -1, mbs, cbMbs, NULL, NULL); 43 | return mbs; 44 | } 45 | 46 | /** Convenience functions. **/ 47 | 48 | /** 49 | * Convert from one multibyte text format to another 50 | * @param source Text to convert. 51 | * @param sourcecp Code page of the source string. 52 | * @param targetcp Code page to convert to. 53 | * @return Converted text, or empty string on error. 54 | */ 55 | char* MBStoMBS(const char* source, unsigned int sourcecp, unsigned int targetcp) 56 | { 57 | // Convert from the source codepage to UTF-16. 58 | wchar_t* wcs = MBStoUTF16(source, sourcecp); 59 | if (!wcs) 60 | return nullptr; 61 | 62 | // Convert from UTF-16 to the target codepage. 63 | char* mbs = UTF16toMBS(wcs, targetcp); 64 | delete[] wcs; 65 | if (!mbs) 66 | return nullptr; 67 | 68 | return mbs; 69 | } 70 | 71 | /** 72 | * Convert Shift-JIS text to UTF-8. 73 | * @param sjis Shift-JIS text, null-terminated. 74 | * @return UTF-8 text (allocated via new[]), or nullptr on error. 75 | */ 76 | char* SJIStoUTF8(const char* sjis) 77 | { 78 | return MBStoMBS(sjis, CP_SJIS, CP_UTF8); 79 | } 80 | 81 | /** 82 | * Convert UTF-8 text to Shift-JIS. 83 | * @param utf8 UTF-8 text, null-terminated. 84 | * @return Shift-JIS text (allocated via new[]), or nullptr on error. 85 | */ 86 | char* UTF8toSJIS(const char* utf8) 87 | { 88 | return MBStoMBS(utf8, CP_UTF8, CP_SJIS); 89 | } 90 | 91 | /** 92 | * Convert UTF-8 text to Windows-1252. 93 | * @param utf8 UTF-8 text, null-terminated. 94 | * @return Windows-1252 text (allocated via new[]), or nullptr on error. 95 | */ 96 | char* UTF8to1252(const char* utf8) 97 | { 98 | return MBStoMBS(utf8, CP_UTF8, 1252); 99 | } 100 | 101 | /** 102 | * Convert UTF-8 text to a Windows codepage text. 103 | * @param utf8 UTF-8 text, null-terminated. 104 | * @param short target codepage. 105 | * @return Windows-1252 etc. text (allocated via new[]), or nullptr on error. 106 | */ 107 | char* UTF8toCodepage(const char* utf8, unsigned int codepage) 108 | { 109 | return MBStoMBS(utf8, CP_UTF8, codepage); 110 | } 111 | 112 | /** 113 | * Convert a Windows codepage text to UTF-8 text. 114 | * @param source source text, null-terminated. 115 | * @param codepage source codepage. 116 | * @return UTF8 etc. text (allocated via new[]), or nullptr on error. 117 | */ 118 | char* CodepagetoUTF8(const char* source, unsigned int codepage) 119 | { 120 | return MBStoMBS(source, codepage, CP_UTF8); 121 | } 122 | 123 | /** C++ wrappers. **/ 124 | 125 | #include 126 | using std::string; 127 | using std::wstring; 128 | 129 | /** 130 | * Convert multibyte text to UTF-16. 131 | * @param mbs Multibyte text. 132 | * @param cp Code page. 133 | * @return UTF-16 text, or empty string on error. 134 | */ 135 | wstring MBStoUTF16(const string& mbs, unsigned int cp) 136 | { 137 | wchar_t* wcs = MBStoUTF16(mbs.c_str(), cp); 138 | if (!wcs) 139 | return wstring(); 140 | 141 | wstring wstr(wcs); 142 | delete[] wcs; 143 | return wstr; 144 | } 145 | 146 | /** 147 | * Convert UTF-16 text to multibyte. 148 | * @param wcs UTF-16 text. 149 | * @param cp Code page. 150 | * @return Multibyte text, or empty string on error. 151 | */ 152 | string UTF16toMBS(const wstring& wcs, unsigned int cp) 153 | { 154 | char* mbs = UTF16toMBS(wcs.c_str(), cp); 155 | if (!mbs) 156 | return string(); 157 | 158 | string mstr(mbs); 159 | delete[] mbs; 160 | return mstr; 161 | } 162 | 163 | /** Convenience functions. **/ 164 | 165 | /** 166 | * Convert from one multibyte text format to another 167 | * @param source Text to convert. 168 | * @param sourcecp Code page of the source string. 169 | * @param targetcp Code page to convert to. 170 | * @return Converted text, or empty string on error. 171 | */ 172 | string MBStoMBS(const string& source, unsigned int sourcecp, unsigned int targetcp) 173 | { 174 | char* mbs = MBStoMBS(source.c_str(), sourcecp, targetcp); 175 | if (!mbs) 176 | return string(); 177 | 178 | string mstr(mbs); 179 | delete[] mbs; 180 | return mstr; 181 | } 182 | 183 | /** 184 | * Convert Shift-JIS text to UTF-8. 185 | * @param sjis Shift-JIS text. 186 | * @return UTF-8 text, or empty string on error. 187 | */ 188 | string SJIStoUTF8(const string& sjis) 189 | { 190 | return MBStoMBS(sjis, CP_SJIS, CP_UTF8); 191 | } 192 | 193 | /** 194 | * Convert UTF-8 text to Shift-JIS. 195 | * @param utf8 UTF-8 text. 196 | * @return Shift-JIS text, or empty string on error. 197 | */ 198 | string UTF8toSJIS(const string& utf8) 199 | { 200 | return MBStoMBS(utf8, CP_UTF8, CP_SJIS); 201 | } 202 | 203 | /** 204 | * Convert UTF-8 text to Windows-1252. 205 | * @param utf8 UTF-8 text. 206 | * @return Windows-1252 text, or empty string on error. 207 | */ 208 | string UTF8to1252(const string& utf8) 209 | { 210 | return MBStoMBS(utf8, CP_UTF8, 1252); 211 | } 212 | 213 | /** 214 | * Convert UTF-8 text to a Windows codepage text. 215 | * @param utf8 UTF-8 text, 216 | * @param short target codepage. 217 | * @return Windows-1252 etc. text, or empty string on error. 218 | */ 219 | string UTF8toCodepage(const string& utf8, unsigned int codepage) 220 | { 221 | return MBStoMBS(utf8, CP_UTF8, codepage); 222 | } 223 | 224 | /** 225 | * Convert a Windows codepage text to UTF-8 text. 226 | * @param source source text, null-terminated. 227 | * @param codepage source codepage. 228 | * @return UTF8 etc. text, or nullptr on error. 229 | */ 230 | string CodepagetoUTF8(const string& source, unsigned int codepage) 231 | { 232 | return MBStoMBS(source, codepage, CP_UTF8); 233 | } -------------------------------------------------------------------------------- /ModLoaderCommon/TextConv.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SADX Mod Loader 3 | * Text conversion functions. 4 | */ 5 | 6 | #ifndef TEXTCONV_HPP 7 | #define TEXTCONV_HPP 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | * Convert multibyte text to UTF-16. 15 | * @param mbs Multibyte text, null-terminated. 16 | * @param cp Code page. 17 | * @return UTF-16 text (allocated via new[]), or nullptr on error. 18 | */ 19 | wchar_t* MBStoUTF16(const char* mbs, unsigned int cp); 20 | 21 | /** 22 | * Convert UTF-16 text to multibyte. 23 | * @param wcs UTF-16 text, null-terminated. 24 | * @param cp Code page. 25 | * @return Multibyte text (allocated via new[]), or nullptr on error. 26 | */ 27 | char* UTF16toMBS(const wchar_t* wcs, unsigned int cp); 28 | 29 | /** Convenience functions. **/ 30 | 31 | /** 32 | * Convert Shift-JIS text to UTF-8. 33 | * @param sjis Shift-JIS text, null-terminated. 34 | * @return UTF-8 text (allocated via new[]), or nullptr on error. 35 | */ 36 | char* SJIStoUTF8(const char* sjis); 37 | 38 | /** 39 | * Convert UTF-8 text to Shift-JIS. 40 | * @param utf8 UTF-8 text, null-terminated. 41 | * @return Shift-JIS text (allocated via new[]), or nullptr on error. 42 | */ 43 | char* UTF8toSJIS(const char* utf8); 44 | 45 | /** 46 | * Convert UTF-8 text to Windows-1252. 47 | * @param utf8 UTF-8 text, null-terminated. 48 | * @return Windows-1252 text (allocated via new[]), or nullptr on error. 49 | */ 50 | char* UTF8to1252(const char* utf8); 51 | 52 | /** 53 | * Convert UTF-8 text to a Windows codepage text. 54 | * @param utf8 UTF-8 text, null-terminated. 55 | * @param short target codepage. 56 | * @return Windows-1252 etc. text (allocated via new[]), or nullptr on error. 57 | */ 58 | char* UTF8toCodepage(const char* utf8, unsigned int codepage); 59 | 60 | /** 61 | * Convert a Windows codepage text to UTF-8 text. 62 | * @param source source text, null-terminated. 63 | * @param codepage source codepage. 64 | * @return UTF8 etc. text (allocated via new[]), or nullptr on error. 65 | */ 66 | char* CodepagetoUTF8(const char* source, unsigned int codepage); 67 | 68 | #ifdef __cplusplus 69 | } 70 | 71 | // C++ wrappers. 72 | #include 73 | 74 | /** 75 | * Convert multibyte text to UTF-16. 76 | * @param mbs Multibyte text. 77 | * @param cp Code page. 78 | * @return UTF-16 text, or empty string on error. 79 | */ 80 | std::wstring MBStoUTF16(const std::string& mbs, unsigned int cp); 81 | 82 | /** 83 | * Convert UTF-16 text to multibyte. 84 | * @param wcs UTF-16 text. 85 | * @param cp Code page. 86 | * @return Multibyte text, or empty string on error. 87 | */ 88 | std::string UTF16toMBS(const std::wstring& wcs, unsigned int cp); 89 | 90 | /** Convenience functions. **/ 91 | 92 | /** 93 | * Convert Shift-JIS text to UTF-8. 94 | * @param sjis Shift-JIS text. 95 | * @return UTF-8 text, or empty string on error. 96 | */ 97 | std::string SJIStoUTF8(const std::string& sjis); 98 | 99 | /** 100 | * Convert UTF-8 text to Shift-JIS. 101 | * @param utf8 UTF-8 text. 102 | * @return Shift-JIS text, or empty string on error. 103 | */ 104 | std::string UTF8toSJIS(const std::string& utf8); 105 | 106 | /** 107 | * Convert UTF-8 text to Windows-1252. 108 | * @param utf8 UTF-8 text. 109 | * @return Windows-1252 text, or empty string on error. 110 | */ 111 | std::string UTF8to1252(const std::string& utf8); 112 | 113 | /** 114 | * Convert UTF-8 text to a Windows codepage text. 115 | * @param utf8 UTF-8 text, 116 | * @param short target codepage. 117 | * @return Windows-1252 etc. text, or empty string on error. 118 | */ 119 | std::string UTF8toCodepage(const std::string& utf8, unsigned int codepage); 120 | 121 | /** 122 | * Convert a Windows codepage text to UTF-8 text. 123 | * @param source source text, null-terminated. 124 | * @param codepage source codepage. 125 | * @return UTF8 etc. text (allocated via new[]), or nullptr on error. 126 | */ 127 | std::string CodepagetoUTF8(const std::string& source, unsigned int codepage); 128 | 129 | #endif /* __cplusplus */ 130 | 131 | #endif /* TEXTCONV_H */ 132 | -------------------------------------------------------------------------------- /ModLoaderCommon/Utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_HPP 2 | #define UTILS_HPP 3 | 4 | // Utility Functions 5 | #ifdef __cplusplus 6 | // C++ version. 7 | 8 | /** 9 | * Get the number of elements in an array. 10 | * @return Number of elements in the array. 11 | */ 12 | template 13 | static inline size_t LengthOfArray(const T(&)[N]) 14 | { 15 | return N; 16 | } 17 | 18 | /** 19 | * Get the size of an array. 20 | * @return Size of the array, in bytes. 21 | */ 22 | template 23 | static inline size_t SizeOfArray(const T(&)[N]) 24 | { 25 | return N * sizeof(T); 26 | } 27 | #else 28 | 29 | // C version. 30 | 31 | /** 32 | * Number of elements in an array. 33 | * 34 | * Includes a static check for pointers to make sure 35 | * a dynamically-allocated array wasn't specified. 36 | * Reference: http://stackoverflow.com/questions/8018843/macro-definition-array-size 37 | */ 38 | #define LengthOfArray(x) \ 39 | ((int)(((sizeof(x) / sizeof(x[0]))) / \ 40 | (size_t)(!(sizeof(x) % sizeof(x[0]))))) 41 | 42 | #define SizeOfArray(x) sizeof(x) 43 | 44 | #endif 45 | 46 | // Macros for functions that need both an array 47 | // and the array length or size. 48 | #define arrayptrandlength(data) data, LengthOfArray(data) 49 | #define arraylengthandptr(data) LengthOfArray(data), data 50 | #define arrayptrandsize(data) data, SizeOfArray(data) 51 | #define arraysizeandptr(data) SizeOfArray(data), data 52 | 53 | #endif /* UTILS_HPP */ 54 | -------------------------------------------------------------------------------- /ModLoaderCommon/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ModLoaderCommon.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /ModLoaderCommon/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | 12 | #include 13 | 14 | // TODO: reference additional headers your program requires here 15 | -------------------------------------------------------------------------------- /ModLoaderCommon/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 10 | #define WINVER _WIN32_WINNT_WINXP --------------------------------------------------------------------------------