├── src ├── stdafx.cpp ├── external │ └── inih │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── test.ini │ │ ├── INIReaderTest.cpp │ │ ├── LICENSE.txt │ │ ├── README.md │ │ └── INIReader.h ├── stdafx.h ├── proxy.def ├── helper.hpp ├── proxy.cpp └── dllmain.cpp ├── .github └── FUNDING.yml ├── release_body.md ├── BravelyDefault2Fix.ini ├── LICENSE ├── BravelyDefault2Fix.sln ├── README.md ├── BravelyDefault2Fix.filters ├── .gitattributes ├── .gitignore └── BravelyDefault2Fix.vcxproj /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | 2 | ko_fi: lyall 3 | -------------------------------------------------------------------------------- /src/external/inih/.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.o 3 | -------------------------------------------------------------------------------- /src/external/inih/.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: false 3 | install: 4 | - g++ INIReaderTest.cpp -o INIReaderTest.out 5 | script: 6 | - ./INIReaderTest.out 7 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | -------------------------------------------------------------------------------- /release_body.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | - Unzip in to the game directory (e.g **steamapps\common\Bravely Default II**). 3 | - Edit **BravelyDefault2Fix.ini** to enable/adjust features. 4 | -------------------------------------------------------------------------------- /src/external/inih/test.ini: -------------------------------------------------------------------------------- 1 | ; Test config file for ini_example.c and INIReaderTest.cpp 2 | 3 | [protocol] ; Protocol configuration 4 | version=6 ; IPv6 5 | 6 | [user] 7 | name = Bob Smith ; Spaces around '=' are stripped 8 | email = bob@smith.com ; And comments (like this) ignored 9 | active = true ; Test a boolean 10 | pi = 3.14159 ; Test a floating point number 11 | multi = this is a ; test 12 | multi-line value ; test 13 | -------------------------------------------------------------------------------- /src/proxy.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllMain_stub @1 3 | XInputGetState @2 4 | XInputSetState @3 5 | XInputGetCapabilities @4 6 | XInputEnable @5 7 | XInputGetDSoundAudioDeviceGuids @6 8 | XInputGetBatteryInformation @7 9 | XInputGetKeystroke @8 10 | DirectInput8Create @9 11 | DXGIDumpJournal @10 12 | CreateDXGIFactory @11 13 | CreateDXGIFactory1 @12 14 | CreateDXGIFactory2 @13 15 | DXGID3D10CreateDevice @14 16 | DXGID3D10CreateLayeredDevice @15 17 | DXGID3D10GetLayeredDeviceSize @17 18 | DXGID3D10RegisterLayers @18 19 | DXGIGetDebugInterface1 @19 20 | DXGIReportAdapterConfiguration @20 21 | X3DAudioInitialize @21 22 | X3DAudioCalculate @22 23 | CreateFX @23 -------------------------------------------------------------------------------- /BravelyDefault2Fix.ini: -------------------------------------------------------------------------------- 1 | ------ Ultrawide Fixes ------ 2 | 3 | [Custom Resolution] 4 | ; Enter your chosen resolution. 5 | ; This is used for calculations related to fixes. 6 | ; You can leave these at 0 if you want your desktop resolution used as a reference instead. 7 | Width = 0 8 | Height = 0 9 | 10 | [Fix Resolution] 11 | ; Overwrites in-game option for 1280x720 with your desktop/custom resolution. 12 | ; I strongly recommend using borderless/windowed. 13 | ; Fullscreen resolutions in game are buggy even without this fix. 14 | Enable = true 15 | 16 | [Fix Aspect Ratio] 17 | ; Fixes aspect ratio. 18 | Enabled = true 19 | 20 | [Fix FOV] 21 | ; Corrects vert- FOV 22 | Enabled = true 23 | 24 | [Fix HUD] 25 | ; Constrains HUD to 16:9 26 | Enabled = true 27 | 28 | [r.ScreenPercentage] 29 | ; High settings forces 130% resolution scaling. 30 | ; You can override this here. 31 | Enabled = false 32 | Value = 100 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Lyall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/external/inih/INIReaderTest.cpp: -------------------------------------------------------------------------------- 1 | // Example that shows simple usage of the INIReader class 2 | 3 | #include 4 | #include 5 | #include "INIReader.h" 6 | 7 | std::string sections(INIReader &reader) 8 | { 9 | std::stringstream ss; 10 | std::set sections = reader.Sections(); 11 | for (std::set::iterator it = sections.begin(); it != sections.end(); ++it) 12 | ss << *it << ","; 13 | return ss.str(); 14 | } 15 | 16 | int main() 17 | { 18 | INIReader reader("test.ini"); 19 | 20 | if (reader.ParseError() < 0) { 21 | std::cout << "Can't load 'test.ini'\n"; 22 | return 1; 23 | } 24 | std::cout << "Config loaded from 'test.ini': found sections=" << sections(reader) 25 | << " version=" 26 | << reader.GetInteger("protocol", "version", -1) << ", name=" 27 | << reader.Get("user", "name", "UNKNOWN") << ", email=" 28 | << reader.Get("user", "email", "UNKNOWN") << ", multi=" 29 | << reader.Get("user", "multi", "UNKNOWN") << ", pi=" 30 | << reader.GetReal("user", "pi", -1) << ", active=" 31 | << reader.GetBoolean("user", "active", true) << "\n"; 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /BravelyDefault2Fix.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32414.318 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BravelyDefault2Fix", "BravelyDefault2Fix.vcxproj", "{408040DF-6069-4803-B22D-FDB135D98B95}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {408040DF-6069-4803-B22D-FDB135D98B95}.Debug|x64.ActiveCfg = Debug|x64 17 | {408040DF-6069-4803-B22D-FDB135D98B95}.Debug|x64.Build.0 = Debug|x64 18 | {408040DF-6069-4803-B22D-FDB135D98B95}.Debug|x86.ActiveCfg = Debug|Win32 19 | {408040DF-6069-4803-B22D-FDB135D98B95}.Debug|x86.Build.0 = Debug|Win32 20 | {408040DF-6069-4803-B22D-FDB135D98B95}.Release|x64.ActiveCfg = Release|x64 21 | {408040DF-6069-4803-B22D-FDB135D98B95}.Release|x64.Build.0 = Release|x64 22 | {408040DF-6069-4803-B22D-FDB135D98B95}.Release|x86.ActiveCfg = Release|Win32 23 | {408040DF-6069-4803-B22D-FDB135D98B95}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {781A5AA6-6176-46C6-AF57-C044E9A1267E} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bravely Default 2 Fix 2 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/W7W01UAI9)
3 | [![Github All Releases](https://img.shields.io/github/downloads/Lyall/BravelyDefault2Fix/total.svg)](https://github.com/Lyall/BravelyDefault2Fix/releases) 4 | 5 | This is a DLL hook that adds ultrawide/custom resolution support to Bravely Default 2.
6 | 7 | ## Features 8 | - Support for ultrawide/custom resolutions. 9 | - Centered 16:9 HUD. 10 | - Hor+ FOV (Vert+ for <16:9) and FOV adjustment. 11 | 12 | ## Installation 13 | - Downloaded the [latest release](https://github.com/Lyall/BravelyDefault2Fix/releases) of BravelyDefault2Fix. 14 | - Unzip in to the game directory (e.g **steamapps\common\BRAVELY DEFAULT II**). 15 | - Edit **BravelyDefault2Fix.ini** to enable/adjust features. 16 | 17 | ## Known Issues 18 | - I recommend only using windowed/borderless. Fullscreen mode in this game is buggy even without this fix. 19 | - The game is designed around 16:9. You may see glitches/pop-in outside the 16:9 frame, especially in cutscenes. 20 | 21 | ## Screenshots 22 | ![ezgif-3-86f9b2c108](https://user-images.githubusercontent.com/695941/176579058-d008aba0-3aad-4729-80d0-f8346fb4a5a4.gif) 23 | 24 | ## Credits 25 | [killer-m]() on the WSGF discord for the pillarbox removal bytes.
26 | [WSGF](https://www.wsgf.org/article/common-hex-values) for info on FOV calculation.
27 | [RERevHook](https://www.nexusmods.com/residentevilrevelations/mods/26) for the DLL proxy code.
28 | [inih](https://github.com/jtilly/inih) for ini reading. 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/external/inih/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | The "inih" library is distributed under the New BSD license: 3 | 4 | Copyright (c) 2009, Ben Hoyt 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of Ben Hoyt nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /BravelyDefault2Fix.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | Source Files 39 | 40 | 41 | Header Files 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/external/inih/README.md: -------------------------------------------------------------------------------- 1 | # inih 2 | [![Build Status](https://travis-ci.org/jtilly/inih.svg?branch=master)](https://travis-ci.org/jtilly/inih) 3 | 4 | This is a header only C++ version of [inih](https://github.com/benhoyt/inih). 5 | 6 | **inih (INI Not Invented Here)** is a simple [.INI file](http://en.wikipedia.org/wiki/INI_file) parser written in C. It's only a couple of pages of code, and it was designed to be _small and simple_, so it's good for embedded systems. It's also more or less compatible with Python's [ConfigParser](http://docs.python.org/library/configparser.html) style of .INI files, including RFC 822-style multi-line syntax and `name: value` entries. 7 | 8 | ## Usage 9 | 10 | All you need to do is to include `INIReader.h`. Consider the following example (`INIReaderTest.cpp`): 11 | 12 | ```cpp 13 | #include 14 | #include "INIReader.h" 15 | 16 | int main() { 17 | 18 | INIReader reader("test.ini"); 19 | 20 | if (reader.ParseError() != 0) { 21 | std::cout << "Can't load 'test.ini'\n"; 22 | return 1; 23 | } 24 | std::cout << "Config loaded from 'test.ini': version=" 25 | << reader.GetInteger("protocol", "version", -1) << ", name=" 26 | << reader.Get("user", "name", "UNKNOWN") << ", email=" 27 | << reader.Get("user", "email", "UNKNOWN") << ", pi=" 28 | << reader.GetReal("user", "pi", -1) << ", active=" 29 | << reader.GetBoolean("user", "active", true) << "\n"; 30 | return 0; 31 | 32 | } 33 | ``` 34 | 35 | To compile and run: 36 | 37 | ```sh 38 | g++ INIReaderTest.cpp -o INIReaderTest.out 39 | ./INIReaderTest.out 40 | # Config loaded from 'test.ini': version=6, name=Bob Smith, email=bob@smith.com, pi=3.14159, active=1 41 | ``` 42 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/helper.hpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace Memory 7 | { 8 | template 9 | void Write(uintptr_t writeAddress, T value) 10 | { 11 | DWORD oldProtect; 12 | VirtualProtect((LPVOID)(writeAddress), sizeof(T), PAGE_EXECUTE_WRITECOPY, &oldProtect); 13 | *(reinterpret_cast(writeAddress)) = value; 14 | VirtualProtect((LPVOID)(writeAddress), sizeof(T), oldProtect, &oldProtect); 15 | } 16 | 17 | void PatchBytes(uintptr_t address, const char* pattern, unsigned int numBytes) 18 | { 19 | DWORD oldProtect; 20 | VirtualProtect((LPVOID)address, numBytes, PAGE_EXECUTE_READWRITE, &oldProtect); 21 | memcpy((LPVOID)address, pattern, numBytes); 22 | VirtualProtect((LPVOID)address, numBytes, oldProtect, &oldProtect); 23 | } 24 | 25 | uintptr_t ReadMultiLevelPointer(uintptr_t base, const std::vector& offsets) 26 | { 27 | MEMORY_BASIC_INFORMATION mbi; 28 | for (auto& offset : offsets) 29 | { 30 | if (!VirtualQuery(reinterpret_cast(base), &mbi, sizeof(MEMORY_BASIC_INFORMATION)) || mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) 31 | return 0; 32 | 33 | base = *reinterpret_cast(base) + offset; 34 | } 35 | 36 | return base; 37 | } 38 | 39 | void* DetourFunction64(void* pSource, void* pDestination, int dwLen) 40 | { 41 | DWORD MinLen = 14; 42 | 43 | if (dwLen < MinLen) return NULL; 44 | 45 | BYTE stub[] = { 46 | 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [$+6] 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ptr 48 | }; 49 | 50 | void* pTrampoline = VirtualAlloc(0, dwLen + sizeof(stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 51 | 52 | DWORD dwOld = 0; 53 | VirtualProtect(pSource, dwLen, PAGE_EXECUTE_READWRITE, &dwOld); 54 | 55 | DWORD64 retto = (DWORD64)pSource + dwLen; 56 | 57 | // trampoline 58 | memcpy(stub + 6, &retto, 8); 59 | memcpy((void*)((DWORD_PTR)pTrampoline), pSource, dwLen); 60 | memcpy((void*)((DWORD_PTR)pTrampoline + dwLen), stub, sizeof(stub)); 61 | 62 | // orig 63 | memcpy(stub + 6, &pDestination, 8); 64 | memcpy(pSource, stub, sizeof(stub)); 65 | 66 | for (int i = MinLen; i < dwLen; i++) 67 | { 68 | *(BYTE*)((DWORD_PTR)pSource + i) = 0x90; 69 | } 70 | 71 | VirtualProtect(pSource, dwLen, dwOld, &dwOld); 72 | return (void*)((DWORD_PTR)pTrampoline); 73 | } 74 | 75 | // CSGOSimple's pattern scan 76 | // https://github.com/OneshotGH/CSGOSimple-master/blob/master/CSGOSimple/helpers/utils.cpp 77 | std::uint8_t* PatternScan(void* module, const char* signature) 78 | { 79 | static auto pattern_to_byte = [](const char* pattern) { 80 | auto bytes = std::vector{}; 81 | auto start = const_cast(pattern); 82 | auto end = const_cast(pattern) + strlen(pattern); 83 | 84 | for (auto current = start; current < end; ++current) { 85 | if (*current == '?') { 86 | ++current; 87 | if (*current == '?') 88 | ++current; 89 | bytes.push_back(-1); 90 | } 91 | else { 92 | bytes.push_back(strtoul(current, ¤t, 16)); 93 | } 94 | } 95 | return bytes; 96 | }; 97 | 98 | auto dosHeader = (PIMAGE_DOS_HEADER)module; 99 | auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module + dosHeader->e_lfanew); 100 | 101 | auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage; 102 | auto patternBytes = pattern_to_byte(signature); 103 | auto scanBytes = reinterpret_cast(module); 104 | 105 | auto s = patternBytes.size(); 106 | auto d = patternBytes.data(); 107 | 108 | for (auto i = 0ul; i < sizeOfImage - s; ++i) { 109 | bool found = true; 110 | for (auto j = 0ul; j < s; ++j) { 111 | if (scanBytes[i + j] != d[j] && d[j] != -1) { 112 | found = false; 113 | break; 114 | } 115 | } 116 | if (found) { 117 | return &scanBytes[i]; 118 | } 119 | } 120 | return nullptr; 121 | } 122 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /BravelyDefault2Fix.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 16.0 36 | Win32Proj 37 | {408040df-6069-4803-b22d-fdb135d98b95} 38 | BravelyDefault2Fix 39 | 10.0 40 | 41 | 42 | 43 | DynamicLibrary 44 | true 45 | Intel C++ Compiler 19.2 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | Intel C++ Compiler 19.2 52 | true 53 | Unicode 54 | 55 | 56 | DynamicLibrary 57 | true 58 | Intel C++ Compiler 19.2 59 | Unicode 60 | 61 | 62 | DynamicLibrary 63 | false 64 | Intel C++ Compiler 19.2 65 | true 66 | Unicode 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | true 88 | 89 | 90 | false 91 | 92 | 93 | true 94 | xinput1_3 95 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 96 | 97 | 98 | false 99 | xinput1_3 100 | 101 | 102 | 103 | Level3 104 | true 105 | WIN32;_DEBUG;RESONANCEOFFATEFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 106 | true 107 | NotUsing 108 | pch.h 109 | 110 | 111 | Windows 112 | true 113 | false 114 | 115 | 116 | 117 | 118 | 119 | 120 | Level3 121 | true 122 | true 123 | true 124 | WIN32;NDEBUG;RESONANCEOFFATEFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 125 | true 126 | NotUsing 127 | pch.h 128 | 129 | 130 | Windows 131 | true 132 | true 133 | true 134 | false 135 | src/proxy.def 136 | 137 | 138 | 139 | 140 | Level3 141 | true 142 | _DEBUG;RESONANCEOFFATEFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 143 | true 144 | NotUsing 145 | pch.h 146 | Default 147 | C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\lib;%(AdditionalIncludeDirectories) 148 | 149 | 150 | Windows 151 | true 152 | false 153 | src/proxy.def 154 | 155 | 156 | 157 | 158 | Level3 159 | true 160 | true 161 | true 162 | NDEBUG;RESONANCEOFFATEFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 163 | true 164 | NotUsing 165 | pch.h 166 | 167 | 168 | Windows 169 | true 170 | true 171 | true 172 | false 173 | src/proxy.def 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /src/proxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | 5 | #define PLUGIN_API extern "C" __declspec(dllexport) 6 | 7 | // XAPOFX1_5.dll 8 | typedef DWORD(WINAPI* CreateFX_ptr)(REFCLSID clsid, void* pEffect); 9 | 10 | CreateFX_ptr CreateFX_orig; 11 | 12 | PLUGIN_API DWORD WINAPI CreateFX(REFCLSID clsid, void* pEffect) 13 | { 14 | return CreateFX_orig(clsid, pEffect); 15 | } 16 | 17 | // X3DAudio1_7 18 | typedef DWORD(WINAPI* X3DAudioInitialize_ptr)(UINT32 SpeakerChannelMask, float SpeedOfSound, void* Instance); 19 | typedef DWORD(WINAPI* X3DAudioCalculate_ptr)(void* Instance, void* pListener, void* pEmitter, UINT32 Flags, void* pDSPSettings); 20 | 21 | X3DAudioInitialize_ptr X3DAudioInitialize_orig; 22 | X3DAudioCalculate_ptr X3DAudioCalculate_orig; 23 | 24 | PLUGIN_API DWORD WINAPI X3DAudioInitialize(UINT32 SpeakerChannelMask, float SpeedOfSound, void* Instance) 25 | { 26 | return X3DAudioInitialize_orig(SpeakerChannelMask, SpeedOfSound, Instance); 27 | } 28 | 29 | PLUGIN_API DWORD WINAPI X3DAudioCalculate(void* Instance, void* pListener, void* pEmitter, UINT32 Flags, void* pDSPSettings) 30 | { 31 | return X3DAudioCalculate_orig(Instance, pListener, pEmitter, Flags, pDSPSettings); 32 | } 33 | 34 | // XInput1_3 and XInput9_1_0 35 | typedef DWORD(WINAPI* XInputGetState_ptr)(DWORD dwUserIndex, void* pState); 36 | typedef DWORD(WINAPI* XInputSetState_ptr)(DWORD dwUserIndex, void* pVibration); 37 | typedef DWORD(WINAPI* XInputGetCapabilities_ptr)(DWORD dwUserIndex, DWORD dwFlags, void* pCapabilities); 38 | typedef void(WINAPI* XInputEnable_ptr)(BOOL enable); 39 | typedef DWORD(WINAPI* XInputGetDSoundAudioDeviceGuids_ptr)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid); 40 | typedef DWORD(WINAPI* XInputGetBatteryInformation_ptr)(DWORD dwUserIndex, BYTE devType, void* pBatteryInformation); 41 | typedef DWORD(WINAPI* XInputGetKeystroke_ptr)(DWORD dwUserIndex, DWORD dwReserved, void* pKeystroke); 42 | 43 | XInputGetState_ptr XInputGetState_orig; 44 | XInputSetState_ptr XInputSetState_orig; 45 | XInputGetCapabilities_ptr XInputGetCapabilities_orig; 46 | XInputEnable_ptr XInputEnable_orig; 47 | XInputGetDSoundAudioDeviceGuids_ptr XInputGetDSoundAudioDeviceGuids_orig; 48 | XInputGetBatteryInformation_ptr XInputGetBatteryInformation_orig; 49 | XInputGetKeystroke_ptr XInputGetKeystroke_orig; 50 | 51 | // xinput1_3 needs everything at the proper ordinal, proxy.def handles that, but we need something for ordinal 1 so: 52 | PLUGIN_API void DllMain_stub() 53 | { 54 | 55 | } 56 | 57 | PLUGIN_API DWORD WINAPI XInputGetState(DWORD dwUserIndex, void* pState) 58 | { 59 | return XInputGetState_orig(dwUserIndex, pState); 60 | } 61 | 62 | PLUGIN_API DWORD WINAPI XInputSetState(DWORD dwUserIndex, void* pVibration) 63 | { 64 | return XInputSetState_orig(dwUserIndex, pVibration); 65 | } 66 | 67 | PLUGIN_API DWORD WINAPI XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, void* pCapabilities) 68 | { 69 | return XInputGetCapabilities_orig(dwUserIndex, dwFlags, pCapabilities); 70 | } 71 | 72 | PLUGIN_API void WINAPI XInputEnable(BOOL enable) 73 | { 74 | XInputEnable_orig(enable); 75 | } 76 | 77 | PLUGIN_API DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid) 78 | { 79 | return XInputGetDSoundAudioDeviceGuids_orig(dwUserIndex, pDSoundRenderGuid, pDSoundCaptureGuid); 80 | } 81 | 82 | PLUGIN_API DWORD WINAPI XInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, void* pBatteryInformation) 83 | { 84 | return XInputGetBatteryInformation_orig(dwUserIndex, devType, pBatteryInformation); 85 | } 86 | 87 | PLUGIN_API DWORD WINAPI XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, void* pKeystroke) 88 | { 89 | return XInputGetKeystroke_orig(dwUserIndex, dwReserved, pKeystroke); 90 | } 91 | 92 | //dinput8.dll 93 | typedef HRESULT(WINAPI* DirectInput8Create_ptr)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, void* punkOuter); 94 | 95 | DirectInput8Create_ptr DirectInput8Create_orig; 96 | 97 | PLUGIN_API HRESULT WINAPI DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, void* punkOuter) 98 | { 99 | return DirectInput8Create_orig(hinst, dwVersion, riidltf, ppvOut, punkOuter); 100 | } 101 | 102 | //dxgi.dll 103 | struct UNKNOWN { 104 | BYTE unknown[20]; 105 | }; 106 | 107 | typedef HRESULT(WINAPI* DXGIDumpJournal_ptr)(void* unk); 108 | typedef HRESULT(WINAPI* CreateDXGIFactory_ptr)(REFIID riid, void** ppFactory); 109 | typedef HRESULT(WINAPI* CreateDXGIFactory1_ptr)(REFIID riid, void** ppFactory); 110 | typedef HRESULT(WINAPI* CreateDXGIFactory2_ptr)(UINT Flags, REFIID riid, void** ppFactory); 111 | typedef HRESULT(WINAPI* DXGID3D10CreateDevice_ptr)(HMODULE hModule, void* pFactory, void* pAdapter, UINT Flags, void* unknown, void* ppDevice); 112 | typedef HRESULT(WINAPI* DXGID3D10CreateLayeredDevice_ptr)(UNKNOWN unk); 113 | typedef size_t(WINAPI* DXGID3D10GetLayeredDeviceSize_ptr)(const void* pLayers, UINT NumLayers); 114 | typedef HRESULT(WINAPI* DXGID3D10RegisterLayers_ptr)(const void* pLayers, UINT NumLayers); 115 | typedef HRESULT(WINAPI* DXGIGetDebugInterface1_ptr)(UINT Flags, REFIID riid, void** pDebug); 116 | typedef HRESULT(WINAPI* DXGIReportAdapterConfiguration_ptr)(DWORD unk); 117 | 118 | DXGIDumpJournal_ptr DXGIDumpJournal_orig; 119 | CreateDXGIFactory_ptr CreateDXGIFactory_orig; 120 | CreateDXGIFactory1_ptr CreateDXGIFactory1_orig; 121 | CreateDXGIFactory2_ptr CreateDXGIFactory2_orig; 122 | DXGID3D10CreateDevice_ptr DXGID3D10CreateDevice_orig; 123 | DXGID3D10CreateLayeredDevice_ptr DXGID3D10CreateLayeredDevice_orig; 124 | DXGID3D10GetLayeredDeviceSize_ptr DXGID3D10GetLayeredDeviceSize_orig; 125 | DXGID3D10RegisterLayers_ptr DXGID3D10RegisterLayers_orig; 126 | DXGIGetDebugInterface1_ptr DXGIGetDebugInterface1_orig; 127 | DXGIReportAdapterConfiguration_ptr DXGIReportAdapterConfiguration_orig; 128 | 129 | PLUGIN_API HRESULT WINAPI DXGIDumpJournal(void* unk) 130 | { 131 | return DXGIDumpJournal_orig(unk); 132 | } 133 | 134 | PLUGIN_API HRESULT WINAPI CreateDXGIFactory(REFIID riid, _Out_ void** ppFactory) 135 | { 136 | return CreateDXGIFactory_orig(riid, ppFactory); 137 | } 138 | 139 | PLUGIN_API HRESULT WINAPI CreateDXGIFactory1(REFIID riid, _Out_ void** ppFactory) 140 | { 141 | return CreateDXGIFactory1_orig(riid, ppFactory); 142 | } 143 | 144 | PLUGIN_API HRESULT WINAPI CreateDXGIFactory2(UINT Flags, REFIID riid, _Out_ void** ppFactory) 145 | { 146 | return CreateDXGIFactory2_orig(Flags, riid, ppFactory); 147 | } 148 | 149 | PLUGIN_API HRESULT WINAPI DXGID3D10CreateDevice(HMODULE hModule, void* pFactory, void* pAdapter, UINT Flags, void* unknown, void* ppDevice) 150 | { 151 | return DXGID3D10CreateDevice_orig(hModule, pFactory, pAdapter, Flags, unknown, ppDevice); 152 | } 153 | 154 | PLUGIN_API HRESULT WINAPI DXGID3D10CreateLayeredDevice(UNKNOWN unk) 155 | { 156 | return DXGID3D10CreateLayeredDevice_orig(unk); 157 | } 158 | 159 | PLUGIN_API size_t WINAPI DXGID3D10GetLayeredDeviceSize(const void* pLayers, UINT NumLayers) 160 | { 161 | return DXGID3D10GetLayeredDeviceSize_orig(pLayers, NumLayers); 162 | } 163 | 164 | PLUGIN_API HRESULT WINAPI DXGID3D10RegisterLayers(const void* pLayers, UINT NumLayers) 165 | { 166 | return DXGID3D10RegisterLayers_orig(pLayers, NumLayers); 167 | } 168 | 169 | PLUGIN_API HRESULT WINAPI DXGIGetDebugInterface1(UINT Flags, REFIID riid, void** pDebug) 170 | { 171 | return DXGIGetDebugInterface1_orig(Flags, riid, pDebug); 172 | } 173 | 174 | PLUGIN_API HRESULT WINAPI DXGIReportAdapterConfiguration(DWORD unk) 175 | { 176 | return DXGIReportAdapterConfiguration_orig(unk); 177 | } 178 | 179 | HMODULE origModule = NULL; 180 | 181 | bool Proxy_Attach() 182 | { 183 | extern HMODULE ourModule; 184 | 185 | // get the filename of our DLL and try loading the DLL with the same name from system dir 186 | WCHAR modulePath[MAX_PATH] = { 0 }; 187 | if (!GetSystemDirectoryW(modulePath, _countof(modulePath))) 188 | return false; 189 | 190 | WCHAR ourModulePath[MAX_PATH] = { 0 }; 191 | GetModuleFileNameW(ourModule, ourModulePath, _countof(ourModulePath)); 192 | 193 | WCHAR exeName[MAX_PATH] = { 0 }; 194 | WCHAR extName[MAX_PATH] = { 0 }; 195 | _wsplitpath_s(ourModulePath, NULL, NULL, NULL, NULL, exeName, MAX_PATH, extName, MAX_PATH); 196 | 197 | swprintf_s(modulePath, MAX_PATH, L"%ws\\%ws%ws", modulePath, exeName, extName); 198 | 199 | origModule = LoadLibraryW(modulePath); 200 | if (!origModule) 201 | return false; 202 | 203 | XInputGetCapabilities_orig = (XInputGetCapabilities_ptr)GetProcAddress(origModule, "XInputGetCapabilities"); 204 | XInputGetDSoundAudioDeviceGuids_orig = (XInputGetDSoundAudioDeviceGuids_ptr)GetProcAddress(origModule, "XInputGetDSoundAudioDeviceGuids"); 205 | XInputGetState_orig = (XInputGetState_ptr)GetProcAddress(origModule, "XInputGetState"); 206 | XInputSetState_orig = (XInputSetState_ptr)GetProcAddress(origModule, "XInputSetState"); 207 | XInputEnable_orig = (XInputEnable_ptr)GetProcAddress(origModule, "XInputEnable"); 208 | XInputGetBatteryInformation_orig = (XInputGetBatteryInformation_ptr)GetProcAddress(origModule, "XInputGetBatteryInformation"); 209 | XInputGetKeystroke_orig = (XInputGetKeystroke_ptr)GetProcAddress(origModule, "XInputGetKeystroke"); 210 | 211 | DirectInput8Create_orig = (DirectInput8Create_ptr)GetProcAddress(origModule, "DirectInput8Create"); 212 | 213 | DXGIDumpJournal_orig = (DXGIDumpJournal_ptr)GetProcAddress(origModule, "DXGIDumpJournal"); 214 | CreateDXGIFactory_orig = (CreateDXGIFactory_ptr)GetProcAddress(origModule, "CreateDXGIFactory"); 215 | CreateDXGIFactory1_orig = (CreateDXGIFactory1_ptr)GetProcAddress(origModule, "CreateDXGIFactory1"); 216 | CreateDXGIFactory2_orig = (CreateDXGIFactory2_ptr)GetProcAddress(origModule, "CreateDXGIFactory2"); 217 | DXGID3D10CreateDevice_orig = (DXGID3D10CreateDevice_ptr)GetProcAddress(origModule, "DXGID3D10CreateDevice"); 218 | DXGID3D10CreateLayeredDevice_orig = (DXGID3D10CreateLayeredDevice_ptr)GetProcAddress(origModule, "DXGID3D10CreateLayeredDevice"); 219 | DXGID3D10GetLayeredDeviceSize_orig = (DXGID3D10GetLayeredDeviceSize_ptr)GetProcAddress(origModule, "DXGID3D10GetLayeredDeviceSize"); 220 | DXGID3D10RegisterLayers_orig = (DXGID3D10RegisterLayers_ptr)GetProcAddress(origModule, "DXGID3D10RegisterLayers"); 221 | DXGIGetDebugInterface1_orig = (DXGIGetDebugInterface1_ptr)GetProcAddress(origModule, "DXGIGetDebugInterface1"); 222 | DXGIReportAdapterConfiguration_orig = (DXGIReportAdapterConfiguration_ptr)GetProcAddress(origModule, "DXGIReportAdapterConfiguration"); 223 | 224 | X3DAudioInitialize_orig = (X3DAudioInitialize_ptr)GetProcAddress(origModule, "X3DAudioInitialize"); 225 | X3DAudioCalculate_orig = (X3DAudioCalculate_ptr)GetProcAddress(origModule, "X3DAudioCalculate"); 226 | 227 | CreateFX_orig = (CreateFX_ptr)GetProcAddress(origModule, "CreateFX"); 228 | 229 | return true; 230 | } 231 | 232 | void Proxy_Detach() 233 | { 234 | if (!origModule) 235 | return; 236 | 237 | FreeLibrary(origModule); 238 | origModule = nullptr; 239 | } 240 | -------------------------------------------------------------------------------- /src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "external/inih/INIReader.h" 3 | #include "helper.hpp" 4 | 5 | bool Proxy_Attach(); 6 | void Proxy_Detach(); 7 | 8 | using namespace std; 9 | 10 | HMODULE baseModule = GetModuleHandle(NULL); 11 | 12 | // INI Variables 13 | bool bResFix; 14 | bool bAspectFix; 15 | bool bHUDFix; 16 | bool bFOVFix; 17 | int iCustomResX; 18 | int iCustomResY; 19 | bool bResScale; 20 | float fResScale; 21 | 22 | // Variables 23 | float fNewX; 24 | float fNewY; 25 | float fNativeAspect = 1.777777791f; 26 | float fPi = 3.14159265358979323846f; 27 | float fDefaultHUDWidth = 1920; 28 | float fDefaultHUDHeight = 1080; 29 | float fNewAspect; 30 | 31 | // FOV Hook 32 | DWORD64 FOVFixReturnJMP; 33 | float FOVPiDiv; 34 | float FOVDivPi; 35 | float FOVFinalValue; 36 | void __declspec(naked) FOVFix_CC() 37 | { 38 | __asm 39 | { 40 | fld dword ptr[rbx + 0x00000218] 41 | fmul [FOVPiDiv] 42 | fptan 43 | fxch st(1) 44 | fdiv [fNativeAspect] 45 | fmul [fNewAspect] 46 | fxch st(1) 47 | fpatan 48 | fmul [FOVDivPi] 49 | fstp [FOVFinalValue] 50 | movss xmm0, [FOVFinalValue] 51 | movss [rdi + 0x18], xmm0 52 | mov eax, [rbx + 0x00000228] 53 | jmp[FOVFixReturnJMP] 54 | } 55 | } 56 | 57 | // HUD Width Hook 58 | DWORD64 HUDWidthReturnJMP; 59 | void __declspec(naked) HUDWidth_CC() 60 | { 61 | __asm 62 | { 63 | movss xmm9, [fDefaultHUDWidth] 64 | movss xmm6, [fDefaultHUDHeight] 65 | movss [rsp + 0x30], xmm9 66 | movss [rsp + 0x34], xmm6 67 | mov byte ptr [rsp + 0x38], 01 68 | jmp[HUDWidthReturnJMP] 69 | } 70 | } 71 | 72 | // HUD Offset Hook 73 | DWORD64 HUDOffsetReturnJMP; 74 | float HUDHorOffsetValue; 75 | float HUDVerOffsetValue; 76 | void __declspec(naked) HUDOffset_CC() 77 | { 78 | __asm 79 | { 80 | movss xmm7, [HUDHorOffsetValue] 81 | movss xmm8, [HUDVerOffsetValue] 82 | movss [rsp + 0x30], xmm7 83 | movss [rsp + 0x34], xmm8 84 | mov byte ptr [rsp + 0x38], 01 85 | jmp[HUDOffsetReturnJMP] 86 | } 87 | } 88 | 89 | // r.ScreenPercentage Hook 90 | DWORD64 ResScaleReturnJMP; 91 | float fResScaleValue = 0.009999999776f; 92 | void __declspec(naked) ResScale_CC() 93 | { 94 | __asm 95 | { 96 | setne bl 97 | movss xmm1, [fResScale] 98 | xorps xmm0, xmm0 99 | mulss xmm1, [fResScaleValue] 100 | jmp[ResScaleReturnJMP] 101 | } 102 | } 103 | 104 | void ReadConfig() 105 | { 106 | INIReader config("BravelyDefault2Fix.ini"); 107 | 108 | bResFix = config.GetBoolean("Fix Resolution", "Enabled", true); 109 | bAspectFix = config.GetBoolean("Fix Aspect Ratio", "Enabled", true); 110 | bHUDFix = config.GetBoolean("Fix HUD", "Enabled", true); 111 | bFOVFix = config.GetBoolean("Fix FOV", "Enabled", true); 112 | iCustomResX = config.GetInteger("Custom Resolution", "Width", -1); 113 | iCustomResY = config.GetInteger("Custom Resolution", "Height", -1); 114 | bResScale = config.GetBoolean("r.ScreenPercentage", "Enabled", true); 115 | fResScale = config.GetFloat("r.ScreenPercentage", "Value", 0); 116 | 117 | // Grab desktop resolution 118 | RECT desktop; 119 | GetWindowRect(GetDesktopWindow(), &desktop); 120 | fNewX = (float)desktop.right; 121 | fNewY = (float)desktop.bottom; 122 | fNewAspect = (float)desktop.right / (float)desktop.bottom; 123 | 124 | // Custom resolution enabled 125 | if (iCustomResX > 0 && iCustomResY > 0) 126 | { 127 | fNewX = (float)iCustomResX; 128 | fNewY = (float)iCustomResY; 129 | fNewAspect = (float)iCustomResX / (float)iCustomResY; 130 | } 131 | 132 | #if _DEBUG 133 | if (config.ParseError() != 0) { 134 | std::cout << "Can't load config file\n" << std::endl; 135 | std::cout << "Parse error: " << config.ParseError() << std::endl; 136 | } 137 | 138 | std::cout << printf("Config parse\nbResFix: %d\nbAspectFix : %d\nbHUDFix : %d\nbFOVFix : %d\niCustomResX : %d\niCustomResY : %d\nbResScale:: %d\nfResScale: %.4f\nfNewX : %.4f\nfNewY: %.4f\nfNewAspect: %.4f\n", 139 | bResFix, bAspectFix, bHUDFix, bFOVFix, iCustomResX, iCustomResY, bResScale, fResScale, fNewX, fNewY, fNewAspect) << std::endl; 140 | #endif 141 | } 142 | 143 | void ResolutionFix() 144 | { 145 | if (bResFix) 146 | { 147 | //Address of signature = Bravely_Default_II - Win64 - Shipping.exe + 0x009F3D0B 148 | uint8_t* ResScanResult = Memory::PatternScan(baseModule, "C7 02 ? ? ? ? 48 8B ? C7 42 04 ? ? ? ? C3 CC CC CC CC 66 0F"); 149 | 150 | if (ResScanResult) 151 | { 152 | Memory::Write((uintptr_t)(ResScanResult + 0x2), (int)fNewX); 153 | Memory::Write((uintptr_t)(ResScanResult + 0xC), (int)fNewY); 154 | #if _DEBUG 155 | std::cout << "1280x720 changed to: " << fNewX << "x" << fNewY << std::endl; 156 | #endif 157 | } 158 | 159 | if (bResScale) 160 | { 161 | // Bravely_Default_II-Win64-Shipping.exe+1FEA46F 162 | uint8_t* ResScaleScanResult = Memory::PatternScan(baseModule, "F3 0F 10 ?? ?? 0F ?? ?? F3 0F 59 ?? ?? ?? ?? ?? 0F ?? ?? 77 ?? F3 0F 10"); 163 | 164 | if (ResScaleScanResult) 165 | { 166 | int ResScaleHookLength = 19; 167 | DWORD64 ResScaleAddress = (uintptr_t)(ResScaleScanResult - 0x3); 168 | ResScaleReturnJMP = ResScaleAddress + ResScaleHookLength; 169 | Memory::DetourFunction64((void*)ResScaleAddress, ResScale_CC, ResScaleHookLength); 170 | 171 | #if _DEBUG 172 | std::cout << "r.ScreenPercentage forced to " << fResScale << std::endl; 173 | #endif 174 | } 175 | } 176 | } 177 | 178 | } 179 | 180 | void AspectFix() 181 | { 182 | if (bAspectFix) 183 | { 184 | // UE4 Pillarboxing 185 | // Credit: killer-m (WSGF Discord) 186 | // Address of signature = Bravely_Default_II - Win64 - Shipping.exe + 0x01BDC79A 187 | uint8_t* AspectFixScanResult = Memory::PatternScan(baseModule, "49 ? ? ? ? ? ? F6 ? ? 01 48 ? ? F3 44"); 188 | if (AspectFixScanResult) 189 | { 190 | Memory::PatchBytes((uintptr_t)(AspectFixScanResult + 0xA), "\x00", 1); 191 | 192 | #if _DEBUG 193 | std::cout << "Pillarboxing disabled" << std::endl; 194 | #endif 195 | } 196 | } 197 | } 198 | 199 | void FOVFix() 200 | { 201 | if (bFOVFix) 202 | { 203 | // Shoutout to WSGF's FOV calculations. I'm not good with maths. 204 | // https://www.wsgf.org/article/common-hex-values 205 | // Arctan(Tan(originalFOV * PI / 360) / (nativeAspect) * (newAspect)) * 360 / PI 206 | // Writing this in assembly sucked. But it allows for a dynamic FOV. 207 | 208 | // Address of signature = Bravely_Default_II - Win64 - Shipping.exe + 0x01BD9448 209 | uint8_t* FOVFixScanResult = Memory::PatternScan(baseModule, "F3 0F 10 ?? ?? ?? ?? ?? F3 0F 11 ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? 0F B6 ?? ?? ?? ?? ??"); 210 | if (FOVFixScanResult && fNewAspect > fNativeAspect) 211 | { 212 | int FOVFixHookLength = 19; 213 | DWORD64 FOVFixAddress = (uintptr_t)FOVFixScanResult; 214 | FOVFixReturnJMP = FOVFixAddress + FOVFixHookLength; 215 | FOVPiDiv = fPi / 360; 216 | FOVDivPi = 360 / fPi; 217 | Memory::DetourFunction64((void*)FOVFixAddress, FOVFix_CC, FOVFixHookLength); 218 | 219 | #if _DEBUG 220 | std::cout << "FOV converted to hor+" << std::endl; 221 | #endif 222 | } 223 | } 224 | } 225 | 226 | void HUDFix() 227 | { 228 | if (bHUDFix) 229 | { 230 | // Address of signature = Bravely_Default_II - Win64 - Shipping.exe + 0x01E0BD24 231 | uint8_t* HUDWidthScanResult = Memory::PatternScan(baseModule, "F3 44 ? ? ? ? ? F3 0F ? ? ? ? C6 44 24 38"); 232 | if (HUDWidthScanResult) 233 | { 234 | int HUDWidthHookLength = 18; 235 | DWORD64 HUDWidthAddress = (uintptr_t)HUDWidthScanResult; 236 | HUDWidthReturnJMP = HUDWidthAddress + HUDWidthHookLength; 237 | Memory::DetourFunction64((void*)HUDWidthAddress, HUDWidth_CC, HUDWidthHookLength); 238 | 239 | #if _DEBUG 240 | std::cout << "HUD width set to " << fDefaultHUDWidth << std::endl; 241 | #endif 242 | } 243 | 244 | // Address of signature = Bravely_Default_II - Win64 - Shipping.exe + 0x01E0BD6E 245 | uint8_t* HUDOffsetScanResult = Memory::PatternScan(baseModule, "F3 0F 11 ?? ?? ?? F3 44 0F 11 ?? ?? ?? C6 ?? ?? ?? 01 F3 0F 11"); 246 | if (HUDOffsetScanResult) 247 | { 248 | int HUDOffsetHookLength = 18; 249 | DWORD64 HUDOffsetAddress = (uintptr_t)HUDOffsetScanResult; 250 | HUDOffsetReturnJMP = HUDOffsetAddress + HUDOffsetHookLength; 251 | if (fNewAspect > fNativeAspect) 252 | { 253 | HUDHorOffsetValue = round(((fDefaultHUDWidth * (fNewAspect / fNativeAspect) - 1920) / 2)); 254 | HUDVerOffsetValue = 0; 255 | } 256 | else if (fNewAspect < fNativeAspect) 257 | { 258 | HUDHorOffsetValue = 0; 259 | HUDVerOffsetValue = round(((fDefaultHUDHeight * (fNativeAspect / fNewAspect) - fDefaultHUDHeight) / 2)); 260 | } 261 | Memory::DetourFunction64((void*)HUDOffsetAddress, HUDOffset_CC, HUDOffsetHookLength); 262 | 263 | #if _DEBUG 264 | std::cout << "HUD horizontal offset set to " << HUDHorOffsetValue << std::endl; 265 | std::cout << "HUD vertical offset set to " << HUDVerOffsetValue << std::endl; 266 | #endif 267 | } 268 | } 269 | } 270 | 271 | DWORD __stdcall Main(void*) 272 | { 273 | #if _DEBUG 274 | AllocConsole(); 275 | freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); 276 | std::cout << "Console initiated" << std::endl; 277 | #endif 278 | Sleep(500); 279 | ReadConfig(); 280 | ResolutionFix(); 281 | AspectFix(); 282 | FOVFix(); 283 | HUDFix(); 284 | 285 | return true; // end thread 286 | } 287 | 288 | HMODULE ourModule; 289 | 290 | void Patch_Uninit() 291 | { 292 | 293 | } 294 | 295 | BOOL APIENTRY DllMain(HMODULE hModule, int ul_reason_for_call, LPVOID lpReserved) 296 | { 297 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) 298 | { 299 | ourModule = hModule; 300 | Proxy_Attach(); 301 | 302 | CreateThread(NULL, 0, Main, 0, NULL, 0); 303 | } 304 | if (ul_reason_for_call == DLL_PROCESS_DETACH) 305 | { 306 | Patch_Uninit(); 307 | 308 | Proxy_Detach(); 309 | } 310 | 311 | return TRUE; 312 | } 313 | -------------------------------------------------------------------------------- /src/external/inih/INIReader.h: -------------------------------------------------------------------------------- 1 | // Read an INI file into easy-to-access name/value pairs. 2 | 3 | // inih and INIReader are released under the New BSD license (see LICENSE.txt). 4 | // Go to the project home page for more info: 5 | // 6 | // https://github.com/benhoyt/inih 7 | /* inih -- simple .INI file parser 8 | 9 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 10 | home page for more info: 11 | 12 | https://github.com/benhoyt/inih 13 | 14 | */ 15 | 16 | #ifndef __INI_H__ 17 | #define __INI_H__ 18 | 19 | /* Make this header file easier to include in C++ code */ 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | 26 | /* Typedef for prototype of handler function. */ 27 | typedef int (*ini_handler)(void* user, const char* section, 28 | const char* name, const char* value); 29 | 30 | /* Typedef for prototype of fgets-style reader function. */ 31 | typedef char* (*ini_reader)(char* str, int num, void* stream); 32 | 33 | /* Parse given INI-style file. May have [section]s, name=value pairs 34 | (whitespace stripped), and comments starting with ';' (semicolon). Section 35 | is "" if name=value pair parsed before any section heading. name:value 36 | pairs are also supported as a concession to Python's configparser. 37 | 38 | For each name=value pair parsed, call handler function with given user 39 | pointer as well as section, name, and value (data only valid for duration 40 | of handler call). Handler should return nonzero on success, zero on error. 41 | 42 | Returns 0 on success, line number of first error on parse error (doesn't 43 | stop on first error), -1 on file open error, or -2 on memory allocation 44 | error (only when INI_USE_STACK is zero). 45 | */ 46 | int ini_parse(const char* filename, ini_handler handler, void* user); 47 | 48 | /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't 49 | close the file when it's finished -- the caller must do that. */ 50 | int ini_parse_file(FILE* file, ini_handler handler, void* user); 51 | 52 | /* Same as ini_parse(), but takes an ini_reader function pointer instead of 53 | filename. Used for implementing custom or string-based I/O. */ 54 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, 55 | void* user); 56 | 57 | /* Nonzero to allow multi-line value parsing, in the style of Python's 58 | configparser. If allowed, ini_parse() will call the handler with the same 59 | name for each subsequent line parsed. */ 60 | #ifndef INI_ALLOW_MULTILINE 61 | #define INI_ALLOW_MULTILINE 1 62 | #endif 63 | 64 | /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 65 | the file. See http://code.google.com/p/inih/issues/detail?id=21 */ 66 | #ifndef INI_ALLOW_BOM 67 | #define INI_ALLOW_BOM 1 68 | #endif 69 | 70 | /* Nonzero to allow inline comments (with valid inline comment characters 71 | specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match 72 | Python 3.2+ configparser behaviour. */ 73 | #ifndef INI_ALLOW_INLINE_COMMENTS 74 | #define INI_ALLOW_INLINE_COMMENTS 1 75 | #endif 76 | #ifndef INI_INLINE_COMMENT_PREFIXES 77 | #define INI_INLINE_COMMENT_PREFIXES ";" 78 | #endif 79 | 80 | /* Nonzero to use stack, zero to use heap (malloc/free). */ 81 | #ifndef INI_USE_STACK 82 | #define INI_USE_STACK 1 83 | #endif 84 | 85 | /* Stop parsing on first error (default is to keep parsing). */ 86 | #ifndef INI_STOP_ON_FIRST_ERROR 87 | #define INI_STOP_ON_FIRST_ERROR 0 88 | #endif 89 | 90 | /* Maximum line length for any line in INI file. */ 91 | #ifndef INI_MAX_LINE 92 | #define INI_MAX_LINE 200 93 | #endif 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | /* inih -- simple .INI file parser 100 | 101 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 102 | home page for more info: 103 | 104 | https://github.com/benhoyt/inih 105 | 106 | */ 107 | 108 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 109 | #define _CRT_SECURE_NO_WARNINGS 110 | #endif 111 | 112 | #include 113 | #include 114 | #include 115 | 116 | #if !INI_USE_STACK 117 | #include 118 | #endif 119 | 120 | #define MAX_SECTION 50 121 | #define MAX_NAME 50 122 | 123 | /* Strip whitespace chars off end of given string, in place. Return s. */ 124 | inline static char* rstrip(char* s) 125 | { 126 | char* p = s + strlen(s); 127 | while (p > s && isspace((unsigned char)(*--p))) 128 | *p = '\0'; 129 | return s; 130 | } 131 | 132 | /* Return pointer to first non-whitespace char in given string. */ 133 | inline static char* lskip(const char* s) 134 | { 135 | while (*s && isspace((unsigned char)(*s))) 136 | s++; 137 | return (char*)s; 138 | } 139 | 140 | /* Return pointer to first char (of chars) or inline comment in given string, 141 | or pointer to null at end of string if neither found. Inline comment must 142 | be prefixed by a whitespace character to register as a comment. */ 143 | inline static char* find_chars_or_comment(const char* s, const char* chars) 144 | { 145 | #if INI_ALLOW_INLINE_COMMENTS 146 | int was_space = 0; 147 | while (*s && (!chars || !strchr(chars, *s)) && 148 | !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { 149 | was_space = isspace((unsigned char)(*s)); 150 | s++; 151 | } 152 | #else 153 | while (*s && (!chars || !strchr(chars, *s))) { 154 | s++; 155 | } 156 | #endif 157 | return (char*)s; 158 | } 159 | 160 | /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ 161 | inline static char* strncpy0(char* dest, const char* src, size_t size) 162 | { 163 | strncpy(dest, src, size); 164 | dest[size - 1] = '\0'; 165 | return dest; 166 | } 167 | 168 | /* See documentation in header file. */ 169 | inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, 170 | void* user) 171 | { 172 | /* Uses a fair bit of stack (use heap instead if you need to) */ 173 | #if INI_USE_STACK 174 | char line[INI_MAX_LINE]; 175 | #else 176 | char* line; 177 | #endif 178 | char section[MAX_SECTION] = ""; 179 | char prev_name[MAX_NAME] = ""; 180 | 181 | char* start; 182 | char* end; 183 | char* name; 184 | char* value; 185 | int lineno = 0; 186 | int error = 0; 187 | 188 | #if !INI_USE_STACK 189 | line = (char*)malloc(INI_MAX_LINE); 190 | if (!line) { 191 | return -2; 192 | } 193 | #endif 194 | 195 | /* Scan through stream line by line */ 196 | while (reader(line, INI_MAX_LINE, stream) != NULL) { 197 | lineno++; 198 | 199 | start = line; 200 | #if INI_ALLOW_BOM 201 | if (lineno == 1 && (unsigned char)start[0] == 0xEF && 202 | (unsigned char)start[1] == 0xBB && 203 | (unsigned char)start[2] == 0xBF) { 204 | start += 3; 205 | } 206 | #endif 207 | start = lskip(rstrip(start)); 208 | 209 | if (*start == ';' || *start == '#') { 210 | /* Per Python configparser, allow both ; and # comments at the 211 | start of a line */ 212 | } 213 | #if INI_ALLOW_MULTILINE 214 | else if (*prev_name && *start && start > line) { 215 | 216 | #if INI_ALLOW_INLINE_COMMENTS 217 | end = find_chars_or_comment(start, NULL); 218 | if (*end) 219 | *end = '\0'; 220 | rstrip(start); 221 | #endif 222 | 223 | /* Non-blank line with leading whitespace, treat as continuation 224 | of previous name's value (as per Python configparser). */ 225 | if (!handler(user, section, prev_name, start) && !error) 226 | error = lineno; 227 | } 228 | #endif 229 | else if (*start == '[') { 230 | /* A "[section]" line */ 231 | end = find_chars_or_comment(start + 1, "]"); 232 | if (*end == ']') { 233 | *end = '\0'; 234 | strncpy0(section, start + 1, sizeof(section)); 235 | *prev_name = '\0'; 236 | } 237 | else if (!error) { 238 | /* No ']' found on section line */ 239 | error = lineno; 240 | } 241 | } 242 | else if (*start) { 243 | /* Not a comment, must be a name[=:]value pair */ 244 | end = find_chars_or_comment(start, "=:"); 245 | if (*end == '=' || *end == ':') { 246 | *end = '\0'; 247 | name = rstrip(start); 248 | value = lskip(end + 1); 249 | #if INI_ALLOW_INLINE_COMMENTS 250 | end = find_chars_or_comment(value, NULL); 251 | if (*end) 252 | *end = '\0'; 253 | #endif 254 | rstrip(value); 255 | 256 | /* Valid name[=:]value pair found, call handler */ 257 | strncpy0(prev_name, name, sizeof(prev_name)); 258 | if (!handler(user, section, name, value) && !error) 259 | error = lineno; 260 | } 261 | else if (!error) { 262 | /* No '=' or ':' found on name[=:]value line */ 263 | error = lineno; 264 | } 265 | } 266 | 267 | #if INI_STOP_ON_FIRST_ERROR 268 | if (error) 269 | break; 270 | #endif 271 | } 272 | 273 | #if !INI_USE_STACK 274 | free(line); 275 | #endif 276 | 277 | return error; 278 | } 279 | 280 | /* See documentation in header file. */ 281 | inline int ini_parse_file(FILE* file, ini_handler handler, void* user) 282 | { 283 | return ini_parse_stream((ini_reader)fgets, file, handler, user); 284 | } 285 | 286 | /* See documentation in header file. */ 287 | inline int ini_parse(const char* filename, ini_handler handler, void* user) 288 | { 289 | FILE* file; 290 | int error; 291 | 292 | file = fopen(filename, "r"); 293 | if (!file) 294 | return -1; 295 | error = ini_parse_file(file, handler, user); 296 | fclose(file); 297 | return error; 298 | } 299 | 300 | #endif /* __INI_H__ */ 301 | 302 | 303 | #ifndef __INIREADER_H__ 304 | #define __INIREADER_H__ 305 | 306 | #include 307 | #include 308 | #include 309 | 310 | // Read an INI file into easy-to-access name/value pairs. (Note that I've gone 311 | // for simplicity here rather than speed, but it should be pretty decent.) 312 | class INIReader 313 | { 314 | public: 315 | // Empty Constructor 316 | INIReader() {}; 317 | 318 | // Construct INIReader and parse given filename. See ini.h for more info 319 | // about the parsing. 320 | explicit INIReader(const std::string& filename); 321 | 322 | // Construct INIReader and parse given file. See ini.h for more info 323 | // about the parsing. 324 | explicit INIReader(FILE *file); 325 | 326 | // Return the result of ini_parse(), i.e., 0 on success, line number of 327 | // first error on parse error, or -1 on file open error. 328 | int ParseError() const; 329 | 330 | // Return the list of sections found in ini file 331 | const std::set& Sections() const; 332 | 333 | // Get a string value from INI file, returning default_value if not found. 334 | std::string Get(const std::string& section, const std::string& name, 335 | const std::string& default_value) const; 336 | 337 | // Get an integer (long) value from INI file, returning default_value if 338 | // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). 339 | long GetInteger(const std::string& section, const std::string& name, long default_value) const; 340 | 341 | // Get a real (floating point double) value from INI file, returning 342 | // default_value if not found or not a valid floating point value 343 | // according to strtod(). 344 | double GetReal(const std::string& section, const std::string& name, double default_value) const; 345 | 346 | // Get a single precision floating point number value from INI file, returning 347 | // default_value if not found or not a valid floating point value 348 | // according to strtof(). 349 | float GetFloat(const std::string& section, const std::string& name, float default_value) const; 350 | 351 | // Get a boolean value from INI file, returning default_value if not found or if 352 | // not a valid true/false value. Valid true values are "true", "yes", "on", "1", 353 | // and valid false values are "false", "no", "off", "0" (not case sensitive). 354 | bool GetBoolean(const std::string& section, const std::string& name, bool default_value) const; 355 | 356 | protected: 357 | int _error; 358 | std::map _values; 359 | std::set _sections; 360 | static std::string MakeKey(const std::string& section, const std::string& name); 361 | static int ValueHandler(void* user, const char* section, const char* name, 362 | const char* value); 363 | }; 364 | 365 | #endif // __INIREADER_H__ 366 | 367 | 368 | #ifndef __INIREADER__ 369 | #define __INIREADER__ 370 | 371 | #include 372 | #include 373 | #include 374 | 375 | inline INIReader::INIReader(const std::string& filename) 376 | { 377 | _error = ini_parse(filename.c_str(), ValueHandler, this); 378 | } 379 | 380 | inline INIReader::INIReader(FILE *file) 381 | { 382 | _error = ini_parse_file(file, ValueHandler, this); 383 | } 384 | 385 | inline int INIReader::ParseError() const 386 | { 387 | return _error; 388 | } 389 | 390 | inline const std::set& INIReader::Sections() const 391 | { 392 | return _sections; 393 | } 394 | 395 | inline std::string INIReader::Get(const std::string& section, const std::string& name, const std::string& default_value) const 396 | { 397 | std::string key = MakeKey(section, name); 398 | return _values.count(key) ? _values.at(key) : default_value; 399 | } 400 | 401 | inline long INIReader::GetInteger(const std::string& section, const std::string& name, long default_value) const 402 | { 403 | std::string valstr = Get(section, name, ""); 404 | const char* value = valstr.c_str(); 405 | char* end; 406 | // This parses "1234" (decimal) and also "0x4D2" (hex) 407 | long n = strtol(value, &end, 0); 408 | return end > value ? n : default_value; 409 | } 410 | 411 | inline double INIReader::GetReal(const std::string& section, const std::string& name, double default_value) const 412 | { 413 | std::string valstr = Get(section, name, ""); 414 | const char* value = valstr.c_str(); 415 | char* end; 416 | double n = strtod(value, &end); 417 | return end > value ? n : default_value; 418 | } 419 | 420 | inline float INIReader::GetFloat(const std::string& section, const std::string& name, float default_value) const 421 | { 422 | std::string valstr = Get(section, name, ""); 423 | const char* value = valstr.c_str(); 424 | char* end; 425 | float n = strtof(value, &end); 426 | return end > value ? n : default_value; 427 | } 428 | 429 | inline bool INIReader::GetBoolean(const std::string& section, const std::string& name, bool default_value) const 430 | { 431 | std::string valstr = Get(section, name, ""); 432 | // Convert to lower case to make string comparisons case-insensitive 433 | std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); 434 | if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") 435 | return true; 436 | else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") 437 | return false; 438 | else 439 | return default_value; 440 | } 441 | 442 | inline std::string INIReader::MakeKey(const std::string& section, const std::string& name) 443 | { 444 | std::string key = section + "=" + name; 445 | // Convert to lower case to make section/name lookups case-insensitive 446 | std::transform(key.begin(), key.end(), key.begin(), ::tolower); 447 | return key; 448 | } 449 | 450 | inline int INIReader::ValueHandler(void* user, const char* section, const char* name, 451 | const char* value) 452 | { 453 | INIReader* reader = (INIReader*)user; 454 | std::string key = MakeKey(section, name); 455 | if (reader->_values[key].size() > 0) 456 | reader->_values[key] += "\n"; 457 | reader->_values[key] += value; 458 | reader->_sections.insert(section); 459 | return 1; 460 | } 461 | 462 | #endif // __INIREADER__ 463 | --------------------------------------------------------------------------------