├── resources ├── ct.png ├── gh.ico ├── code.png ├── hpp.png ├── rcnet.png └── cppheader.png ├── configs ├── config.json ├── diskSample.json └── oldCsgo.json ├── src ├── dumper │ ├── main.cpp │ ├── resource.h │ ├── GH-Offset-Dumper.rc │ └── GH-Offset-Dumper.vcxproj └── dumper-lib │ ├── include │ ├── GHFileHelp.h │ ├── GHFileHelp.cpp │ └── GHDumper.h │ ├── resource.h │ ├── FileScanner.h │ ├── FileScanner.cpp │ ├── GH-Offset-Dumper-Lib.vcxproj │ ├── zip.h │ ├── GHDumper.cpp │ └── base64.hpp ├── LICENSE ├── GH-Offset-Dumper.sln ├── .gitignore └── README.md /resources/ct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/ct.png -------------------------------------------------------------------------------- /resources/gh.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/gh.ico -------------------------------------------------------------------------------- /resources/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/code.png -------------------------------------------------------------------------------- /resources/hpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/hpp.png -------------------------------------------------------------------------------- /resources/rcnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/rcnet.png -------------------------------------------------------------------------------- /resources/cppheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guidedhacking/GH-Offset-Dumper/HEAD/resources/cppheader.png -------------------------------------------------------------------------------- /configs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileonly": true, 3 | "relativeByDefault": true, 4 | "exefile": "C:/Windows/System32/notepad.exe", 5 | "executable": "notepad.exe", 6 | "filename": "notepad", 7 | "signatures": [ 8 | { 9 | "name": "WinMain", 10 | "pattern": "E8 ? ? ? ? 8B D8 E8 ? ? ? ? 84 C0", 11 | "rva": true, 12 | "opLoc": 1, 13 | "opLength": 5 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /src/dumper/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | // This project serves as an exampe to use the offset dumping library 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, const char** argv) 8 | { 9 | if (!gh::ParseCommandLine(argc, argv)) 10 | { 11 | printf("[-] Failed to dump offsets.\n"); 12 | return 1; 13 | } 14 | 15 | printf("[+] Successfully dumped offsets!\n"); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/dumper-lib/include/GHFileHelp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "GHDumper.h" 5 | #include "../json.hpp" 6 | #include "../zip.h" 7 | #include "../FileScanner.h" 8 | 9 | void saveFile(nlohmann::json& config, const std::string& text, const std::string& extension); 10 | void saveReclassFile(nlohmann::json& config, const std::string& xml); 11 | nlohmann::json parseConfig(std::string& path, bool* success); 12 | -------------------------------------------------------------------------------- /src/dumper-lib/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by GH-Offset-Dumper.rc 4 | // 5 | #define IDI_ICON1 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /src/dumper/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by GH-Offset-Dumper.rc 4 | // 5 | #define IDI_ICON1 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GuidedHacking.com Source Available License 2 | Version 1, 05-14-2025 3 | 4 | Disclaimer: 5 | This project contains code developed and published by Guided Hacking LLC. 6 | GuidedHacking® sells educational content including source codes like this. 7 | 8 | GuidedHacking® - The Game Hacking Bible® - © 2025 Guided Hacking LLC. All Rights Reserved. 9 | 10 | Licensed Materials: 11 | Source code, compiled binaries, documentation, image and video assets, including original, modified or derivative versions. 12 | 13 | Limited Use License: 14 | 1. You may use these materials only in non-commercial private, personal projects. 15 | 2. Distribution of these materials in any form, including compiled, modified, or derivative works is not permitted. 16 | 17 | This software is provided AS IS without any warranties, express or implied, and Guided Hacking LLC is not liable for any damages arising from the use of these materials. 18 | 19 | Any rights not expressly granted by the license are reserved by Guided Hacking LLC. -------------------------------------------------------------------------------- /configs/diskSample.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileonly": true, // specify file only mode 3 | "relativeByDefault": true, // treats all signatures that don't specify if they're relative or not as relative 4 | "exefile": "C:/Path/To/Game/dump.exe", // supply path to dumped game 5 | "executable": "GameName.exe", 6 | "filename": "GameName", 7 | "additionalModules": [ 8 | // you'll need to load every module you want to scan 9 | { 10 | "name": "AnotherModule", 11 | "path": "C:/Path/To/Module/something.dll" // this can be another exe or dll 12 | } 13 | ], 14 | "signatures": [ 15 | { 16 | "name": "TestSig123", 17 | "pattern": "E9 ? ? ? ? 48 8B 8A ? ? ? ? 48 83 C1 28 E9 ? ? ? ? 40 55", 18 | "rva": true, // specify this is a relative branch signature 19 | "opLoc": 1, // this is an optional value, its defaulted to 1 20 | "opLength": 5, // this is an optional value, its defaulted to 5 21 | "module": "AnotherModule" // if this is not specified it will default to GameName.exe 22 | }, 23 | { 24 | "name": "MysteriousFunction", 25 | "pattern": "E8 ? ? ? ? 48 8B F8 48 89 44 24 ? 48 85 DB" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/dumper-lib/include/GHFileHelp.cpp: -------------------------------------------------------------------------------- 1 | #include "GHFileHelp.h" 2 | 3 | void saveFile(nlohmann::json& config, const std::string& text, const std::string& extension) 4 | { 5 | // get filename from JSON 6 | std::string filename = config["filename"]; 7 | 8 | // format full filename 9 | std::stringstream ss; 10 | std::string outpath = filename + "/"; 11 | ss << outpath << filename << "." << extension; 12 | 13 | // write text file 14 | std::ofstream file(ss.str()); 15 | file << text; 16 | } 17 | 18 | void saveReclassFile(nlohmann::json& config, const std::string& xml) 19 | { 20 | std::string fname = config["filename"]; 21 | std::string reclassFilename = 22 | fname + "/" + fname; 23 | reclassFilename += ".rcnet"; 24 | struct zip_t* zip = zip_open(reclassFilename.c_str(), ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); 25 | 26 | zip_entry_open(zip, "Data.xml"); 27 | zip_entry_write(zip, xml.c_str(), xml.size()); 28 | zip_entry_close(zip); 29 | 30 | zip_close(zip); 31 | } 32 | 33 | nlohmann::json parseConfig(std::string& path, bool* success) 34 | { 35 | if (success == nullptr) 36 | { 37 | return {}; 38 | } 39 | 40 | *success = true; 41 | 42 | std::ifstream ifs(path); 43 | std::ostringstream oss; 44 | oss << ifs.rdbuf(); 45 | std::string entireFile = oss.str(); 46 | 47 | if (!nlohmann::json::accept(entireFile)) 48 | { 49 | *success = false; 50 | return {}; 51 | } 52 | 53 | return nlohmann::json::parse(entireFile); 54 | } 55 | -------------------------------------------------------------------------------- /src/dumper-lib/FileScanner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GHDumper.h" 3 | 4 | // helper class to manage dynamicly loaded modules easier 5 | using MappedType = std::byte; 6 | using MappedSize = std::size_t; 7 | class MappedFile 8 | { 9 | public: 10 | MappedType* getBytes(); 11 | MappedSize getSize(); 12 | 13 | explicit MappedFile() = default; 14 | explicit MappedFile(const std::string& diskPath); 15 | 16 | std::string getExt(); 17 | void Release(); 18 | 19 | private: 20 | MappedType* mappedBytes {}; 21 | MappedSize mappedSize {}; 22 | std::string ext {}; 23 | }; 24 | 25 | // dynamic module structure 26 | struct DynamicModule 27 | { 28 | // file path 29 | std::string filePath {}; 30 | // name used when accessing the module 31 | std::string compName {}; 32 | }; 33 | 34 | using DynamicMoudleArray = std::vector; 35 | 36 | // load file from disk and dump signatures from it 37 | class FileScanner 38 | { 39 | public: 40 | // main process will be passed as the file path 41 | // additional modules can also be loaded and accessed here (ex: client.dll) 42 | explicit FileScanner() = default; 43 | explicit FileScanner(const std::string& filePath, const DynamicMoudleArray& dynamicModules = {}); 44 | void decon(); 45 | 46 | MappedFile getMainFile(); 47 | MappedFile getFileByName(const std::string& name); 48 | std::string getMainFileName(); 49 | static std::vector ReadBytes(const std::string& fp); 50 | bool Valid(); 51 | private: 52 | // each file is mapped into our process by name 53 | std::unordered_map mappedFiles {}; 54 | std::string mainFileName {}; 55 | bool valid {}; 56 | 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /src/dumper/GH-Offset-Dumper.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_ICON1 ICON "..\\..\\resources\\gh.ico" 56 | 57 | #endif // English (United States) resources 58 | ///////////////////////////////////////////////////////////////////////////// 59 | 60 | 61 | 62 | #ifndef APSTUDIO_INVOKED 63 | ///////////////////////////////////////////////////////////////////////////// 64 | // 65 | // Generated from the TEXTINCLUDE 3 resource. 66 | // 67 | 68 | 69 | ///////////////////////////////////////////////////////////////////////////// 70 | #endif // not APSTUDIO_INVOKED 71 | 72 | -------------------------------------------------------------------------------- /GH-Offset-Dumper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.35931.194 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GH-Offset-Dumper-Lib", "src\dumper-lib\GH-Offset-Dumper-Lib.vcxproj", "{1722F02C-911E-44E4-8613-37AB98D08C22}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GH-Offset-Dumper", "src\dumper\GH-Offset-Dumper.vcxproj", "{D549C579-2AC2-4310-BD6E-6FA2C447709D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Debug|x64.ActiveCfg = Debug|x64 19 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Debug|x64.Build.0 = Debug|x64 20 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Debug|x86.ActiveCfg = Debug|Win32 21 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Debug|x86.Build.0 = Debug|Win32 22 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Release|x64.ActiveCfg = Release|x64 23 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Release|x64.Build.0 = Release|x64 24 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Release|x86.ActiveCfg = Release|Win32 25 | {1722F02C-911E-44E4-8613-37AB98D08C22}.Release|x86.Build.0 = Release|Win32 26 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Debug|x64.ActiveCfg = Debug|x64 27 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Debug|x64.Build.0 = Debug|x64 28 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Debug|x86.ActiveCfg = Debug|Win32 29 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Debug|x86.Build.0 = Debug|Win32 30 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Release|x64.ActiveCfg = Release|x64 31 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Release|x64.Build.0 = Release|x64 32 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Release|x86.ActiveCfg = Release|Win32 33 | {D549C579-2AC2-4310-BD6E-6FA2C447709D}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {113DE095-A7DD-4C4E-A0C5-0AEB79D6BB8D} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /src/dumper-lib/FileScanner.cpp: -------------------------------------------------------------------------------- 1 | #include "FileScanner.h" 2 | 3 | 4 | std::vector FileScanner::ReadBytes(const std::string& fp) 5 | { 6 | std::ifstream file_stream(fp, std::ios_base::binary); 7 | 8 | if (!file_stream.is_open() || !file_stream.good()) 9 | { 10 | return std::vector(); 11 | } 12 | 13 | std::vector buffer((std::istreambuf_iterator(file_stream)), 14 | std::istreambuf_iterator()); 15 | 16 | std::vector result(buffer.size()); 17 | std::transform(buffer.begin(), buffer.end(), result.begin(), 18 | [] (char c) { return static_cast(c); }); 19 | return result; 20 | } 21 | 22 | FileScanner::FileScanner(const std::string& filePath, const DynamicMoudleArray& dynamicModules) 23 | { 24 | this->mainFileName = std::filesystem::path(filePath).filename().string(); 25 | this->mappedFiles[mainFileName] = MappedFile(filePath); 26 | for (auto& module : dynamicModules) 27 | { 28 | this->mappedFiles[module.compName] = MappedFile(module.filePath); 29 | } 30 | if (this->mappedFiles[mainFileName].getBytes()) 31 | { 32 | this->valid = true; 33 | } 34 | } 35 | 36 | void FileScanner::decon() 37 | { 38 | for (auto& it = this->mappedFiles.begin(); it != this->mappedFiles.end(); it++) 39 | { 40 | it->second.Release(); 41 | } 42 | } 43 | 44 | MappedFile FileScanner::getMainFile() 45 | { 46 | return this->mappedFiles[mainFileName]; 47 | } 48 | 49 | MappedFile FileScanner::getFileByName(const std::string& name) 50 | { 51 | return this->mappedFiles[name]; 52 | } 53 | 54 | std::string FileScanner::getMainFileName() 55 | { 56 | return this->mainFileName; 57 | } 58 | 59 | bool FileScanner::Valid() 60 | { 61 | return this->valid; 62 | } 63 | 64 | MappedType* MappedFile::getBytes() 65 | { 66 | return this->mappedBytes; 67 | } 68 | 69 | MappedSize MappedFile::getSize() 70 | { 71 | return this->mappedSize; 72 | } 73 | 74 | MappedFile::MappedFile(const std::string& diskPath) 75 | { 76 | this->ext = std::filesystem::path(diskPath).extension().string(); 77 | 78 | const auto map = FileScanner::ReadBytes(diskPath); 79 | if (map.size() == 0) 80 | { 81 | return; 82 | } 83 | 84 | IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)map.data(); 85 | IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)((char*)dos + dos->e_lfanew); 86 | 87 | SIZE_T sizeOfImage = nt->OptionalHeader.SizeOfImage; 88 | this->mappedBytes = new MappedType[sizeOfImage]; 89 | memset(this->mappedBytes, 0, sizeOfImage); 90 | 91 | SIZE_T sizeOfHeaders = nt->OptionalHeader.SizeOfHeaders; 92 | memcpy(this->mappedBytes, map.data(), sizeOfHeaders); 93 | 94 | IMAGE_SECTION_HEADER* section = IMAGE_FIRST_SECTION(nt); 95 | for (int i = 0; i < nt->FileHeader.NumberOfSections; i++, section++) 96 | { 97 | memcpy(this->mappedBytes + section->VirtualAddress, map.data() + section->PointerToRawData, section->SizeOfRawData); 98 | } 99 | 100 | this->mappedSize = sizeOfImage; 101 | 102 | printf("[+] Loaded %s at 0x%p (0x%x)\n", std::filesystem::path(diskPath).filename().string().c_str(), this->mappedBytes, this->mappedSize); 103 | } 104 | 105 | 106 | std::string MappedFile::getExt() 107 | { 108 | return this->ext; 109 | } 110 | 111 | void MappedFile::Release() 112 | { 113 | if (this->mappedBytes) 114 | { 115 | delete[] this->mappedBytes; 116 | } 117 | } 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/dumper-lib/include/GHDumper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "../json.hpp" 16 | #include "../FileScanner.h" 17 | 18 | /* Notes 19 | - gh::DumpNetvars() crashes if the dumper's architecture (32-bit or 64-bit) is different than the target process's architecture. 20 | - gh::DumpNetvars() only works for games using the source engine. 21 | - gh::DumpSignatures() and gh::DumpNetvars() return a Dump which is a std::unordered_map. If an error occurs, an empty map is returned. 22 | - gh::FormatReclass() returns the Data.xml text contents. A reclass file is a .rcnet zip containing Data.xml. 23 | */ 24 | 25 | /* Example 26 | #include 27 | #include "json.hpp" 28 | #include "GHDumper.h" 29 | 30 | int main() 31 | { 32 | // load json 33 | std::ifstream file("config.json"); 34 | auto config = nlohmann::json::parse(file); 35 | 36 | // dump as std::unordered_map 37 | auto signatures = gh::DumpSignatures(config); 38 | auto netvars = gh::DumpNetvars(config, signatures); 39 | 40 | // format files as std::string 41 | auto hpp = gh::FormatHeader(config, signatures, netvars); 42 | auto ct = gh::FormatCheatEngine(config, signatures, netvars); 43 | auto xml = gh::FormatReclass(config, netvars); 44 | 45 | // save files or do whatever 46 | // ... 47 | } 48 | 49 | */ 50 | class FileScanner; 51 | struct DynamicModule; 52 | struct RecvProp; 53 | struct RecvTable 54 | { 55 | RecvProp* m_pProps; 56 | int m_nProps; 57 | void* m_pDecoder; 58 | char* m_pNetTableName; 59 | bool m_bInitialized; 60 | bool m_bInMainList; 61 | }; 62 | 63 | struct RecvProp 64 | { 65 | char* m_pVarName; 66 | void* m_RecvType; 67 | int m_Flags; 68 | int m_StringBufferSize; 69 | int m_bInsideArray; 70 | const void* m_pExtraData; 71 | RecvProp* m_pArrayProp; 72 | void* m_ArrayLengthProxy; 73 | void* m_ProxyFn; 74 | void* m_DataTableProxyFn; 75 | RecvTable* m_pDataTable; 76 | int m_Offset; 77 | int m_ElementStride; 78 | int m_nElements; 79 | const char* m_pParentArrayPropName; 80 | }; 81 | 82 | struct ClientClass 83 | { 84 | void* m_pCreateFn; 85 | void* m_pCreateEventFn; 86 | char* m_pNetworkName; 87 | RecvTable* m_pRecvTable; 88 | ClientClass* m_pNext; 89 | int m_ClassID; 90 | }; 91 | typedef std::unordered_map Dump; 92 | 93 | namespace gh 94 | { 95 | namespace internal 96 | { 97 | BOOL GetProcessByName(const wchar_t* processName, PROCESSENTRY32W* out); 98 | BOOL GetModuleByName(DWORD pid, const wchar_t* moduleName, MODULEENTRY32W* out); 99 | 100 | void SplitComboPattern(const char* combo, std::string& pattern, std::string& mask); 101 | 102 | // https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/ 103 | char* ScanBasic(const char* pattern, const char* mask, char* begin, intptr_t size); 104 | 105 | 106 | // https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/ 107 | char* ScanEx(const char* pattern, const char* mask, char* begin, intptr_t size, HANDLE hProc); 108 | 109 | intptr_t FindNetvarInRecvTable(RecvTable* table, const char* netvarName); 110 | 111 | intptr_t FindNetvar(const char* tableName, const char* netvarName, ClientClass* firstClientClass); 112 | 113 | std::string FormatNowUTC(); 114 | 115 | nlohmann::json FindSignatureJSON(nlohmann::json& config, std::string signatureName); 116 | nlohmann::json FindNetvarJSON(nlohmann::json& config, std::string netvarName); 117 | 118 | } // namespace internal 119 | 120 | 121 | Dump DumpSignatures(nlohmann::json& config, FileScanner& scanner); 122 | 123 | Dump DumpNetvars(nlohmann::json& config, const Dump& signatures); 124 | 125 | std::string FormatHeader(nlohmann::json& config, const Dump& signatures, FileScanner& scanner, const Dump& netvars = {}); 126 | std::string FormatReclass(nlohmann::json& config, FileScanner& scanner, const Dump& netvars = {}); 127 | std::string FormatCheatEngine(nlohmann::json& config, const Dump& signatures, FileScanner& scanner, const Dump& netvars = {}); 128 | 129 | FileScanner InitScanner(nlohmann::json& config, bool* runtime); 130 | bool ParseCommandLine(int argc, const char** argv); 131 | } // namespace ghdumper 132 | -------------------------------------------------------------------------------- /.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 | *.user 8 | *.userosscache 9 | *.sln.docstates 10 | 11 | # User-specific files (MonoDevelop/Xamarin Studio) 12 | *.userprefs 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # Visual Studio 2017 auto generated files 30 | Generated\ Files/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # Benchmark Results 46 | BenchmarkDotNet.Artifacts/ 47 | 48 | # .NET Core 49 | project.lock.json 50 | project.fragment.lock.json 51 | artifacts/ 52 | **/Properties/launchSettings.json 53 | 54 | # StyleCop 55 | StyleCopReport.xml 56 | 57 | # Files built by Visual Studio 58 | *_i.c 59 | *_p.c 60 | *_i.h 61 | *.ilk 62 | *.meta 63 | *.obj 64 | *.iobj 65 | *.pch 66 | *.pdb 67 | *.ipdb 68 | *.pgc 69 | *.pgd 70 | *.rsp 71 | *.sbr 72 | *.tlb 73 | *.tli 74 | *.tlh 75 | *.tmp 76 | *.tmp_proj 77 | *.log 78 | *.vspscc 79 | *.vssscc 80 | .builds 81 | *.pidb 82 | *.svclog 83 | *.scc 84 | 85 | # Chutzpah Test files 86 | _Chutzpah* 87 | 88 | # Visual C++ cache files 89 | ipch/ 90 | *.aps 91 | *.ncb 92 | *.opendb 93 | *.opensdf 94 | *.sdf 95 | *.cachefile 96 | *.VC.db 97 | *.VC.VC.opendb 98 | 99 | # Visual Studio profiler 100 | *.psess 101 | *.vsp 102 | *.vspx 103 | *.sap 104 | 105 | # Visual Studio Trace Files 106 | *.e2e 107 | 108 | # TFS 2012 Local Workspace 109 | $tf/ 110 | 111 | # Guidance Automation Toolkit 112 | *.gpState 113 | 114 | # ReSharper is a .NET coding add-in 115 | _ReSharper*/ 116 | *.[Rr]e[Ss]harper 117 | *.DotSettings.user 118 | 119 | # JustCode is a .NET coding add-in 120 | .JustCode 121 | 122 | # TeamCity is a build add-in 123 | _TeamCity* 124 | 125 | # DotCover is a Code Coverage Tool 126 | *.dotCover 127 | 128 | # AxoCover is a Code Coverage Tool 129 | .axoCover/* 130 | !.axoCover/settings.json 131 | 132 | # Visual Studio code coverage results 133 | *.coverage 134 | *.coveragexml 135 | 136 | # NCrunch 137 | _NCrunch_* 138 | .*crunch*.local.xml 139 | nCrunchTemp_* 140 | 141 | # MightyMoose 142 | *.mm.* 143 | AutoTest.Net/ 144 | 145 | # Web workbench (sass) 146 | .sass-cache/ 147 | 148 | # Installshield output folder 149 | [Ee]xpress/ 150 | 151 | # DocProject is a documentation generator add-in 152 | DocProject/buildhelp/ 153 | DocProject/Help/*.HxT 154 | DocProject/Help/*.HxC 155 | DocProject/Help/*.hhc 156 | DocProject/Help/*.hhk 157 | DocProject/Help/*.hhp 158 | DocProject/Help/Html2 159 | DocProject/Help/html 160 | 161 | # Click-Once directory 162 | publish/ 163 | 164 | # Publish Web Output 165 | *.[Pp]ublish.xml 166 | *.azurePubxml 167 | # Note: Comment the next line if you want to checkin your web deploy settings, 168 | # but database connection strings (with potential passwords) will be unencrypted 169 | *.pubxml 170 | *.publishproj 171 | 172 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 173 | # checkin your Azure Web App publish settings, but sensitive information contained 174 | # in these scripts will be unencrypted 175 | PublishScripts/ 176 | 177 | # NuGet Packages 178 | *.nupkg 179 | # The packages folder can be ignored because of Package Restore 180 | **/[Pp]ackages/* 181 | # except build/, which is used as an MSBuild target. 182 | !**/[Pp]ackages/build/ 183 | # Uncomment if necessary however generally it will be regenerated when needed 184 | #!**/[Pp]ackages/repositories.config 185 | # NuGet v3's project.json files produces more ignorable files 186 | *.nuget.props 187 | *.nuget.targets 188 | 189 | # Microsoft Azure Build Output 190 | csx/ 191 | *.build.csdef 192 | 193 | # Microsoft Azure Emulator 194 | ecf/ 195 | rcf/ 196 | 197 | # Windows Store app package directories and files 198 | AppPackages/ 199 | BundleArtifacts/ 200 | Package.StoreAssociation.xml 201 | _pkginfo.txt 202 | *.appx 203 | 204 | # Visual Studio cache files 205 | # files ending in .cache can be ignored 206 | *.[Cc]ache 207 | # but keep track of directories ending in .cache 208 | !*.[Cc]ache/ 209 | 210 | # Others 211 | ClientBin/ 212 | ~$* 213 | *~ 214 | *.dbmdl 215 | *.dbproj.schemaview 216 | *.jfm 217 | *.pfx 218 | *.publishsettings 219 | orleans.codegen.cs 220 | 221 | # Including strong name files can present a security risk 222 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 223 | #*.snk 224 | 225 | # Since there are multiple workflows, uncomment next line to ignore bower_components 226 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 227 | #bower_components/ 228 | 229 | # RIA/Silverlight projects 230 | Generated_Code/ 231 | 232 | # Backup & report files from converting an old project file 233 | # to a newer Visual Studio version. Backup files are not needed, 234 | # because we have git ;-) 235 | _UpgradeReport_Files/ 236 | Backup*/ 237 | UpgradeLog*.XML 238 | UpgradeLog*.htm 239 | ServiceFabricBackup/ 240 | *.rptproj.bak 241 | 242 | # SQL Server files 243 | *.mdf 244 | *.ldf 245 | *.ndf 246 | 247 | # Business Intelligence projects 248 | *.rdl.data 249 | *.bim.layout 250 | *.bim_*.settings 251 | *.rptproj.rsuser 252 | 253 | # Microsoft Fakes 254 | FakesAssemblies/ 255 | 256 | # GhostDoc plugin setting file 257 | *.GhostDoc.xml 258 | 259 | # Node.js Tools for Visual Studio 260 | .ntvs_analysis.dat 261 | node_modules/ 262 | 263 | # Visual Studio 6 build log 264 | *.plg 265 | 266 | # Visual Studio 6 workspace options file 267 | *.opt 268 | 269 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 270 | *.vbw 271 | 272 | # Visual Studio LightSwitch build output 273 | **/*.HTMLClient/GeneratedArtifacts 274 | **/*.DesktopClient/GeneratedArtifacts 275 | **/*.DesktopClient/ModelManifest.xml 276 | **/*.Server/GeneratedArtifacts 277 | **/*.Server/ModelManifest.xml 278 | _Pvt_Extensions 279 | 280 | # Paket dependency manager 281 | .paket/paket.exe 282 | paket-files/ 283 | 284 | # FAKE - F# Make 285 | .fake/ 286 | 287 | # JetBrains Rider 288 | .idea/ 289 | *.sln.iml 290 | 291 | # CodeRush 292 | .cr/ 293 | 294 | # Python Tools for Visual Studio (PTVS) 295 | __pycache__/ 296 | *.pyc 297 | 298 | # Cake - Uncomment if you are using it 299 | # tools/** 300 | # !tools/packages.config 301 | 302 | # Tabs Studio 303 | *.tss 304 | 305 | # Telerik's JustMock configuration file 306 | *.jmconfig 307 | 308 | # BizTalk build output 309 | *.btp.cs 310 | *.btm.cs 311 | *.odx.cs 312 | *.xsd.cs 313 | 314 | # OpenCover UI analysis results 315 | OpenCover/ 316 | 317 | # Azure Stream Analytics local run output 318 | ASALocalRun/ 319 | 320 | # MSBuild Binary and Structured Log 321 | *.binlog 322 | 323 | # NVidia Nsight GPU debugger configuration file 324 | *.nvuser 325 | 326 | # MFractors (Xamarin productivity tool) working folder 327 | .mfractor/ 328 | *.CT 329 | /csgo - notes.h 330 | /.vs/GH-Offset-Dumper/v16/Browse.VC.db-shm 331 | /.vs/GH-Offset-Dumper/v16/Browse.VC.db-wal 332 | /.vs 333 | /output 334 | /build 335 | -------------------------------------------------------------------------------- /src/dumper/GH-Offset-Dumper.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 | 16.0 23 | Win32Proj 24 | {d549c579-2ac2-4310-bd6e-6fa2c447709d} 25 | dumper 26 | 10.0 27 | GH-Offset-Dumper 28 | 29 | 30 | 31 | Application 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | $(SolutionDir)src\dumper-lib\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 77 | $(SolutionDir)bin\ 78 | $(SolutionDir)build\ 79 | $(ProjectName)-x$(PlatformArchitecture) 80 | 81 | 82 | false 83 | $(SolutionDir)src\dumper-lib\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 84 | $(SolutionDir)bin\ 85 | $(SolutionDir)build\ 86 | $(ProjectName)-x$(PlatformArchitecture) 87 | 88 | 89 | true 90 | $(SolutionDir)src\dumper-lib\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 91 | $(SolutionDir)bin\ 92 | $(SolutionDir)build\ 93 | $(ProjectName)-x$(PlatformArchitecture) 94 | 95 | 96 | false 97 | $(SolutionDir)src\dumper-lib\include;$(IncludePath) 98 | $(SolutionDir)bin\ 99 | $(SolutionDir)build\ 100 | $(ProjectName)-x$(PlatformArchitecture) 101 | 102 | 103 | 104 | Level3 105 | true 106 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | stdcpp17 109 | 110 | 111 | Console 112 | true 113 | HighestAvailable 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | stdcpp17 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | HighestAvailable 132 | 133 | 134 | 135 | 136 | Level3 137 | true 138 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 139 | true 140 | stdcpp17 141 | 142 | 143 | Console 144 | true 145 | HighestAvailable 146 | 147 | 148 | 149 | 150 | Level3 151 | true 152 | true 153 | true 154 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 155 | true 156 | stdcpp17 157 | 158 | 159 | Console 160 | true 161 | true 162 | true 163 | HighestAvailable 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | {1722f02c-911e-44e4-8613-37ab98d08c22} 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Guided Hacking Offset Dumper** 2 | 3 | A modernized signature scanner that works with any game. This tool can very quickly generate full offset headers for any game on disk or during runtime, without changing any of the code. You can have separate JSON files for each game and project, which are to be dragged and dropped on the dumper. 4 | 5 | ![image](resources/code.png) 6 | 7 | ## What Can It Do? 8 | 14 | 15 | ## **How to Use It** 16 | 17 | 1. Run the game. 18 | 2. If the game uses the source engine, you should run `GH-Offset-Dumper-64.exe` if the game is 64 bits, or `GH-Offset-Dumper-32.exe` if the game is 32 bits; otherwise, netvars will not be dumped. If the game does not use the source engine, you can use either one. 19 | 3. Drag and drop your `config.json` on the exe. 20 | 4. Include the generated `.hpp` file in your project. 21 | 22 | ## **How to Dump From Disk** 23 | 24 | 1. Update your `config.json` with our example, which can be found below or in the `diskSample.json` file, make sure `fileonly` is set to true. 25 | 2. Update the `exeFile` field with the path to your exe on disk. 26 | 3. If you require any modules, make sure you add them and put their path in the `additionalModules` array. 27 | 4. Add any signatures you need. 28 | 5. Drag and drop your config file on the dumper. 29 | 30 | ## **How to Use The GH Offset Dumper library** 31 | 32 | Using the GH Offset Dumping Library is very easy. If you're working externally, the offset dumper is 1 line of code to get set up. When you use the `ParseCommandLine` function from the library, it will automatically support dragging and dropping JSON files onto your output exe. This function can be easily modified if you need more control. You need to link your project to the static library, and add the include directory to your project. 33 | 34 | ```cpp 35 | #include 36 | #include 37 | #include 38 | 39 | int main(int argc, const char** argv) 40 | { 41 | if (!gh::ParseCommandLine(argc, argv)) 42 | { 43 | printf("[-] Failed to dump offsets.\n"); 44 | return 1; 45 | } 46 | 47 | printf("[+] Successfully dumped offsets!\n"); 48 | return 0; 49 | } 50 | ``` 51 | 52 | ## **How to Dump From Game Dumps** 53 | 54 | Dumping from a game exe on disk is simple. You need to adjust your `config.json` file and specify the path to your dump. You can also add more than one module to this, so if you want to scan through many files on disk at once, you can. 55 | 56 | ```jsonc 57 | { 58 | "fileonly": true, // specify file only mode 59 | "relativeByDefault": true, // treats all signatures that don't specify if they're relative or not as relative 60 | "exefile": "C:/Path/To/Game/dump.exe", // supply path to dumped game 61 | "executable": "GameName.exe", 62 | "filename": "GameName", 63 | "additionalModules": [ 64 | { 65 | "name": "AnotherModule", 66 | "path": "C:/Path/To/Module/something.dll" 67 | } 68 | ], 69 | "signatures": [ 70 | { 71 | "name": "TestSig123", 72 | "pattern": "E9 ? ? ? ? 48 8B 8A ? ? ? ? 48 83 C1 28 E9 ? ? ? ? 40 55", 73 | "rva": true, 74 | "opLoc": 1, 75 | "opLength": 5, 76 | "module": "AnotherModule" 77 | }, 78 | { 79 | "name": "MysteriousFunction", 80 | "pattern": "E8 ? ? ? ? 48 8B F8 48 89 44 24 ? 48 85 DB" 81 | } 82 | ] 83 | } 84 | ``` 85 | 86 | ## **Dumping From Disk Features** 87 | 88 | * Supports dumping from a main exe and multiple modules (DLLs) at once. 89 | * Supports relative branch signatures 90 | * Does not support netvars when dumping from disk 91 | 92 | 93 | ## Notepad Disk Example 94 | This will dump the WinMain from Notepad on disk. 95 | ```json 96 | { 97 | "fileonly": true, 98 | "relativeByDefault": true, 99 | "exefile": "C:/Windows/System32/notepad.exe", 100 | "executable": "notepad.exe", 101 | "filename": "notepad", 102 | "signatures": [ 103 | { 104 | "name": "WinMain", 105 | "pattern": "E8 ? ? ? ? 8B D8 E8 ? ? ? ? 84 C0", 106 | "rva": true, 107 | "opLoc": 1, 108 | "opLength": 5 109 | } 110 | ] 111 | } 112 | ``` 113 | 114 | ```bash 115 | [+] Loaded notepad.exe at 0x000001DD07D264B0 (0x38000) 116 | [~] Target: notepad.exe 117 | [!] Dumping From Disk 118 | [+] Found pattern WinMain at 000001DD07D49FF1 119 | [?] Processing Relative Branch 120 | [+] Resolved call location: 000001DD07D312EC 121 | [+] Successfully dumped offsets! 122 | ``` 123 | 124 | ## **Why is GH Offset Dumper Better Than All Others?** 125 | 126 | * Three dump file formats: `.hpp` (C/C++ header), `.ct` (Cheat Engine Table), `.rcnet` (ReClass.NET) 127 | * `.hpp` header file is easily included in your project, so you can use offsets. Also, it has comments showing modules and base objects of signatures and netvars, respectively. 128 | * `.ct` Cheat Engine Table shows the Local Player and Entity List. At the bottom, all signatures and netvars are organized in a nice format. 129 | * `.rcnet` ReClass.NET: All netvar tables are organized as classes. 130 | * Supports dumping signatures from disk. 131 | 132 | ## **Why** 133 | This tool externally scan a process for signatures and dump the relative offsets to a header file, which is easy to incorporate into your Visual Studio project, when an update is released for a game, you run the dumper to get the latest offsets. 134 | Scrubs don't know how to pattern scan, so they manually update their offsets in their game hacks after running an offset dumper like this. It's smarter to generate headers like this, rather than send someone your code with perfect auto-updating offsets built in. 135 | 136 | ## **Misc** 137 | 138 | You can drag and drop a config file on the exe to parse it. If you use the given `config.json`, the dumper will dump the WinMain address out of Notepad as an example. The old CSGO is in the `oldCsgo.json` file. 139 | Dumped offsets will be placed in a directory named whatever the config executable name is. 140 | 141 | 142 | ## **How is this different from HazeDumper?** 143 | This dumper was inspired by [hazedumper](https://github.com/frk1/hazedumper), so thank you to frk1, rN', and the other contributors to that project. 144 | 145 | I started learning Rust when messing with HazeDumper, and I decided we needed a C++ version. I also wanted to extend the functionality. 146 | 147 | **GH Dumper will do the same thing as HazeDumper** with the addition of dumping ReClass files and Cheat Engine Tables. 148 | Our dumper uses the same JSON config file format, so they are interchangeable. 149 | 150 | ## **Notes** 151 | 152 | * The main code is `GHDumper.h/GHDumper.cpp` (the dumper library). 153 | * `json.hpp` is a dependency of `GHDumper.h`. 154 | * `zip.h`, `zip.c`, and `miniz.h` are dependencies used to make a ZIP file when creating `.rcnet`. 155 | * If any value is missing from the output header file, it is possible that the signature is outdated, and thus the pattern scan returned 0. 156 | * In CS\:GO, joining a match may cause the dumper to fail. Restarting CS\:GO should solve it. 157 | * Netvars are not supported when dumping signatures from disk. 158 | * You can default all signatures to be relative (that don't specify otherwise) by using the setting `relativeByDefault` to `true`. 159 | * Provided is a sample to start dumping from disk with, and the old csgo style config for reference. 160 | 161 | ## **TODO** 162 | 163 | * Make an internal version 164 | * Add CSS functionality 165 | * Other ideas to make it kewl 166 | 167 | ## **Releases/Downloads** 168 | 169 | [https://guidedhacking.com/resources/guided-hacking-offset-dumper-gh-offset-dumper.51/](https://guidedhacking.com/resources/guided-hacking-offset-dumper-gh-offset-dumper.51/) 170 | 171 | ## **Credits** 172 | 173 | Thank you to 174 | - frk1, rN' and the contributors to [hazedumper](https://github.com/frk1/hazedumper) 175 | - nlohmann and the contributors of [json.hpp](https://github.com/nlohmann/json) 176 | - tobias and the contributors of the single header [base64](https://github.com/tobiaslocker/base64) library 177 | 178 |

Official GH Courses

179 | 191 | 192 | GuidedHacking® - The Game Hacking Bible® - © 2025 Guided Hacking LLC. All Rights Reserved. 193 | -------------------------------------------------------------------------------- /src/dumper-lib/GH-Offset-Dumper-Lib.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 | 36 | 37 | 38 | 16.0 39 | {1722F02C-911E-44E4-8613-37AB98D08C22} 40 | Win32Proj 41 | GHOffsetDumper 42 | 10.0 43 | GH-Offset-Dumper-Lib 44 | 45 | 46 | 47 | StaticLibrary 48 | true 49 | v142 50 | MultiByte 51 | 52 | 53 | StaticLibrary 54 | false 55 | v142 56 | true 57 | MultiByte 58 | 59 | 60 | StaticLibrary 61 | true 62 | v142 63 | MultiByte 64 | 65 | 66 | StaticLibrary 67 | false 68 | v142 69 | true 70 | MultiByte 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | true 92 | true 93 | $(DXSDK_DIR)Include;$(IncludePath) 94 | $(DXSDK_DIR)Lib\x64;$(DXSDK_DIR)Lib\x86;$(LibraryPath) 95 | $(SolutionDir)bin\lib\ 96 | $(ProjectName)-x$(PlatformArchitecture) 97 | $(SolutionDir)build\ 98 | 99 | 100 | true 101 | true 102 | $(DXSDK_DIR)Include;$(IncludePath) 103 | $(DXSDK_DIR)Lib\x64;$(DXSDK_DIR)Lib\x86;$(LibraryPath) 104 | $(SolutionDir)bin\lib\ 105 | $(ProjectName)-x$(PlatformArchitecture) 106 | $(SolutionDir)build\ 107 | 108 | 109 | false 110 | true 111 | $(DXSDK_DIR)Include;$(IncludePath) 112 | $(DXSDK_DIR)Lib\x64;$(DXSDK_DIR)Lib\x86;$(LibraryPath) 113 | $(ProjectName)-x$(PlatformArchitecture) 114 | $(SolutionDir)bin\lib\ 115 | $(SolutionDir)build\ 116 | 117 | 118 | false 119 | true 120 | $(DXSDK_DIR)Include;$(IncludePath) 121 | $(DXSDK_DIR)Lib\x64;$(DXSDK_DIR)Lib\x86;$(LibraryPath) 122 | $(SolutionDir)bin\lib\ 123 | $(ProjectName)-x$(PlatformArchitecture) 124 | $(SolutionDir)build\ 125 | 126 | 127 | 128 | Level3 129 | Disabled 130 | true 131 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | false 133 | stdcpp17 134 | 135 | 136 | Console 137 | true 138 | RequireAdministrator 139 | 140 | 141 | 142 | 143 | Level3 144 | Disabled 145 | true 146 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 147 | false 148 | stdcpp17 149 | 150 | 151 | Console 152 | true 153 | RequireAdministrator 154 | 155 | 156 | 157 | 158 | Level3 159 | MaxSpeed 160 | true 161 | true 162 | true 163 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 164 | false 165 | stdcpp17 166 | 167 | 168 | Console 169 | true 170 | true 171 | true 172 | RequireAdministrator 173 | 174 | 175 | 176 | 177 | Level3 178 | MaxSpeed 179 | true 180 | true 181 | true 182 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 183 | false 184 | stdcpp17 185 | 186 | 187 | Console 188 | true 189 | true 190 | true 191 | RequireAdministrator 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /src/dumper-lib/zip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 3 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 4 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 5 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 6 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 7 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 8 | * OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | #ifndef ZIP_H 13 | #define ZIP_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef ZIP_SHARED 21 | #define ZIP_EXPORT 22 | #else 23 | #ifdef _WIN32 24 | #ifdef ZIP_BUILD_SHARED 25 | #define ZIP_EXPORT __declspec(dllexport) 26 | #else 27 | #define ZIP_EXPORT __declspec(dllimport) 28 | #endif 29 | #else 30 | #define ZIP_EXPORT __attribute__((visibility("default"))) 31 | #endif 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER) 39 | // 64-bit Windows is the only mainstream platform 40 | // where sizeof(long) != sizeof(void*) 41 | #ifdef _WIN64 42 | typedef long long ssize_t; /* byte count or error */ 43 | #else 44 | typedef long ssize_t; /* byte count or error */ 45 | #endif 46 | #endif 47 | 48 | /** 49 | * @mainpage 50 | * 51 | * Documentation for @ref zip. 52 | */ 53 | 54 | /** 55 | * @addtogroup zip 56 | * @{ 57 | */ 58 | 59 | /** 60 | * Default zip compression level. 61 | */ 62 | #define ZIP_DEFAULT_COMPRESSION_LEVEL 6 63 | 64 | /** 65 | * Error codes 66 | */ 67 | #define ZIP_ENOINIT -1 // not initialized 68 | #define ZIP_EINVENTNAME -2 // invalid entry name 69 | #define ZIP_ENOENT -3 // entry not found 70 | #define ZIP_EINVMODE -4 // invalid zip mode 71 | #define ZIP_EINVLVL -5 // invalid compression level 72 | #define ZIP_ENOSUP64 -6 // no zip 64 support 73 | #define ZIP_EMEMSET -7 // memset error 74 | #define ZIP_EWRTENT -8 // cannot write data to entry 75 | #define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor 76 | #define ZIP_EINVIDX -10 // invalid index 77 | #define ZIP_ENOHDR -11 // header not found 78 | #define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer 79 | #define ZIP_ECRTHDR -13 // cannot create entry header 80 | #define ZIP_EWRTHDR -14 // cannot write entry header 81 | #define ZIP_EWRTDIR -15 // cannot write to central dir 82 | #define ZIP_EOPNFILE -16 // cannot open file 83 | #define ZIP_EINVENTTYPE -17 // invalid entry type 84 | #define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation 85 | #define ZIP_ENOFILE -19 // file not found 86 | #define ZIP_ENOPERM -20 // no permission 87 | #define ZIP_EOOMEM -21 // out of memory 88 | #define ZIP_EINVZIPNAME -22 // invalid zip archive name 89 | #define ZIP_EMKDIR -23 // make dir error 90 | #define ZIP_ESYMLINK -24 // symlink error 91 | #define ZIP_ECLSZIP -25 // close archive error 92 | #define ZIP_ECAPSIZE -26 // capacity size too small 93 | #define ZIP_EFSEEK -27 // fseek error 94 | #define ZIP_EFREAD -28 // fread error 95 | #define ZIP_EFWRITE -29 // fwrite error 96 | #define ZIP_ERINIT -30 // cannot initialize reader 97 | #define ZIP_EWINIT -31 // cannot initialize writer 98 | #define ZIP_EWRINIT -32 // cannot initialize writer from reader 99 | #define ZIP_EINVAL -33 // invalid argument 100 | #define ZIP_ENORITER -34 // cannot initialize reader iterator 101 | 102 | /** 103 | * Looks up the error message string corresponding to an error number. 104 | * @param errnum error number 105 | * @return error message string corresponding to errnum or NULL if error is not 106 | * found. 107 | */ 108 | extern ZIP_EXPORT const char *zip_strerror(int errnum); 109 | 110 | /** 111 | * @struct zip_t 112 | * 113 | * This data structure is used throughout the library to represent zip archive - 114 | * forward declaration. 115 | */ 116 | struct zip_t; 117 | 118 | /** 119 | * Opens zip archive with compression level using the given mode. 120 | * 121 | * @param zipname zip archive file name. 122 | * @param level compression level (0-9 are the standard zlib-style levels). 123 | * @param mode file access mode. 124 | * - 'r': opens a file for reading/extracting (the file must exists). 125 | * - 'w': creates an empty file for writing. 126 | * - 'a': appends to an existing archive. 127 | * 128 | * @return the zip archive handler or NULL on error 129 | */ 130 | extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level, 131 | char mode); 132 | 133 | /** 134 | * Opens zip archive with compression level using the given mode. 135 | * The function additionally returns @param errnum - 136 | * 137 | * @param zipname zip archive file name. 138 | * @param level compression level (0-9 are the standard zlib-style levels). 139 | * @param mode file access mode. 140 | * - 'r': opens a file for reading/extracting (the file must exists). 141 | * - 'w': creates an empty file for writing. 142 | * - 'a': appends to an existing archive. 143 | * @param errnum 0 on success, negative number (< 0) on error. 144 | * 145 | * @return the zip archive handler or NULL on error 146 | */ 147 | extern ZIP_EXPORT struct zip_t * 148 | zip_openwitherror(const char *zipname, int level, char mode, int *errnum); 149 | 150 | /** 151 | * Closes the zip archive, releases resources - always finalize. 152 | * 153 | * @param zip zip archive handler. 154 | */ 155 | extern ZIP_EXPORT void zip_close(struct zip_t *zip); 156 | 157 | /** 158 | * Determines if the archive has a zip64 end of central directory headers. 159 | * 160 | * @param zip zip archive handler. 161 | * 162 | * @return the return code - 1 (true), 0 (false), negative number (< 0) on 163 | * error. 164 | */ 165 | extern ZIP_EXPORT int zip_is64(struct zip_t *zip); 166 | 167 | /** 168 | * Returns the offset in the stream where the zip header is located. 169 | * 170 | * @param zip zip archive handler. 171 | * @param offset zip header offset. 172 | * 173 | * @return the return code - 0 if successful, negative number (< 0) on error. 174 | */ 175 | extern ZIP_EXPORT int zip_offset(struct zip_t *zip, uint64_t *offset); 176 | 177 | /** 178 | * Opens an entry by name in the zip archive. 179 | * 180 | * For zip archive opened in 'w' or 'a' mode the function will append 181 | * a new entry. In readonly mode the function tries to locate the entry 182 | * in global dictionary. 183 | * 184 | * @param zip zip archive handler. 185 | * @param entryname an entry name in local dictionary. 186 | * 187 | * @return the return code - 0 on success, negative number (< 0) on error. 188 | */ 189 | extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname); 190 | 191 | /** 192 | * Opens an entry by name in the zip archive. 193 | * 194 | * For zip archive opened in 'w' or 'a' mode the function will append 195 | * a new entry. In readonly mode the function tries to locate the entry 196 | * in global dictionary (case sensitive). 197 | * 198 | * @param zip zip archive handler. 199 | * @param entryname an entry name in local dictionary (case sensitive). 200 | * 201 | * @return the return code - 0 on success, negative number (< 0) on error. 202 | */ 203 | extern ZIP_EXPORT int zip_entry_opencasesensitive(struct zip_t *zip, 204 | const char *entryname); 205 | 206 | /** 207 | * Opens a new entry by index in the zip archive. 208 | * 209 | * This function is only valid if zip archive was opened in 'r' (readonly) mode. 210 | * 211 | * @param zip zip archive handler. 212 | * @param index index in local dictionary. 213 | * 214 | * @return the return code - 0 on success, negative number (< 0) on error. 215 | */ 216 | extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, size_t index); 217 | 218 | /** 219 | * Closes a zip entry, flushes buffer and releases resources. 220 | * 221 | * @param zip zip archive handler. 222 | * 223 | * @return the return code - 0 on success, negative number (< 0) on error. 224 | */ 225 | extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip); 226 | 227 | /** 228 | * Returns a local name of the current zip entry. 229 | * 230 | * The main difference between user's entry name and local entry name 231 | * is optional relative path. 232 | * Following .ZIP File Format Specification - the path stored MUST not contain 233 | * a drive or device letter, or a leading slash. 234 | * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' 235 | * for compatibility with Amiga and UNIX file systems etc. 236 | * 237 | * @param zip: zip archive handler. 238 | * 239 | * @return the pointer to the current zip entry name, or NULL on error. 240 | */ 241 | extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip); 242 | 243 | /** 244 | * Returns an index of the current zip entry. 245 | * 246 | * @param zip zip archive handler. 247 | * 248 | * @return the index on success, negative number (< 0) on error. 249 | */ 250 | extern ZIP_EXPORT ssize_t zip_entry_index(struct zip_t *zip); 251 | 252 | /** 253 | * Determines if the current zip entry is a directory entry. 254 | * 255 | * @param zip zip archive handler. 256 | * 257 | * @return the return code - 1 (true), 0 (false), negative number (< 0) on 258 | * error. 259 | */ 260 | extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip); 261 | 262 | /** 263 | * Returns the uncompressed size of the current zip entry. 264 | * Alias for zip_entry_uncomp_size (for backward compatibility). 265 | * 266 | * @param zip zip archive handler. 267 | * 268 | * @return the uncompressed size in bytes. 269 | */ 270 | extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip); 271 | 272 | /** 273 | * Returns the uncompressed size of the current zip entry. 274 | * 275 | * @param zip zip archive handler. 276 | * 277 | * @return the uncompressed size in bytes. 278 | */ 279 | extern ZIP_EXPORT unsigned long long zip_entry_uncomp_size(struct zip_t *zip); 280 | 281 | /** 282 | * Returns the compressed size of the current zip entry. 283 | * 284 | * @param zip zip archive handler. 285 | * 286 | * @return the compressed size in bytes. 287 | */ 288 | extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip); 289 | 290 | /** 291 | * Returns CRC-32 checksum of the current zip entry. 292 | * 293 | * @param zip zip archive handler. 294 | * 295 | * @return the CRC-32 checksum. 296 | */ 297 | extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip); 298 | 299 | /** 300 | * Returns byte offset of the current zip entry 301 | * in the archive's central directory. 302 | * 303 | * @param zip zip archive handler. 304 | * 305 | * @return the offset in bytes. 306 | */ 307 | extern ZIP_EXPORT unsigned long long zip_entry_dir_offset(struct zip_t *zip); 308 | 309 | /** 310 | * Returns the current zip entry's local header file offset in bytes. 311 | * 312 | * @param zip zip archive handler. 313 | * 314 | * @return the entry's local header file offset in bytes. 315 | */ 316 | extern ZIP_EXPORT unsigned long long zip_entry_header_offset(struct zip_t *zip); 317 | 318 | /** 319 | * Compresses an input buffer for the current zip entry. 320 | * 321 | * @param zip zip archive handler. 322 | * @param buf input buffer. 323 | * @param bufsize input buffer size (in bytes). 324 | * 325 | * @return the return code - 0 on success, negative number (< 0) on error. 326 | */ 327 | extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf, 328 | size_t bufsize); 329 | 330 | /** 331 | * Compresses a file for the current zip entry. 332 | * 333 | * @param zip zip archive handler. 334 | * @param filename input file. 335 | * 336 | * @return the return code - 0 on success, negative number (< 0) on error. 337 | */ 338 | extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename); 339 | 340 | /** 341 | * Extracts the current zip entry into output buffer. 342 | * 343 | * The function allocates sufficient memory for a output buffer. 344 | * 345 | * @param zip zip archive handler. 346 | * @param buf output buffer. 347 | * @param bufsize output buffer size (in bytes). 348 | * 349 | * @note remember to release memory allocated for a output buffer. 350 | * for large entries, please take a look at zip_entry_extract function. 351 | * 352 | * @return the return code - the number of bytes actually read on success. 353 | * Otherwise a negative number (< 0) on error. 354 | */ 355 | extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf, 356 | size_t *bufsize); 357 | 358 | /** 359 | * Extracts the current zip entry into a memory buffer using no memory 360 | * allocation. 361 | * 362 | * @param zip zip archive handler. 363 | * @param buf preallocated output buffer. 364 | * @param bufsize output buffer size (in bytes). 365 | * 366 | * @note ensure supplied output buffer is large enough. 367 | * zip_entry_size function (returns uncompressed size for the current 368 | * entry) can be handy to estimate how big buffer is needed. 369 | * For large entries, please take a look at zip_entry_extract function. 370 | * 371 | * @return the return code - the number of bytes actually read on success. 372 | * Otherwise a negative number (< 0) on error (e.g. bufsize is not large 373 | * enough). 374 | */ 375 | extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, 376 | size_t bufsize); 377 | 378 | /** 379 | * Extracts the part of the current zip entry into a memory buffer using no 380 | * memory allocation for the buffer. 381 | * 382 | * @param zip zip archive handler. 383 | * @param offset the offset of the entry (in bytes). 384 | * @param size requested number of bytes (in bytes). 385 | * @param buf preallocated output buffer. 386 | * 387 | * @note the iterator api uses an allocation to create its state 388 | * @note each call will iterate from the start of the entry 389 | * 390 | * @return the return code - the number of bytes actually read on success. 391 | * Otherwise a negative number (< 0) on error (e.g. offset is too 392 | * large). 393 | */ 394 | extern ZIP_EXPORT ssize_t zip_entry_noallocreadwithoffset(struct zip_t *zip, 395 | size_t offset, 396 | size_t size, 397 | void *buf); 398 | 399 | /** 400 | * Extracts the current zip entry into output file. 401 | * 402 | * @param zip zip archive handler. 403 | * @param filename output file. 404 | * 405 | * @return the return code - 0 on success, negative number (< 0) on error. 406 | */ 407 | extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename); 408 | 409 | /** 410 | * Extracts the current zip entry using a callback function (on_extract). 411 | * 412 | * @param zip zip archive handler. 413 | * @param on_extract callback function. 414 | * @param arg opaque pointer (optional argument, which you can pass to the 415 | * on_extract callback) 416 | * 417 | * @return the return code - 0 on success, negative number (< 0) on error. 418 | */ 419 | extern ZIP_EXPORT int 420 | zip_entry_extract(struct zip_t *zip, 421 | size_t (*on_extract)(void *arg, uint64_t offset, 422 | const void *data, size_t size), 423 | void *arg); 424 | 425 | /** 426 | * Returns the number of all entries (files and directories) in the zip archive. 427 | * 428 | * @param zip zip archive handler. 429 | * 430 | * @return the return code - the number of entries on success, negative number 431 | * (< 0) on error. 432 | */ 433 | extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip); 434 | 435 | /** 436 | * Deletes zip archive entries. 437 | * 438 | * @param zip zip archive handler. 439 | * @param entries array of zip archive entries to be deleted. 440 | * @param len the number of entries to be deleted. 441 | * @return the number of deleted entries, or negative number (< 0) on error. 442 | */ 443 | extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip, 444 | char *const entries[], size_t len); 445 | 446 | /** 447 | * Deletes zip archive entries. 448 | * 449 | * @param zip zip archive handler. 450 | * @param entries array of zip archive entries indices to be deleted. 451 | * @param len the number of entries to be deleted. 452 | * @return the number of deleted entries, or negative number (< 0) on error. 453 | */ 454 | extern ZIP_EXPORT ssize_t zip_entries_deletebyindex(struct zip_t *zip, 455 | size_t entries[], 456 | size_t len); 457 | 458 | /** 459 | * Extracts a zip archive stream into directory. 460 | * 461 | * If on_extract is not NULL, the callback will be called after 462 | * successfully extracted each zip entry. 463 | * Returning a negative value from the callback will cause abort and return an 464 | * error. The last argument (void *arg) is optional, which you can use to pass 465 | * data to the on_extract callback. 466 | * 467 | * @param stream zip archive stream. 468 | * @param size stream size. 469 | * @param dir output directory. 470 | * @param on_extract on extract callback. 471 | * @param arg opaque pointer. 472 | * 473 | * @return the return code - 0 on success, negative number (< 0) on error. 474 | */ 475 | extern ZIP_EXPORT int 476 | zip_stream_extract(const char *stream, size_t size, const char *dir, 477 | int (*on_extract)(const char *filename, void *arg), 478 | void *arg); 479 | 480 | /** 481 | * Opens zip archive stream into memory. 482 | * 483 | * @param stream zip archive stream. 484 | * @param size stream size. 485 | * @param level compression level (0-9 are the standard zlib-style levels). 486 | * @param mode file access mode. 487 | * - 'r': opens a file for reading/extracting (the file must exists). 488 | * - 'w': creates an empty file for writing. 489 | * - 'a': appends to an existing archive. 490 | * 491 | * @return the zip archive handler or NULL on error 492 | */ 493 | extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size, 494 | int level, char mode); 495 | 496 | /** 497 | * Opens zip archive stream into memory. 498 | * The function additionally returns @param errnum - 499 | * 500 | * @param stream zip archive stream. 501 | * @param size stream size.* 502 | * @param level compression level (0-9 are the standard zlib-style levels). 503 | * @param mode file access mode. 504 | * - 'r': opens a file for reading/extracting (the file must exists). 505 | * - 'w': creates an empty file for writing. 506 | * - 'a': appends to an existing archive. 507 | * @param errnum 0 on success, negative number (< 0) on error. 508 | * 509 | * @return the zip archive handler or NULL on error 510 | */ 511 | extern ZIP_EXPORT struct zip_t *zip_stream_openwitherror(const char *stream, 512 | size_t size, int level, 513 | char mode, 514 | int *errnum); 515 | 516 | /** 517 | * Copy zip archive stream output buffer. 518 | * 519 | * @param zip zip archive handler. 520 | * @param buf output buffer. User should free buf. 521 | * @param bufsize output buffer size (in bytes). 522 | * 523 | * @return copy size 524 | */ 525 | extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf, 526 | size_t *bufsize); 527 | 528 | /** 529 | * Close zip archive releases resources. 530 | * 531 | * @param zip zip archive handler. 532 | * 533 | * @return 534 | */ 535 | extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip); 536 | 537 | /** 538 | * Opens zip archive from existing FILE stream with compression level using the 539 | * given mode. The stream will not be closed when calling zip_close. 540 | * 541 | * @param stream C FILE stream. 542 | * @param level compression level (0-9 are the standard zlib-style levels). 543 | * @param mode file access mode. This mode should be equivalent to the mode 544 | * provided when opening the file. 545 | * - 'r': opens a file for reading/extracting (the file must exists). 546 | * - 'w': creates an empty file for writing. 547 | * - 'a': appends to an existing archive. 548 | * 549 | * @return the zip archive handler or NULL on error 550 | */ 551 | extern ZIP_EXPORT struct zip_t *zip_cstream_open(FILE *stream, int level, 552 | char mode); 553 | 554 | /** 555 | * Opens zip archive from existing FILE stream with compression level using the 556 | * given mode. The function additionally returns @param errnum - The stream will 557 | * not be closed when calling zip_close. 558 | * 559 | * @param stream C FILE stream. 560 | * @param level compression level (0-9 are the standard zlib-style levels). 561 | * @param mode file access mode. 562 | * - 'r': opens a file for reading/extracting (the file must exists). 563 | * - 'w': creates an empty file for writing. 564 | * - 'a': appends to an existing archive. 565 | * @param errnum 0 on success, negative number (< 0) on error. 566 | * 567 | * @return the zip archive handler or NULL on error 568 | */ 569 | extern ZIP_EXPORT struct zip_t * 570 | zip_cstream_openwitherror(FILE *stream, int level, char mode, int *errnum); 571 | 572 | /** 573 | * Closes the zip archive, releases resources - always finalize. 574 | * This function is an alias for zip_close function. 575 | * 576 | * @param zip zip archive handler. 577 | */ 578 | extern ZIP_EXPORT void zip_cstream_close(struct zip_t *zip); 579 | 580 | /** 581 | * Creates a new archive and puts files into a single zip archive. 582 | * 583 | * @param zipname zip archive file. 584 | * @param filenames input files. 585 | * @param len: number of input files. 586 | * 587 | * @return the return code - 0 on success, negative number (< 0) on error. 588 | */ 589 | extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[], 590 | size_t len); 591 | 592 | /** 593 | * Extracts a zip archive file into directory. 594 | * 595 | * If on_extract_entry is not NULL, the callback will be called after 596 | * successfully extracted each zip entry. 597 | * Returning a negative value from the callback will cause abort and return an 598 | * error. The last argument (void *arg) is optional, which you can use to pass 599 | * data to the on_extract_entry callback. 600 | * 601 | * @param zipname zip archive file. 602 | * @param dir output directory. 603 | * @param on_extract_entry on extract callback. 604 | * @param arg opaque pointer. 605 | * 606 | * @return the return code - 0 on success, negative number (< 0) on error. 607 | */ 608 | extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir, 609 | int (*on_extract_entry)(const char *filename, 610 | void *arg), 611 | void *arg); 612 | /** @} */ 613 | #ifdef __cplusplus 614 | } 615 | #endif 616 | 617 | #endif 618 | -------------------------------------------------------------------------------- /configs/oldCsgo.json: -------------------------------------------------------------------------------- 1 | { 2 | "executable": "csgo.exe", 3 | "filename": "csgo", 4 | "signatures": [ 5 | { 6 | "name": "dwClientState", 7 | "extra": 0, 8 | "relative": true, 9 | "module": "engine.dll", 10 | "offsets": [1], 11 | "pattern": "A1 ? ? ? ? 33 D2 6A 00 6A 00 33 C9 89 B0" 12 | }, 13 | { 14 | "name": "dwClientState_GetLocalPlayer", 15 | "extra": 0, 16 | "relative": false, 17 | "module": "engine.dll", 18 | "offsets": [2], 19 | "pattern": "8B 80 ? ? ? ? 40 C3" 20 | }, 21 | { 22 | "name": "dwClientState_IsHLTV", 23 | "extra": 0, 24 | "relative": false, 25 | "module": "engine.dll", 26 | "offsets": [2], 27 | "pattern": "80 BF ? ? ? ? ? 0F 84 ? ? ? ? 32 DB" 28 | }, 29 | { 30 | "name": "dwClientState_Map", 31 | "extra": 0, 32 | "relative": false, 33 | "module": "engine.dll", 34 | "offsets": [1], 35 | "pattern": "05 ? ? ? ? C3 CC CC CC CC CC CC CC A1" 36 | }, 37 | { 38 | "name": "dwClientState_MapDirectory", 39 | "extra": 0, 40 | "relative": false, 41 | "module": "engine.dll", 42 | "offsets": [7], 43 | "pattern": "B8 ? ? ? ? C3 05 ? ? ? ? C3" 44 | }, 45 | { 46 | "name": "dwClientState_MaxPlayer", 47 | "extra": 0, 48 | "relative": false, 49 | "module": "engine.dll", 50 | "offsets": [7], 51 | "pattern": "A1 ? ? ? ? 8B 80 ? ? ? ? C3 CC CC CC CC 55 8B EC 8A 45 08" 52 | }, 53 | { 54 | "name": "dwClientState_PlayerInfo", 55 | "extra": 0, 56 | "relative": false, 57 | "module": "engine.dll", 58 | "offsets": [2], 59 | "pattern": "8B 89 ? ? ? ? 85 C9 0F 84 ? ? ? ? 8B 01" 60 | }, 61 | { 62 | "name": "dwClientState_State", 63 | "extra": 0, 64 | "relative": false, 65 | "module": "engine.dll", 66 | "offsets": [2], 67 | "pattern": "83 B8 ? ? ? ? ? 0F 94 C0 C3" 68 | }, 69 | { 70 | "name": "dwClientState_ViewAngles", 71 | "extra": 0, 72 | "relative": false, 73 | "module": "engine.dll", 74 | "offsets": [4], 75 | "pattern": "F3 0F 11 86 ? ? ? ? F3 0F 10 44 24 ? F3 0F 11 86" 76 | }, 77 | { 78 | "name": "clientstate_delta_ticks", 79 | "extra": 0, 80 | "relative": false, 81 | "module": "engine.dll", 82 | "offsets": [2], 83 | "pattern": "C7 87 ? ? ? ? ? ? ? ? FF 15 ? ? ? ? 83 C4 08" 84 | }, 85 | { 86 | "name": "clientstate_last_outgoing_command", 87 | "extra": 0, 88 | "relative": false, 89 | "module": "engine.dll", 90 | "offsets": [2], 91 | "pattern": "8B 8F ? ? ? ? 8B 87 ? ? ? ? 41" 92 | }, 93 | { 94 | "name": "clientstate_choked_commands", 95 | "extra": 0, 96 | "relative": false, 97 | "module": "engine.dll", 98 | "offsets": [2], 99 | "pattern": "8B 87 ? ? ? ? 41" 100 | }, 101 | { 102 | "name": "clientstate_net_channel", 103 | "extra": 0, 104 | "relative": false, 105 | "module": "engine.dll", 106 | "offsets": [2], 107 | "pattern": "8B 8F ? ? ? ? 8B 01 8B 40 18" 108 | }, 109 | { 110 | "name": "dwEntityList", 111 | "extra": 0, 112 | "relative": true, 113 | "module": "client.dll", 114 | "offsets": [1], 115 | "pattern": "BB ? ? ? ? 83 FF 01 0F 8C ? ? ? ? 3B F8" 116 | }, 117 | { 118 | "name": "dwForceAttack", 119 | "extra": 0, 120 | "relative": true, 121 | "module": "client.dll", 122 | "offsets": [2], 123 | "pattern": "89 0D ? ? ? ? 8B 0D ? ? ? ? 8B F2 8B C1 83 CE 04" 124 | }, 125 | { 126 | "name": "dwForceAttack2", 127 | "extra": 12, 128 | "relative": true, 129 | "module": "client.dll", 130 | "offsets": [2], 131 | "pattern": "89 0D ? ? ? ? 8B 0D ? ? ? ? 8B F2 8B C1 83 CE 04" 132 | }, 133 | { 134 | "name": "dwForceBackward", 135 | "extra": 0, 136 | "relative": true, 137 | "module": "client.dll", 138 | "offsets": [287], 139 | "pattern": "55 8B EC 51 53 8A 5D 08" 140 | }, 141 | { 142 | "name": "dwForceForward", 143 | "extra": 0, 144 | "relative": true, 145 | "module": "client.dll", 146 | "offsets": [245], 147 | "pattern": "55 8B EC 51 53 8A 5D 08" 148 | }, 149 | { 150 | "name": "dwForceJump", 151 | "extra": 0, 152 | "relative": true, 153 | "module": "client.dll", 154 | "offsets": [2], 155 | "pattern": "8B 0D ? ? ? ? 8B D6 8B C1 83 CA 02" 156 | }, 157 | { 158 | "name": "dwForceLeft", 159 | "extra": 0, 160 | "relative": true, 161 | "module": "client.dll", 162 | "offsets": [465], 163 | "pattern": "55 8B EC 51 53 8A 5D 08" 164 | }, 165 | { 166 | "name": "dwForceRight", 167 | "extra": 0, 168 | "relative": true, 169 | "module": "client.dll", 170 | "offsets": [512], 171 | "pattern": "55 8B EC 51 53 8A 5D 08" 172 | }, 173 | { 174 | "name": "dwGameDir", 175 | "extra": 0, 176 | "relative": true, 177 | "module": "engine.dll", 178 | "offsets": [1], 179 | "pattern": "68 ? ? ? ? 8D 85 ? ? ? ? 50 68 ? ? ? ? 68" 180 | }, 181 | { 182 | "name": "dwGameRulesProxy", 183 | "extra": 0, 184 | "relative": true, 185 | "module": "client.dll", 186 | "offsets": [1], 187 | "pattern": "A1 ? ? ? ? 85 C0 0F 84 ? ? ? ? 80 B8 ? ? ? ? ? 74 7A" 188 | }, 189 | { 190 | "name": "dwGetAllClasses", 191 | "extra": 0, 192 | "relative": true, 193 | "module": "client.dll", 194 | "offsets": [1, 0], 195 | "pattern": "A1 ? ? ? ? C3 CC CC CC CC CC CC CC CC CC CC A1 ? ? ? ? B9" 196 | }, 197 | { 198 | "name": "dwGlobalVars", 199 | "extra": 0, 200 | "relative": true, 201 | "module": "engine.dll", 202 | "offsets": [1], 203 | "pattern": "68 ? ? ? ? 68 ? ? ? ? FF 50 08 85 C0" 204 | }, 205 | { 206 | "name": "dwGlowObjectManager", 207 | "extra": 4, 208 | "relative": true, 209 | "module": "client.dll", 210 | "offsets": [1], 211 | "pattern": "A1 ? ? ? ? A8 01 75 4B" 212 | }, 213 | { 214 | "name": "dwInput", 215 | "extra": 0, 216 | "relative": true, 217 | "module": "client.dll", 218 | "offsets": [1], 219 | "pattern": "B9 ? ? ? ? F3 0F 11 04 24 FF 50 10" 220 | }, 221 | { 222 | "name": "dwInterfaceLinkList", 223 | "extra": 0, 224 | "relative": true, 225 | "module": "client.dll", 226 | "offsets": [], 227 | "pattern": "8B 35 ? ? ? ? 57 85 F6 74 ? 8B 7D 08 8B 4E 04 8B C7 8A 11 3A 10" 228 | }, 229 | { 230 | "name": "dwLocalPlayer", 231 | "extra": 4, 232 | "relative": true, 233 | "module": "client.dll", 234 | "offsets": [3], 235 | "pattern": "8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF" 236 | }, 237 | { 238 | "name": "dwMouseEnable", 239 | "extra": 48, 240 | "relative": true, 241 | "module": "client.dll", 242 | "offsets": [1], 243 | "pattern": "B9 ? ? ? ? FF 50 34 85 C0 75 10" 244 | }, 245 | { 246 | "name": "dwMouseEnablePtr", 247 | "extra": 0, 248 | "relative": true, 249 | "module": "client.dll", 250 | "offsets": [1], 251 | "pattern": "B9 ? ? ? ? FF 50 34 85 C0 75 10" 252 | }, 253 | { 254 | "name": "dwPlayerResource", 255 | "extra": 0, 256 | "relative": true, 257 | "module": "client.dll", 258 | "offsets": [2], 259 | "pattern": "8B 3D ? ? ? ? 85 FF 0F 84 ? ? ? ? 81 C7" 260 | }, 261 | { 262 | "name": "dwRadarBase", 263 | "extra": 0, 264 | "relative": true, 265 | "module": "client.dll", 266 | "offsets": [1], 267 | "pattern": "A1 ? ? ? ? 8B 0C B0 8B 01 FF 50 ? 46 3B 35 ? ? ? ? 7C EA 8B 0D" 268 | }, 269 | { 270 | "name": "dwSensitivity", 271 | "extra": 0, 272 | "relative": true, 273 | "module": "client.dll", 274 | "offsets": [2], 275 | "pattern": "81 F9 ? ? ? ? 75 7E F3 0F 10 05" 276 | }, 277 | { 278 | "name": "dwSensitivityPtr", 279 | "extra": 0, 280 | "relative": true, 281 | "module": "client.dll", 282 | "offsets": [2], 283 | "pattern": "81 F9 ? ? ? ? 75 7E F3 0F 10 05" 284 | }, 285 | { 286 | "name": "dwSetClanTag", 287 | "extra": 0, 288 | "relative": true, 289 | "module": "engine.dll", 290 | "offsets": [], 291 | "pattern": "53 56 57 8B DA 8B F9 FF 15" 292 | }, 293 | { 294 | "name": "dwViewMatrix", 295 | "extra": 176, 296 | "relative": true, 297 | "module": "client.dll", 298 | "offsets": [3], 299 | "pattern": "0F 10 05 ? ? ? ? 8D 85 ? ? ? ? B9" 300 | }, 301 | { 302 | "name": "dwWeaponTable", 303 | "extra": 0, 304 | "relative": true, 305 | "module": "client.dll", 306 | "offsets": [1], 307 | "pattern": "B9 ? ? ? ? 6A 00 FF 50 08 C3" 308 | }, 309 | { 310 | "name": "dwWeaponTableIndex", 311 | "extra": 0, 312 | "relative": false, 313 | "module": "client.dll", 314 | "offsets": [2], 315 | "pattern": "39 86 ? ? ? ? 74 06 89 86 ? ? ? ? 8B 86" 316 | }, 317 | { 318 | "name": "dwYawPtr", 319 | "extra": 0, 320 | "relative": true, 321 | "module": "client.dll", 322 | "offsets": [5], 323 | "pattern": "8B 44 24 1C 35 ? ? ? ? 89 44 24 14 EB 0D" 324 | }, 325 | { 326 | "name": "dwZoomSensitivityRatioPtr", 327 | "extra": 0, 328 | "relative": true, 329 | "module": "client.dll", 330 | "offsets": [1], 331 | "pattern": "35 ? ? ? ? 89 45 FC EB 0A 8B 01 8B 40 30 FF D0 D9 5D FC A1" 332 | }, 333 | { 334 | "name": "dwbSendPackets", 335 | "extra": 1, 336 | "relative": true, 337 | "module": "engine.dll", 338 | "offsets": [], 339 | "pattern": "B3 01 8B 01 8B 40 10 FF D0 84 C0 74 0F 80 BF ? ? ? ? ? 0F 84" 340 | }, 341 | { 342 | "name": "dwppDirect3DDevice9", 343 | "extra": 0, 344 | "relative": true, 345 | "module": "shaderapidx9.dll", 346 | "offsets": [1], 347 | "pattern": "A1 ? ? ? ? 50 8B 08 FF 51 0C" 348 | }, 349 | { 350 | "name": "m_pStudioHdr", 351 | "extra": 0, 352 | "relative": false, 353 | "module": "client.dll", 354 | "offsets": [2], 355 | "pattern": "8B B6 ? ? ? ? 85 F6 74 05 83 3E 00 75 02 33 F6 F3 0F 10 44 24" 356 | }, 357 | { 358 | "name": "m_yawClassPtr", 359 | "extra": 0, 360 | "relative": true, 361 | "module": "client.dll", 362 | "offsets": [5], 363 | "pattern": "8B 44 24 1C 35 ? ? ? ? 89 44 24 14 EB 0D" 364 | }, 365 | { 366 | "name": "m_pitchClassPtr", 367 | "extra": 0, 368 | "relative": true, 369 | "module": "client.dll", 370 | "offsets": [1], 371 | "pattern": "B9 ? ? ? ? 89 44 24 40" 372 | }, 373 | { 374 | "name": "interface_engine_cvar", 375 | "extra": 0, 376 | "relative": true, 377 | "module": "vstdlib.dll", 378 | "offsets": [2], 379 | "pattern": "8B 0D ? ? ? ? C7 05" 380 | }, 381 | { 382 | "name": "convar_name_hash_table", 383 | "extra": 0, 384 | "relative": true, 385 | "module": "vstdlib.dll", 386 | "offsets": [3], 387 | "pattern": "8B 3C 85" 388 | }, 389 | { 390 | "name": "m_bDormant", 391 | "extra": 8, 392 | "relative": false, 393 | "module": "client.dll", 394 | "offsets": [2], 395 | "pattern": "8A 81 ? ? ? ? C3 32 C0" 396 | }, 397 | { 398 | "name": "model_ambient_min", 399 | "extra": 0, 400 | "relative": true, 401 | "module": "engine.dll", 402 | "offsets": [4], 403 | "pattern": "F3 0F 10 0D ? ? ? ? F3 0F 11 4C 24 ? 8B 44 24 20 35 ? ? ? ? 89 44 24 0C" 404 | }, 405 | { 406 | "name": "set_abs_angles", 407 | "extra": 0, 408 | "relative": true, 409 | "module": "client.dll", 410 | "pattern": "55 8B EC 83 E4 F8 83 EC 64 53 56 57 8B F1 E8" 411 | }, 412 | { 413 | "name": "set_abs_origin", 414 | "extra": 0, 415 | "relative": true, 416 | "module": "client.dll", 417 | "pattern": "55 8B EC 83 E4 F8 51 53 56 57 8B F1 E8" 418 | }, 419 | { 420 | "name": "is_c4_owner", 421 | "extra": 0, 422 | "relative": true, 423 | "module": "client.dll", 424 | "pattern": "56 8B F1 85 F6 74 31" 425 | }, 426 | { 427 | "name": "force_update_spectator_glow", 428 | "extra": 0, 429 | "relative": true, 430 | "module": "client.dll", 431 | "pattern": "74 07 8B CB E8 ? ? ? ? 83 C7 10" 432 | }, 433 | { 434 | "name": "anim_overlays", 435 | "extra": 0, 436 | "relative": false, 437 | "module": "client.dll", 438 | "offsets": [2], 439 | "pattern": "8B 89 ? ? ? ? 8D 0C D1" 440 | }, 441 | { 442 | "name": "m_flSpawnTime", 443 | "extra": 0, 444 | "relative": false, 445 | "module": "client.dll", 446 | "offsets": [2], 447 | "pattern": "89 86 ? ? ? ? E8 ? ? ? ? 80 BE ? ? ? ? ?" 448 | }, 449 | { 450 | "name": "find_hud_element", 451 | "extra": 0, 452 | "relative": false, 453 | "module": "client.dll", 454 | "pattern": "55 8B EC 53 8B 5D 08 56 57 8B F9 33 F6 39 77 28" 455 | }, 456 | { 457 | "name": "m_bIsLocalPlayer", 458 | "extra": 0, 459 | "relative": false, 460 | "module": "client.dll", 461 | "offsets": [2], 462 | "pattern": "80 BF ? ? ? ? ? F2 0F 10 1D" 463 | } 464 | ], 465 | "netvars": [ 466 | { 467 | "name": "m_ArmorValue", 468 | "prop": "m_ArmorValue", 469 | "table": "DT_CSPlayer" 470 | }, 471 | { 472 | "name": "m_Collision", 473 | "prop": "m_Collision", 474 | "table": "DT_BasePlayer" 475 | }, 476 | { 477 | "name": "m_CollisionGroup", 478 | "prop": "m_CollisionGroup", 479 | "table": "DT_CSPlayer" 480 | }, 481 | { 482 | "name": "m_Local", 483 | "prop": "m_Local", 484 | "table": "DT_BasePlayer" 485 | }, 486 | { 487 | "name": "m_MoveType", 488 | "prop": "m_nRenderMode", 489 | "offset": 1, 490 | "table": "DT_CSPlayer" 491 | }, 492 | { 493 | "name": "m_OriginalOwnerXuidHigh", 494 | "prop": "m_OriginalOwnerXuidHigh", 495 | "table": "DT_BaseAttributableItem" 496 | }, 497 | { 498 | "name": "m_OriginalOwnerXuidLow", 499 | "prop": "m_OriginalOwnerXuidLow", 500 | "table": "DT_BaseAttributableItem" 501 | }, 502 | { 503 | "name": "m_aimPunchAngle", 504 | "prop": "m_aimPunchAngle", 505 | "table": "DT_BasePlayer" 506 | }, 507 | { 508 | "name": "m_aimPunchAngleVel", 509 | "prop": "m_aimPunchAngleVel", 510 | "table": "DT_BasePlayer" 511 | }, 512 | { 513 | "name": "m_bGunGameImmunity", 514 | "prop": "m_bGunGameImmunity", 515 | "table": "DT_CSPlayer" 516 | }, 517 | { 518 | "name": "m_bHasDefuser", 519 | "prop": "m_bHasDefuser", 520 | "table": "DT_CSPlayer" 521 | }, 522 | { 523 | "name": "m_bHasHelmet", 524 | "prop": "m_bHasHelmet", 525 | "table": "DT_CSPlayer" 526 | }, 527 | { 528 | "name": "m_bInReload", 529 | "prop": "m_flNextPrimaryAttack", 530 | "offset": 109, 531 | "table": "DT_BaseCombatWeapon" 532 | }, 533 | { 534 | "name": "m_bIsDefusing", 535 | "prop": "m_bIsDefusing", 536 | "table": "DT_CSPlayer" 537 | }, 538 | { 539 | "name": "m_bIsScoped", 540 | "prop": "m_bIsScoped", 541 | "table": "DT_CSPlayer" 542 | }, 543 | { 544 | "name": "m_bSpotted", 545 | "prop": "m_bSpotted", 546 | "table": "DT_BaseEntity" 547 | }, 548 | { 549 | "name": "m_bSpottedByMask", 550 | "prop": "m_bSpottedByMask", 551 | "table": "DT_BaseEntity" 552 | }, 553 | { 554 | "name": "m_dwBoneMatrix", 555 | "prop": "m_nForceBone", 556 | "offset": 28, 557 | "table": "DT_BaseAnimating" 558 | }, 559 | { 560 | "name": "m_fAccuracyPenalty", 561 | "prop": "m_fAccuracyPenalty", 562 | "table": "DT_WeaponCSBase" 563 | }, 564 | { 565 | "name": "m_fFlags", 566 | "prop": "m_fFlags", 567 | "table": "DT_CSPlayer" 568 | }, 569 | { 570 | "name": "m_hViewModel", 571 | "prop": "m_hViewModel[0]", 572 | "table": "DT_CSPlayer" 573 | }, 574 | { 575 | "name": "m_flFallbackWear", 576 | "prop": "m_flFallbackWear", 577 | "table": "DT_BaseAttributableItem" 578 | }, 579 | { 580 | "name": "m_flFlashDuration", 581 | "prop": "m_flFlashDuration", 582 | "table": "DT_CSPlayer" 583 | }, 584 | { 585 | "name": "m_flFlashMaxAlpha", 586 | "prop": "m_flFlashMaxAlpha", 587 | "table": "DT_CSPlayer" 588 | }, 589 | { 590 | "name": "m_flNextPrimaryAttack", 591 | "prop": "m_flNextPrimaryAttack", 592 | "table": "DT_BaseCombatWeapon" 593 | }, 594 | { 595 | "name": "m_hActiveWeapon", 596 | "prop": "m_hActiveWeapon", 597 | "table": "DT_BasePlayer" 598 | }, 599 | { 600 | "name": "m_hMyWeapons", 601 | "prop": "m_hActiveWeapon", 602 | "offset": -256, 603 | "table": "DT_BasePlayer" 604 | }, 605 | { 606 | "name": "m_hObserverTarget", 607 | "prop": "m_hObserverTarget", 608 | "table": "DT_BasePlayer" 609 | }, 610 | { 611 | "name": "m_hOwner", 612 | "prop": "m_hOwner", 613 | "table": "DT_PredictedViewModel" 614 | }, 615 | { 616 | "name": "m_hOwnerEntity", 617 | "prop": "m_hOwnerEntity", 618 | "table": "DT_CSPlayer" 619 | }, 620 | { 621 | "name": "m_iAccountID", 622 | "prop": "m_iAccountID", 623 | "table": "DT_BaseAttributableItem" 624 | }, 625 | { 626 | "name": "m_iClip1", 627 | "prop": "m_iClip1", 628 | "table": "DT_BaseCombatWeapon" 629 | }, 630 | { 631 | "name": "m_zoomLevel", 632 | "prop": "m_zoomLevel", 633 | "table": "DT_WeaponCSBaseGun" 634 | }, 635 | { 636 | "name": "m_iCompetitiveRanking", 637 | "prop": "m_iCompetitiveRanking", 638 | "table": "DT_CSPlayerResource" 639 | }, 640 | { 641 | "name": "m_iCompetitiveWins", 642 | "prop": "m_iCompetitiveWins", 643 | "table": "DT_CSPlayerResource" 644 | }, 645 | { 646 | "name": "m_iCrosshairId", 647 | "prop": "m_bHasDefuser", 648 | "offset": 92, 649 | "table": "DT_CSPlayer" 650 | }, 651 | { 652 | "name": "m_iEntityQuality", 653 | "prop": "m_iEntityQuality", 654 | "table": "DT_BaseAttributableItem" 655 | }, 656 | { 657 | "name": "m_iFOVStart", 658 | "prop": "m_iFOVStart", 659 | "table": "DT_CSPlayer" 660 | }, 661 | { 662 | "name": "m_iGlowIndex", 663 | "prop": "m_flFlashDuration", 664 | "offset": 24, 665 | "table": "DT_CSPlayer" 666 | }, 667 | { 668 | "name": "m_iHealth", 669 | "prop": "m_iHealth", 670 | "table": "DT_BasePlayer" 671 | }, 672 | { 673 | "name": "m_iItemDefinitionIndex", 674 | "prop": "m_iItemDefinitionIndex", 675 | "table": "DT_BaseCombatWeapon" 676 | }, 677 | { 678 | "name": "m_iItemIDHigh", 679 | "prop": "m_iItemIDHigh", 680 | "table": "DT_BaseAttributableItem" 681 | }, 682 | { 683 | "name": "m_iObserverMode", 684 | "prop": "m_iObserverMode", 685 | "table": "DT_BasePlayer" 686 | }, 687 | { 688 | "name": "m_iShotsFired", 689 | "prop": "m_iShotsFired", 690 | "table": "DT_CSPlayer" 691 | }, 692 | { 693 | "name": "m_iState", 694 | "prop": "m_iState", 695 | "table": "DT_BaseCombatWeapon" 696 | }, 697 | { 698 | "name": "m_iTeamNum", 699 | "prop": "m_iTeamNum", 700 | "table": "DT_BasePlayer" 701 | }, 702 | { 703 | "name": "m_lifeState", 704 | "prop": "m_lifeState", 705 | "table": "DT_CSPlayer" 706 | }, 707 | { 708 | "name": "m_nFallbackPaintKit", 709 | "prop": "m_nFallbackPaintKit", 710 | "table": "DT_BaseAttributableItem" 711 | }, 712 | { 713 | "name": "m_nFallbackSeed", 714 | "prop": "m_nFallbackSeed", 715 | "table": "DT_BaseAttributableItem" 716 | }, 717 | { 718 | "name": "m_nFallbackStatTrak", 719 | "prop": "m_nFallbackStatTrak", 720 | "table": "DT_BaseAttributableItem" 721 | }, 722 | { 723 | "name": "m_iDefaultFOV", 724 | "prop": "m_iDefaultFOV", 725 | "table": "DT_CSPlayer" 726 | }, 727 | { 728 | "name": "m_iFOV", 729 | "prop": "m_iFOV", 730 | "table": "DT_CSPlayer" 731 | }, 732 | { 733 | "name": "m_nForceBone", 734 | "prop": "m_nForceBone", 735 | "table": "DT_BaseAnimating" 736 | }, 737 | { 738 | "name": "m_nTickBase", 739 | "prop": "m_nTickBase", 740 | "table": "DT_BasePlayer" 741 | }, 742 | { 743 | "name": "m_rgflCoordinateFrame", 744 | "prop": "m_CollisionGroup", 745 | "offset": -48, 746 | "table": "DT_CSPlayer" 747 | }, 748 | { 749 | "name": "m_szCustomName", 750 | "prop": "m_szCustomName", 751 | "table": "DT_BaseAttributableItem" 752 | }, 753 | { 754 | "name": "m_szLastPlaceName", 755 | "prop": "m_szLastPlaceName", 756 | "table": "DT_CSPlayer" 757 | }, 758 | { 759 | "name": "m_vecOrigin", 760 | "prop": "m_vecOrigin", 761 | "table": "DT_BasePlayer" 762 | }, 763 | { 764 | "name": "m_vecVelocity", 765 | "prop": "m_vecVelocity[0]", 766 | "table": "DT_CSPlayer" 767 | }, 768 | { 769 | "name": "m_vecViewOffset", 770 | "prop": "m_vecViewOffset[0]", 771 | "table": "DT_CSPlayer" 772 | }, 773 | { 774 | "name": "m_viewPunchAngle", 775 | "prop": "m_viewPunchAngle", 776 | "table": "DT_BasePlayer" 777 | }, 778 | { 779 | "name": "m_thirdPersonViewAngles", 780 | "prop": "deadflag", 781 | "offset": 4, 782 | "table": "DT_CSPlayer" 783 | }, 784 | { 785 | "name": "m_clrRender", 786 | "prop": "m_clrRender", 787 | "table": "DT_BaseEntity" 788 | }, 789 | { 790 | "name": "m_bBombTicking", 791 | "prop": "m_bBombTicking", 792 | "table": "DT_PlantedC4" 793 | }, 794 | { 795 | "name": "m_bBombDefused", 796 | "prop": "m_bBombDefused", 797 | "table": "DT_PlantedC4" 798 | }, 799 | { 800 | "name": "m_flC4Blow", 801 | "prop": "m_flC4Blow", 802 | "table": "DT_PlantedC4" 803 | }, 804 | { 805 | "name": "m_hBombDefuser", 806 | "prop": "m_hBombDefuser", 807 | "table": "DT_PlantedC4" 808 | }, 809 | { 810 | "name": "m_flTimerLength", 811 | "prop": "m_flTimerLength", 812 | "table": "DT_PlantedC4" 813 | }, 814 | { 815 | "name": "m_flDefuseLength", 816 | "prop": "m_flDefuseLength", 817 | "table": "DT_PlantedC4" 818 | }, 819 | { 820 | "name": "m_flDefuseCountDown", 821 | "prop": "m_flDefuseCountDown", 822 | "table": "DT_PlantedC4" 823 | }, 824 | { 825 | "name": "m_nBombSite", 826 | "prop": "m_nBombSite", 827 | "table": "DT_PlantedC4" 828 | }, 829 | { 830 | "name": "cs_gamerules_data", 831 | "prop": "cs_gamerules_data", 832 | "table": "DT_CSGameRulesProxy" 833 | }, 834 | { 835 | "name": "m_SurvivalRules", 836 | "prop": "m_SurvivalRules", 837 | "table": "DT_CSGameRulesProxy" 838 | }, 839 | { 840 | "name": "m_SurvivalGameRuleDecisionTypes", 841 | "prop": "m_SurvivalGameRuleDecisionTypes", 842 | "table": "DT_CSGameRulesProxy" 843 | }, 844 | { 845 | "name": "m_bIsValveDS", 846 | "prop": "m_bIsValveDS", 847 | "table": "DT_CSGameRulesProxy" 848 | }, 849 | { 850 | "name": "m_bFreezePeriod", 851 | "prop": "m_bFreezePeriod", 852 | "table": "DT_CSGameRulesProxy" 853 | }, 854 | { 855 | "name": "m_bBombPlanted", 856 | "prop": "m_bBombPlanted", 857 | "table": "DT_CSGameRulesProxy" 858 | }, 859 | { 860 | "name": "m_bIsQueuedMatchmaking", 861 | "prop": "m_bIsQueuedMatchmaking", 862 | "table": "DT_CSGameRulesProxy" 863 | }, 864 | { 865 | "name": "m_flSimulationTime", 866 | "prop": "m_flSimulationTime", 867 | "table": "DT_CSPlayer" 868 | }, 869 | { 870 | "name": "m_flLowerBodyYawTarget", 871 | "prop": "m_flLowerBodyYawTarget", 872 | "table": "DT_CSPlayer" 873 | }, 874 | { 875 | "name": "m_angEyeAnglesX", 876 | "prop": "m_angEyeAngles[0]", 877 | "table": "DT_CSPlayer" 878 | }, 879 | { 880 | "name": "m_angEyeAnglesY", 881 | "prop": "m_angEyeAngles[1]", 882 | "table": "DT_CSPlayer" 883 | }, 884 | { 885 | "name": "m_flNextAttack", 886 | "prop": "m_flNextAttack", 887 | "table": "DT_CSPlayer" 888 | }, 889 | { 890 | "name": "m_iMostRecentModelBoneCounter", 891 | "prop": "m_nForceBone", 892 | "offset": 4, 893 | "table": "DT_CSPlayer" 894 | }, 895 | { 896 | "name": "m_flLastBoneSetupTime", 897 | "prop": "m_nSequence", 898 | "offset": 104, 899 | "table": "DT_BaseAnimating" 900 | }, 901 | { 902 | "name": "m_bStartedArming", 903 | "prop": "m_bStartedArming", 904 | "table": "DT_WeaponC4" 905 | }, 906 | { 907 | "name": "m_bUseCustomBloomScale", 908 | "prop": "m_bUseCustomBloomScale", 909 | "table": "DT_EnvTonemapController" 910 | }, 911 | { 912 | "name": "m_bUseCustomAutoExposureMin", 913 | "prop": "m_bUseCustomAutoExposureMin", 914 | "table": "DT_EnvTonemapController" 915 | }, 916 | { 917 | "name": "m_bUseCustomAutoExposureMax", 918 | "prop": "m_bUseCustomAutoExposureMax", 919 | "table": "DT_EnvTonemapController" 920 | }, 921 | { 922 | "name": "m_flCustomBloomScale", 923 | "prop": "m_flCustomBloomScale", 924 | "table": "DT_EnvTonemapController" 925 | }, 926 | { 927 | "name": "m_flCustomAutoExposureMin", 928 | "prop": "m_flCustomAutoExposureMin", 929 | "table": "DT_EnvTonemapController" 930 | }, 931 | { 932 | "name": "m_flCustomAutoExposureMax", 933 | "prop": "m_flCustomAutoExposureMax", 934 | "table": "DT_EnvTonemapController" 935 | }, 936 | { 937 | "name": "m_nViewModelIndex", 938 | "prop": "m_nViewModelIndex", 939 | "table": "DT_BaseViewModel" 940 | }, 941 | { 942 | "name": "m_nModelIndex", 943 | "prop": "m_nModelIndex", 944 | "table": "DT_BaseViewModel" 945 | } 946 | ] 947 | } 948 | -------------------------------------------------------------------------------- /src/dumper-lib/GHDumper.cpp: -------------------------------------------------------------------------------- 1 | #include "include/GHDumper.h" 2 | #include 3 | #include 4 | #include "base64.hpp" 5 | #include 6 | 7 | namespace gh 8 | { 9 | namespace internal 10 | { 11 | BOOL GetProcessByName(const wchar_t* processName, PROCESSENTRY32W* out) 12 | { 13 | out->dwSize = sizeof(PROCESSENTRY32W); 14 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 15 | if (hSnap != INVALID_HANDLE_VALUE) 16 | if (Process32FirstW(hSnap, out)) 17 | do 18 | if (!_wcsicmp(out->szExeFile, processName)) 19 | return CloseHandle(hSnap); 20 | while (Process32NextW(hSnap, out)); 21 | CloseHandle(hSnap); 22 | return FALSE; 23 | } 24 | 25 | BOOL GetModuleByName(DWORD pid, const wchar_t* moduleName, MODULEENTRY32W* out) 26 | { 27 | out->dwSize = sizeof(MODULEENTRY32W); 28 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); 29 | if (hSnap != INVALID_HANDLE_VALUE) 30 | if (Module32FirstW(hSnap, out)) 31 | do 32 | if (!_wcsicmp(out->szModule, moduleName)) 33 | return CloseHandle(hSnap); 34 | while (Module32NextW(hSnap, out)); 35 | CloseHandle(hSnap); 36 | return FALSE; 37 | } 38 | 39 | void SplitComboPattern(const char* combo, std::string& pattern, std::string& mask) 40 | { 41 | uint8_t byte; 42 | auto ishex = [] (const char c) -> bool { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); }; 43 | auto hexchartoint = [] (const char c) -> uint8_t { return (c >= 'A') ? (c - 'A' + 10) : (c - '0'); }; 44 | 45 | for (; *combo; combo++) 46 | { 47 | if (ishex(*combo)) 48 | { 49 | if (ishex(combo[1])) 50 | byte = hexchartoint(*combo) | (hexchartoint(*(combo++)) << 4); 51 | else 52 | byte = hexchartoint(*combo); 53 | pattern += byte; 54 | mask += 'x'; 55 | } 56 | else if (*combo == '?') 57 | { 58 | pattern += '\x00'; 59 | mask += '?'; 60 | if (combo[1] == '?') 61 | combo++; 62 | } 63 | } 64 | } 65 | 66 | // https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/ 67 | char* ScanBasic(const char* pattern, const char* mask, char* begin, intptr_t size) 68 | { 69 | intptr_t patternLen = strlen(mask); 70 | 71 | for (int i = 0; i < size; i++) 72 | { 73 | bool found = true; 74 | for (int j = 0; j < patternLen; j++) 75 | { 76 | if (mask[j] != '?' && pattern[j] != *(char*)((intptr_t)begin + i + j)) 77 | { 78 | found = false; 79 | break; 80 | } 81 | } 82 | if (found) 83 | { 84 | return (begin + i); 85 | } 86 | } 87 | 88 | return nullptr; 89 | } 90 | 91 | // https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/ 92 | char* ScanEx(const char* pattern, const char* mask, char* begin, intptr_t size, HANDLE hProc) 93 | { 94 | char* match { nullptr }; 95 | SIZE_T bytesRead; 96 | DWORD oldprotect; 97 | char* buffer { nullptr }; 98 | MEMORY_BASIC_INFORMATION mbi; 99 | mbi.RegionSize = 0x1000; 100 | 101 | VirtualQueryEx(hProc, (LPCVOID)begin, &mbi, sizeof(mbi)); 102 | 103 | for (char* curr = begin; curr < begin + size; curr += mbi.RegionSize) 104 | { 105 | if (!VirtualQueryEx(hProc, curr, &mbi, sizeof(mbi))) continue; 106 | if (mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS) continue; 107 | 108 | delete[] buffer; 109 | buffer = new char[mbi.RegionSize]; 110 | 111 | if (VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldprotect)) 112 | { 113 | ReadProcessMemory(hProc, mbi.BaseAddress, buffer, mbi.RegionSize, &bytesRead); 114 | VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, oldprotect, &oldprotect); 115 | 116 | char* internalAddr = ScanBasic(pattern, mask, buffer, (intptr_t)bytesRead); 117 | 118 | if (internalAddr != nullptr) 119 | { 120 | //calculate from internal to external 121 | match = curr + (internalAddr - buffer); 122 | break; 123 | } 124 | } 125 | } 126 | delete[] buffer; 127 | return match; 128 | } 129 | 130 | intptr_t FindNetvarInRecvTable(RecvTable* table, const char* netvarName) 131 | { 132 | for (int i = 0; i < table->m_nProps; i++) 133 | { 134 | RecvProp* prop = table->m_pProps + i; 135 | 136 | if (!_stricmp(prop->m_pVarName, netvarName)) 137 | return prop->m_Offset; 138 | 139 | if (prop->m_pDataTable) 140 | { 141 | intptr_t offset = FindNetvarInRecvTable(prop->m_pDataTable, netvarName); 142 | 143 | if (offset) 144 | return offset + prop->m_Offset; 145 | } 146 | } 147 | return 0; 148 | } 149 | 150 | intptr_t FindNetvar(const char* tableName, const char* netvarName, ClientClass* firstClientClass) 151 | { 152 | for (auto node = firstClientClass; node; node = node->m_pNext) 153 | if (!_stricmp(tableName, node->m_pRecvTable->m_pNetTableName)) 154 | return FindNetvarInRecvTable(node->m_pRecvTable, netvarName); 155 | return 0; 156 | } 157 | 158 | std::string FormatNowUTC() 159 | { 160 | time_t t = time(0); 161 | struct tm tm_info; 162 | gmtime_s(&tm_info, &t); 163 | 164 | std::stringstream ss; 165 | ss << std::put_time(&tm_info, "%Y-%m-%d %H:%M:%S UTC"); 166 | return ss.str(); 167 | } 168 | 169 | nlohmann::json FindSignatureJSON(nlohmann::json& config, std::string signatureName) 170 | { 171 | for (auto& e : config["signatures"]) 172 | if (std::string(e["name"]) == signatureName) 173 | return e; 174 | } 175 | 176 | nlohmann::json FindNetvarJSON(nlohmann::json& config, std::string netvarName) 177 | { 178 | for (auto& e : config["netvars"]) 179 | if (std::string(e["name"]) == netvarName) 180 | return e; 181 | } 182 | } // internal namespace 183 | 184 | Dump DumpSignatures(nlohmann::json& config, FileScanner& scanner) 185 | { 186 | Dump signatures; 187 | 188 | // Use "executable" string in config JSON to get process handle and PID 189 | PROCESSENTRY32W process; 190 | if (!scanner.Valid()) 191 | { 192 | std::string exe = config["executable"]; 193 | std::wstring wexe(exe.begin(), exe.end()); 194 | if (!internal::GetProcessByName(wexe.c_str(), &process)) 195 | return {}; 196 | } 197 | 198 | DWORD pid = process.th32ProcessID; 199 | HANDLE hProcess = INVALID_HANDLE_VALUE; 200 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 201 | SetConsoleTextAttribute(hConsole, 15); 202 | 203 | if (!scanner.Valid()) 204 | { 205 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 206 | } 207 | 208 | for (auto& signature : config["signatures"]) 209 | { 210 | // make sure required JSON keys are present 211 | if (!(signature.contains("name") && signature.contains("pattern"))) 212 | continue; 213 | 214 | if (!signature.contains("module")) 215 | { 216 | if (scanner.Valid()) 217 | { 218 | // default to the main exe 219 | signature["module"] = scanner.getMainFileName(); 220 | } 221 | else 222 | { 223 | signature["module"] = config["executable"]; 224 | } 225 | } 226 | 227 | // get module where the signature is 228 | MODULEENTRY32W module; 229 | std::string moduleName = signature["module"]; 230 | std::wstring wmoduleName(moduleName.begin(), moduleName.end()); 231 | if (!scanner.Valid()) 232 | { 233 | if (!internal::GetModuleByName(pid, wmoduleName.c_str(), &module)) 234 | return {}; 235 | } 236 | 237 | // do pattern scanning 238 | std::string comboPattern = signature["pattern"]; 239 | std::string pattern, mask; 240 | internal::SplitComboPattern(comboPattern.c_str(), pattern, mask); 241 | size_t result {}; 242 | 243 | if (!scanner.Valid()) 244 | { 245 | result = (size_t)internal::ScanEx(pattern.c_str(), mask.c_str(), (char*)module.modBaseAddr, module.modBaseSize, hProcess); 246 | } 247 | else 248 | { 249 | module.modBaseAddr = (BYTE*)scanner.getFileByName(moduleName).getBytes(); 250 | module.modBaseSize = scanner.getFileByName(moduleName).getSize(); 251 | 252 | // default to executable module 253 | if (module.modBaseAddr == nullptr) 254 | { 255 | module.modBaseAddr = (BYTE*)scanner.getMainFile().getBytes(); 256 | module.modBaseSize = scanner.getMainFile().getSize(); 257 | } 258 | result = (size_t)internal::ScanBasic(pattern.c_str(), mask.c_str(), (char*)module.modBaseAddr, module.modBaseSize); 259 | } 260 | 261 | std::string pattern_name = signature["name"]; 262 | if (result) 263 | { 264 | SetConsoleTextAttribute(hConsole, 10); 265 | printf("[+] Found pattern %s at %p\n", pattern_name.c_str(), result); 266 | 267 | if (signature.contains("rva")) 268 | { 269 | SetConsoleTextAttribute(hConsole, 13); 270 | printf("\t[?] Processing Relative Branch\n"); 271 | bool is_call = signature["rva"]; 272 | if (is_call) 273 | { 274 | int opcode = signature.contains("opLoc") ? signature["opLoc"] : 1; 275 | int oplength = signature.contains("opLength") ? signature["opLength"] : 5; 276 | 277 | // resolve the call (if we are reading from disk) 278 | if (scanner.Valid()) 279 | { 280 | int32_t rva = *(int32_t*)(result + opcode); 281 | size_t jmp_location = rva + result + oplength; 282 | result = jmp_location; 283 | } 284 | else 285 | { 286 | // we need to read it from the process externally otherwise 287 | int32_t rva {}; 288 | ReadProcessMemory(hProcess, (LPCVOID)(result + opcode), &rva, sizeof(rva), nullptr); 289 | size_t jmp_location = rva + result + oplength; 290 | result = jmp_location; 291 | } 292 | 293 | SetConsoleTextAttribute(hConsole, 14); 294 | printf("\t[+] Resolved call location: %p\n", result); 295 | 296 | } 297 | } 298 | } 299 | else 300 | { 301 | SetConsoleTextAttribute(hConsole, 12); 302 | printf("\t[!] Failed to find pattern %s (%s)!\n", pattern_name.c_str(), comboPattern.c_str()); 303 | } 304 | 305 | 306 | if (!result) 307 | { 308 | continue; 309 | } 310 | 311 | // read multi-level pointer (if present) 312 | // first offset is relative to pattern location, different than FindDMAAddy, you must add offset first, then RPM 313 | if (signature.contains("offsets")) 314 | for (auto offset : signature["offsets"]) 315 | { 316 | result += offset; 317 | if (!scanner.Valid()) 318 | { 319 | ReadProcessMemory(hProcess, (BYTE*)result, &result, sizeof(size_t), NULL); 320 | } 321 | else 322 | { 323 | result = *(intptr_t*)result; 324 | } 325 | } 326 | 327 | // add "extra" JSON value to result 328 | if (signature.contains("extra")) 329 | { 330 | int extra = signature["extra"]; 331 | if (extra) 332 | result += extra; 333 | } 334 | 335 | if (signature.contains("relative")) 336 | { 337 | bool relative = signature["relative"]; 338 | if (relative) 339 | result -= (ptrdiff_t)module.modBaseAddr; 340 | } 341 | else 342 | { 343 | if (config.contains("relativeByDefault")) 344 | { 345 | bool relativeByDefault = config["relativeByDefault"]; 346 | if (relativeByDefault) 347 | { 348 | // default to relative address 349 | result -= (ptrdiff_t)module.modBaseAddr; 350 | } 351 | } 352 | 353 | } 354 | 355 | 356 | // store result in "signatures" map 357 | signatures[signature["name"]] = result; 358 | } 359 | 360 | CloseHandle(hProcess); 361 | return signatures; 362 | } 363 | 364 | Dump DumpNetvars(nlohmann::json& config, const Dump& signatures) 365 | { 366 | Dump netvars; 367 | 368 | if (!config.contains("netvars")) 369 | return {}; 370 | 371 | // Use "executable" string in config JSON to get PID 372 | std::string exe = config["executable"]; 373 | std::wstring wexe(exe.begin(), exe.end()); 374 | PROCESSENTRY32W process; 375 | if (!internal::GetProcessByName(wexe.c_str(), &process)) 376 | return {}; 377 | DWORD pid = process.th32ProcessID; 378 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 379 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 380 | SetConsoleTextAttribute(hConsole, 15); 381 | 382 | // return if dumper's architecture does match game's architecture 383 | BOOL wow64; 384 | #ifdef _WIN64 // dumper is 64-bit 385 | IsWow64Process(hProcess, &wow64); 386 | if (wow64) // game is 32-bit on 64-bit OS 387 | return {}; 388 | #else // dumper is 32-bit 389 | IsWow64Process(hProcess, &wow64); 390 | if (!wow64) // game is 32-bit on 32-bit OS or game is 64-bit on 64-bit OS 391 | { 392 | SYSTEM_INFO systemInfo { 0 }; 393 | GetNativeSystemInfo(&systemInfo); 394 | if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) // game is 64-bit on 64-bit OS 395 | return {}; 396 | } 397 | #endif // _WIN64 398 | 399 | // Find client.dll 400 | MODULEENTRY32W client_dll; 401 | if (!internal::GetModuleByName(pid, L"client.dll", &client_dll)) 402 | return {}; 403 | 404 | // Add directory path of client.dll's dependencies, otherwise client.dll won't load 405 | std::filesystem::path path(client_dll.szExePath); 406 | path = path.parent_path().parent_path().parent_path() / "bin"; // is this CS:GO specific? 407 | AddDllDirectory(path.wstring().c_str()); 408 | 409 | // Load client.dll into the dumper process 410 | auto current_addy = LoadLibraryExW(client_dll.szExePath, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); 411 | if (!current_addy) 412 | return {}; 413 | 414 | // Get first ClientClass in the linked list 415 | ClientClass* firstClientClass = (ClientClass*)((size_t)current_addy + signatures.at("dwGetAllClasses")); 416 | 417 | for (auto& netvar : config["netvars"]) 418 | { 419 | // make sure required JSON keys are present 420 | if (!(netvar.contains("name") && netvar.contains("table") && netvar.contains("prop"))) 421 | continue; 422 | 423 | std::string table = netvar["table"]; 424 | std::string prop = netvar["prop"]; 425 | auto result = internal::FindNetvar(table.c_str(), prop.c_str(), firstClientClass); 426 | 427 | // add "offset" (if any) 428 | if (netvar.contains("offset")) 429 | { 430 | int offset = netvar["offset"]; 431 | if (offset) 432 | result += offset; 433 | } 434 | 435 | SetConsoleTextAttribute(hConsole, 11); 436 | printf("[=] Found Netvar %s at %p\n", netvar["name"].get().c_str(), result); 437 | netvars[netvar["name"]] = result; 438 | } 439 | 440 | CloseHandle(hProcess); 441 | return netvars; 442 | } 443 | 444 | std::string FormatHeader(nlohmann::json& config, const Dump& signatures, FileScanner& scanner, const Dump& netvars) 445 | { 446 | std::stringstream hpp; 447 | 448 | hpp << "// Generated by GuidedHacking.com's Offset Dumper at " << internal::FormatNowUTC() << "\n"; 449 | hpp << "#pragma once\n"; 450 | hpp << "#include \n"; 451 | hpp << "#include \n"; // vscode error 452 | hpp << "\n"; 453 | 454 | hpp << "namespace ghdumper\n{\n"; 455 | hpp << "\tconstexpr std::int64_t timestamp = " << std::time(0) << ";\n"; 456 | 457 | hpp << "\tnamespace signatures\n\t{\n"; 458 | for (auto e : signatures) 459 | { 460 | hpp << "\t\tconstexpr std::ptrdiff_t " << e.first << " = 0x" << std::uppercase << std::hex << e.second << ";"; 461 | 462 | // only add module comment if the signature is an offset relative to a module base address 463 | // the comment shows how to use the offset: + 464 | const auto sig_json = internal::FindSignatureJSON(config, e.first); 465 | bool relative = true; 466 | 467 | if (sig_json.contains("relative")) 468 | { 469 | relative = sig_json["relative"]; 470 | } 471 | else 472 | { 473 | if (config.contains("relativeByDefault")) 474 | { 475 | relative = config["relativeByDefault"]; 476 | } 477 | } 478 | 479 | std::string module_name = config["executable"]; 480 | if (sig_json.contains("module")) 481 | { 482 | module_name = sig_json["module"]; 483 | } 484 | 485 | // get the original exe name 486 | if (module_name == scanner.getMainFileName()) 487 | { 488 | module_name = config["executable"]; 489 | } 490 | 491 | if (module_name.find_last_of(".") == std::string::npos) 492 | { 493 | module_name += scanner.getFileByName(module_name).getExt(); 494 | } 495 | 496 | 497 | hpp << " // " << module_name << "+0x" << e.second; 498 | hpp << "\n"; 499 | } 500 | hpp << "\t} // namespace signatures\n"; 501 | 502 | hpp << "\tnamespace netvars\n\t{\n"; 503 | for (auto e : netvars) 504 | hpp << "\t\tconstexpr ::std::ptrdiff_t " << e.first << " = 0x" << std::uppercase << std::hex << e.second << "; // " << std::string(internal::FindNetvarJSON(config, e.first)["table"]) << "\n"; 505 | hpp << "\t} // namespace netvars\n"; 506 | 507 | hpp << "} // namespace ghdumper\n"; 508 | 509 | return hpp.str(); 510 | } 511 | 512 | std::string FormatCheatEngine(nlohmann::json& config, const Dump& signatures, FileScanner& scanner, const Dump& netvars) 513 | { 514 | /* Cheat engine table structure 515 | Generated by GuidedHacking.com's Offset Dumper at 516 | dwGameDir 517 | Local Player 518 | DT_BasePlayer 519 | m_iHealth 520 | ... 521 | DT_CSPlayer 522 | ... 523 | DT_BaseEntity 524 | ... 525 | DT_BaseAnimating 526 | ... 527 | Entity 0 528 | DT_BasePlayer 529 | m_iHealth 530 | ... 531 | DT_CSPlayer 532 | ... 533 | DT_BaseEntity 534 | ... 535 | DT_BaseAnimating 536 | ... 537 | Entity 1 538 | ... 539 | ... 540 | Entity 31 541 | ... 542 | Raw Data (prettified .hpp) 543 | Signatures (relative to module) 544 | 545 | ... 546 | Signatures (not relative to module) 547 | 548 | ... 549 | Netvars 550 | Table X 551 | 552 | ... 553 | Table Y 554 | 555 | ... 556 | ... 557 | */ 558 | 559 | std::stringstream ct, rel, nrel, rawNetvars, rawData; 560 | 561 | std::string nowUTC = internal::FormatNowUTC(); 562 | 563 | ct << "\n"; 564 | ct << "\n"; 565 | ct << "\n"; 566 | 567 | size_t id = 0; 568 | 569 | // A cheat entry is a row in the Cheat Engine table of addresses 570 | auto FormatCheatEntry = [&](const std::string& description, const std::string& childrenXML = {}, bool collapsible = true, bool hideChildren = false, const std::string& address = {}, const std::string& valueType = {}, int showAsHex = 1, int length = 0) 571 | { 572 | std::stringstream tmp; 573 | tmp << "\n"; 574 | tmp << "" << std::dec << id++ << "\n"; 575 | tmp << "\"" << description << "\"\n"; 576 | 577 | if (address.empty()) 578 | tmp << "1\n"; // makes Type and Value columns not appear 579 | else 580 | { 581 | tmp << "
" << address << "
\n"; 582 | tmp << "" << valueType << "\n"; 583 | if (valueType == "String") 584 | tmp << "" << length << "\n"; 585 | tmp << "" << showAsHex << "\n"; 586 | } 587 | 588 | if (!childrenXML.empty()) 589 | tmp << "\n" << childrenXML << "\n"; // child entries 590 | 591 | if (hideChildren || collapsible) 592 | { 593 | tmp << "\n"; 599 | } 600 | 601 | tmp << "
\n"; 602 | return tmp.str(); 603 | }; 604 | 605 | auto FormatPlayer = [&] (const std::string& base) 606 | { 607 | std::stringstream tmp; 608 | auto playerTables = { "DT_BasePlayer", "DT_CSPlayer", "DT_BaseEntity", "DT_BaseAnimating" }; 609 | 610 | for (auto& playerTable : playerTables) 611 | { 612 | std::stringstream entries; 613 | 614 | for (auto& netvar : config["netvars"]) 615 | { 616 | if (std::string(netvar["table"]) == playerTable) 617 | { 618 | std::string name = netvar["name"]; 619 | std::stringstream address; 620 | int length = 0; 621 | address << base << "+" << name; 622 | 623 | std::string valueType = "4 Bytes"; 624 | int showAsHex = 1; 625 | if (name.find("m_i") == 0 || name.find("m_n") == 0) // integer 626 | showAsHex = 0; 627 | else if (name.find("m_b") == 0) // boolean 628 | { 629 | showAsHex = 0; 630 | valueType = "Byte"; 631 | } 632 | else if (name.find("m_fl") == 0 || name.find("m_ang") == 0) // float 633 | { 634 | showAsHex = 0; 635 | valueType = "Float"; 636 | } 637 | else if (name.find("m_sz") == 0) // string 638 | { 639 | showAsHex = 0; 640 | valueType = "String"; 641 | length = 100; 642 | } 643 | 644 | if (name.find("m_vec") == 0) // vector of 3 floats 645 | { 646 | std::stringstream floats; 647 | floats << FormatCheatEntry("x", {}, {}, {}, address.str() + "+0", "Float", 0); 648 | floats << FormatCheatEntry("y", {}, {}, {}, address.str() + "+4", "Float", 0); 649 | floats << FormatCheatEntry("z", {}, {}, {}, address.str() + "+8", "Float", 0); 650 | entries << FormatCheatEntry(name, floats.str(), true, false, address.str(), valueType, showAsHex, length); 651 | } 652 | else 653 | entries << FormatCheatEntry(name, {}, {}, {}, address.str(), valueType, showAsHex, length); 654 | } 655 | } 656 | 657 | if (entries.str().size() > 0) 658 | tmp << FormatCheatEntry(playerTable, entries.str()); 659 | } 660 | 661 | return tmp.str(); 662 | }; 663 | 664 | ct << "\n"; 665 | 666 | // Add green GH banner with timestamp at the top 667 | ct << "\n"; 668 | ct << "0\n"; 669 | ct << "\"Generated by GuidedHacking.com's Offset Dumper at " << nowUTC << "\"\n"; 670 | ct << "1\n"; 671 | ct << "0EF7C1\n"; 672 | ct << "\n"; 673 | id += 1; 674 | 675 | // Add game directory entry 676 | if (signatures.count("dwGameDir")) 677 | for (auto& e : config["signatures"]) 678 | if (std::string(e["name"]) == "dwGameDir") 679 | ct << FormatCheatEntry("dwGameDir", {}, {}, {}, std::string(e["module"]) + "+dwGameDir", "String", 0, 256); 680 | 681 | // Add local player and entity list 682 | if (config.contains("netvars") && config["netvars"].size() > 0) 683 | { 684 | if (signatures.count("dwLocalPlayer")) 685 | ct << FormatCheatEntry("Local Player", FormatPlayer("[client.dll+dwLocalPlayer]"), true, false, "client.dll+dwLocalPlayer", "4 Bytes", 1); 686 | 687 | if (signatures.count("dwEntityList")) 688 | for (int i = 0; i < 32; i++) 689 | { 690 | std::stringstream base; 691 | base << "[client.dll+dwEntityList+" << std::hex << i * 0x10 << "]"; 692 | 693 | std::stringstream groupName; 694 | groupName << "Entity " << std::dec << i; 695 | 696 | std::stringstream address; 697 | address << "client.dll+dwEntityList+" << std::hex << i * 0x10; 698 | 699 | ct << FormatCheatEntry(groupName.str(), FormatPlayer(base.str()), true, true, address.str(), "4 Bytes", 1); 700 | } 701 | } 702 | 703 | // format signatures 704 | for (auto e : signatures) 705 | { 706 | auto signature = internal::FindSignatureJSON(config, e.first); 707 | bool relative = true; // default to true 708 | if (signature.contains("relative")) 709 | { 710 | relative = signature["relative"]; 711 | } 712 | else 713 | { 714 | if (config.contains("relativeByDefault")) 715 | { 716 | relative = config["relativeByDefault"]; 717 | } 718 | } 719 | 720 | std::string module_name = scanner.getMainFileName(); 721 | if (signature.contains("module")) 722 | { 723 | module_name = signature["module"].get(); 724 | } 725 | 726 | std::stringstream address; 727 | if (relative) 728 | address << module_name << "+"; 729 | address << std::uppercase << std::hex << "0x" << e.second; 730 | 731 | auto entry = FormatCheatEntry(e.first, {}, {}, {}, address.str(), "4 Bytes", 1); 732 | 733 | if (relative) 734 | rel << entry; 735 | else 736 | nrel << entry; 737 | } 738 | 739 | // format netvars 740 | std::set netvarTables; 741 | for (auto& netvar : config["netvars"]) 742 | netvarTables.insert(netvar["table"]); 743 | for (auto& table : netvarTables) 744 | { 745 | std::stringstream tmp; 746 | 747 | for (auto& netvar : config["netvars"]) 748 | if (std::string(netvar["table"]) == table) 749 | { 750 | std::string netvarName = netvar["name"]; 751 | if (!netvars.count(netvarName)) // not present 752 | continue; 753 | std::stringstream address; 754 | address << std::uppercase << std::hex << "0x" << netvars.at(netvarName); 755 | tmp << FormatCheatEntry(std::string(netvar["name"]), {}, {}, {}, address.str(), "4 Bytes", 1); 756 | } 757 | 758 | rawNetvars << FormatCheatEntry(table, tmp.str()); 759 | } 760 | 761 | // add signatures and netvars 762 | rawData << FormatCheatEntry("Signatures (relative to module base)", rel.str()); 763 | rawData << FormatCheatEntry("Signatures (not relative to module base)", nrel.str()); 764 | rawData << FormatCheatEntry("Netvars", rawNetvars.str()); 765 | ct << FormatCheatEntry("Raw Data (prettified .hpp)", rawData.str()); 766 | 767 | ct << "\n"; 768 | 769 | // Add all offsets as user defined symbols, these are aliases for addresses you can use throughout your table 770 | 771 | ct << "\n"; 772 | 773 | for (auto e : signatures) 774 | ct << "\n" 775 | << "" << e.first << "\n" 776 | << "
" << std::hex << "0x" << e.second << "
\n" 777 | << "
\n"; 778 | 779 | for (auto e : netvars) 780 | ct << "\n" 781 | << "" << e.first << "\n" 782 | << "
" << std::hex << "0x" << e.second << "
\n" 783 | << "
\n"; 784 | 785 | ct << "
"; 786 | 787 | ct << "
\n"; 788 | 789 | return ct.str(); 790 | } 791 | 792 | std::string FormatReclass(nlohmann::json& config, FileScanner& scanner, const Dump& netvars) 793 | { 794 | std::stringstream xml; 795 | 796 | xml << "\n"; 797 | xml << "\n"; 798 | 799 | xml << "\n"; 800 | xml << "\n"; 801 | xml << "\n"; 802 | xml << "bool\n"; 803 | xml << "int8_t\n"; 804 | xml << "int16_t\n"; 805 | xml << "int32_t\n"; 806 | xml << "int64_t\n"; 807 | xml << "ptrdiff_t\n"; 808 | xml << "uint8_t\n"; 809 | xml << "uint16_t\n"; 810 | xml << "uint32_t\n"; 811 | xml << "uint64_t\n"; 812 | xml << "size_t\n"; 813 | xml << "float\n"; 814 | xml << "double\n"; 815 | xml << "Vector2\n"; 816 | xml << "Vector3\n"; 817 | xml << "Vector4\n"; 818 | xml << "Matrix3x3\n"; 819 | xml << "Matrix3x4\n"; 820 | xml << "Matrix4x4\n"; 821 | xml << "char\n"; 822 | xml << "wchar_t\n"; 823 | xml << "char32_t\n"; 824 | xml << "void*\n"; 825 | xml << "\n"; 826 | xml << "\n"; 827 | 828 | xml << "\n"; 829 | 830 | auto generateUUIDv4 = [] () 831 | { 832 | std::random_device rd; 833 | std::stringstream ss; 834 | ss << std::hex << std::setfill('0'); 835 | ss << std::setw(8) << rd(); 836 | ss << "-"; 837 | ss << std::setw(4) << (rd() & 0xffff); 838 | ss << "-"; 839 | ss << std::setw(0) << "4" << std::setw(3) << (rd() & 0xfff); 840 | ss << "-"; 841 | ss << std::setw(0) << "9" << std::setw(3) << (rd() & 0xfff); 842 | ss << "-"; 843 | ss << std::setw(8) << rd() << std::setw(4) << (rd() & 0xffff); 844 | 845 | // new versions of reclass expect base64 encoded uuids 846 | return base64::to_base64(ss.str()); 847 | }; 848 | 849 | size_t paddingID = 0; 850 | 851 | std::set netvarTables; 852 | for (auto& netvar : config["netvars"]) 853 | netvarTables.insert(netvar["table"]); 854 | 855 | for (auto& table : netvarTables) 856 | { 857 | std::vector> tableNetvars; 858 | 859 | xml << "\n"; 860 | 861 | for (auto& netvar : config["netvars"]) 862 | if (std::string(netvar["table"]) == table) 863 | { 864 | std::string netvarName = netvar["name"]; 865 | if (!netvars.count(netvarName)) // not present 866 | continue; 867 | tableNetvars.push_back({ netvarName, netvars.at(netvarName) }); 868 | } 869 | 870 | std::sort(tableNetvars.begin(), tableNetvars.end(), 871 | [] (const std::pair& a, const std::pair& b) 872 | { 873 | return a.second < b.second; 874 | } 875 | ); 876 | 877 | size_t lastOffset = 0; 878 | size_t lastVarSize = 0; 879 | 880 | for (size_t i = 0; i < tableNetvars.size(); i++) 881 | { 882 | auto& pair = tableNetvars[i]; 883 | size_t paddingSize = pair.second - (lastOffset + lastVarSize); 884 | if (paddingSize > 0) 885 | xml << "\n"; 931 | } 932 | 933 | xml << "\n"; 934 | 935 | xml << "\n"; 936 | 937 | return xml.str(); 938 | } 939 | 940 | FileScanner InitScanner(nlohmann::json& config, bool* runtime) 941 | { 942 | FileScanner scanner {}; 943 | if (config.contains("fileonly") && config.contains("exefile")) 944 | { 945 | DynamicMoudleArray dynamicModules {}; 946 | if (config.contains("additionalModules")) 947 | { 948 | for (auto& mod : config["additionalModules"]) 949 | { 950 | std::string name = mod["name"]; 951 | std::string path = mod["path"]; 952 | 953 | DynamicModule dynamicModule {}; 954 | dynamicModule.compName = name; 955 | dynamicModule.filePath = path; 956 | 957 | dynamicModules.push_back(dynamicModule); 958 | } 959 | } 960 | 961 | scanner = FileScanner(config["exefile"], dynamicModules); 962 | *runtime = false; 963 | } 964 | else 965 | { 966 | // setup scanner for module name 967 | scanner = FileScanner(config["executable"]); 968 | *runtime = true; 969 | } 970 | 971 | return scanner; 972 | } 973 | 974 | bool ParseCommandLine(int argc, const char** argv) 975 | { 976 | // support drag and drop json files 977 | std::string config_file = "config.json"; 978 | if (argc >= 2) 979 | { 980 | config_file = argv[1]; 981 | } 982 | 983 | printf("%s\n", config_file.c_str()); 984 | 985 | bool config_parsed = false; 986 | auto config = parseConfig(config_file, &config_parsed); 987 | 988 | // failed to parse config, invalid json 989 | if (config_parsed == false) 990 | { 991 | printf("[-] Invalid Config File\n"); 992 | return false; 993 | } 994 | 995 | if (!config.contains("executable")) 996 | { 997 | printf("%s\n", config.dump(4).c_str()); 998 | printf("[-] Invalid config, missing executable name\n"); 999 | return false; 1000 | } 1001 | 1002 | const std::string target_game = config["executable"]; 1003 | 1004 | // parse config for on-disk files 1005 | bool runtime_dump = false; 1006 | FileScanner scanner = gh::InitScanner(config, &runtime_dump); 1007 | 1008 | printf("[~] Target: %s\n", target_game.c_str()); 1009 | 1010 | if (runtime_dump) 1011 | { 1012 | printf("[!] Dumping From Runtime\n"); 1013 | 1014 | std::string exe = target_game; 1015 | std::wstring wexe(exe.begin(), exe.end()); 1016 | PROCESSENTRY32W out {}; 1017 | if (!internal::GetProcessByName(wexe.c_str(), &out)) 1018 | { 1019 | printf("[-] Failed to find target process\n"); 1020 | return false; 1021 | } 1022 | } 1023 | else 1024 | { 1025 | printf("[!] Dumping From Disk\n"); 1026 | } 1027 | 1028 | // dump into map 1029 | Dump signatures = gh::DumpSignatures(config, scanner); 1030 | Dump netvars = gh::DumpNetvars(config, signatures); 1031 | 1032 | // format files 1033 | std::string hpp = gh::FormatHeader(config, signatures, scanner, netvars); 1034 | std::string ct = gh::FormatCheatEngine(config, signatures, scanner, netvars); 1035 | std::string xml = gh::FormatReclass(config, scanner, netvars); 1036 | 1037 | // create output directory 1038 | std::string output_dir = config["filename"].get() + "/"; 1039 | std::filesystem::create_directory(output_dir); 1040 | 1041 | // save files 1042 | saveFile(config, hpp, "hpp"); 1043 | saveFile(config, ct, "ct"); 1044 | saveReclassFile(config, xml); 1045 | 1046 | scanner.decon(); 1047 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 1048 | return true; 1049 | } 1050 | } -------------------------------------------------------------------------------- /src/dumper-lib/base64.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_HPP_ 2 | #define BASE64_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(__cpp_lib_bit_cast) 15 | #include // For std::bit_cast. 16 | #endif 17 | 18 | namespace base64 { 19 | 20 | namespace detail { 21 | 22 | #if defined(__cpp_lib_bit_cast) 23 | using std::bit_cast; 24 | #else 25 | template 26 | std::enable_if_t && 28 | std::is_trivially_copyable_v, 29 | To> 30 | bit_cast(const From& src) noexcept { 31 | static_assert(std::is_trivially_constructible_v, 32 | "This implementation additionally requires " 33 | "destination type to be trivially constructible"); 34 | 35 | To dst; 36 | std::memcpy(&dst, &src, sizeof(To)); 37 | return dst; 38 | } 39 | #endif 40 | 41 | inline constexpr char padding_char{'='}; 42 | inline constexpr uint32_t bad_char{0x01FFFFFF}; 43 | 44 | #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) 45 | #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 46 | (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) || \ 47 | (defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN) || \ 48 | (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || \ 49 | (defined(__sun) && defined(__SVR4) && defined(_BIG_ENDIAN)) || \ 50 | defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ 51 | defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) || \ 52 | defined(_M_PPC) 53 | #define __BIG_ENDIAN__ 54 | #elif (defined(__BYTE_ORDER__) && \ 55 | __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || /* gcc */ \ 56 | (defined(__BYTE_ORDER) && \ 57 | __BYTE_ORDER == __LITTLE_ENDIAN) /* linux header */ \ 58 | || (defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN) || \ 59 | (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) /* mingw header */ || \ 60 | (defined(__sun) && defined(__SVR4) && \ 61 | defined(_LITTLE_ENDIAN)) || /* solaris */ \ 62 | defined(__ARMEL__) || \ 63 | defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ 64 | defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_IX86) || \ 65 | defined(_M_X64) || defined(_M_IA64) || /* msvc for intel processors */ \ 66 | defined(_M_ARM) /* msvc code on arm executes in little endian mode */ 67 | #define __LITTLE_ENDIAN__ 68 | #endif 69 | #endif 70 | 71 | #if !defined(__LITTLE_ENDIAN__) & !defined(__BIG_ENDIAN__) 72 | #error "UNKNOWN Platform / endianness. Configure endianness explicitly." 73 | #endif 74 | 75 | #if defined(__LITTLE_ENDIAN__) 76 | std::array constexpr decode_table_0 = { 77 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 78 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 79 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 80 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 81 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 82 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 83 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 84 | 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, 85 | 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 86 | 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, 87 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 88 | 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, 89 | 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, 90 | 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, 91 | 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 92 | 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 93 | 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 94 | 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, 95 | 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, 96 | 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, 97 | 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, 98 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 99 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 100 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 101 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 102 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 103 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 104 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 105 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 106 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 107 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 108 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 109 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 110 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 111 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 112 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 113 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 114 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 115 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 116 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 117 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 118 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 119 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 120 | 121 | std::array constexpr decode_table_1 = { 122 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 123 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 124 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 125 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 126 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 127 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 128 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 129 | 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, 130 | 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 131 | 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, 132 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 133 | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 134 | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 135 | 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, 136 | 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 137 | 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 138 | 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 139 | 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, 140 | 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, 141 | 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, 142 | 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 143 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 144 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 145 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 146 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 147 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 148 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 149 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 150 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 151 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 152 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 153 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 154 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 155 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 156 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 157 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 158 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 159 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 160 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 161 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 162 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 163 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 164 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 165 | 166 | std::array constexpr decode_table_2 = { 167 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 168 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 169 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 170 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 171 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 172 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 173 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 174 | 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, 175 | 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 176 | 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, 177 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 178 | 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, 179 | 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, 180 | 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, 181 | 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 182 | 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 183 | 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 184 | 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, 185 | 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, 186 | 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, 187 | 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 188 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 189 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 190 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 191 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 192 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 193 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 194 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 195 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 196 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 197 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 198 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 199 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 200 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 201 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 202 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 203 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 204 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 205 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 206 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 207 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 208 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 209 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 210 | 211 | std::array constexpr decode_table_3 = { 212 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 213 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 214 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 215 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 216 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 217 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 218 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 219 | 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, 220 | 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 221 | 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, 222 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 223 | 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, 224 | 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, 225 | 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, 226 | 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 227 | 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 228 | 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 229 | 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, 230 | 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, 231 | 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, 232 | 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 233 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 234 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 235 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 236 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 237 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 238 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 239 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 240 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 241 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 242 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 243 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 244 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 245 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 246 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 247 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 248 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 249 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 250 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 251 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 252 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 253 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 254 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 255 | 256 | // TODO fix decoding tables to avoid the need for different indices in big 257 | // endian? 258 | inline constexpr size_t decidx0{0}; 259 | inline constexpr size_t decidx1{1}; 260 | inline constexpr size_t decidx2{2}; 261 | 262 | #elif defined(__BIG_ENDIAN__) 263 | 264 | std::array constexpr decode_table_0 = { 265 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 266 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 267 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 268 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 269 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 270 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 271 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 272 | 0x01ffffff, 0x00f80000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00fc0000, 273 | 0x00d00000, 0x00d40000, 0x00d80000, 0x00dc0000, 0x00e00000, 0x00e40000, 274 | 0x00e80000, 0x00ec0000, 0x00f00000, 0x00f40000, 0x01ffffff, 0x01ffffff, 275 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 276 | 0x00040000, 0x00080000, 0x000c0000, 0x00100000, 0x00140000, 0x00180000, 277 | 0x001c0000, 0x00200000, 0x00240000, 0x00280000, 0x002c0000, 0x00300000, 278 | 0x00340000, 0x00380000, 0x003c0000, 0x00400000, 0x00440000, 0x00480000, 279 | 0x004c0000, 0x00500000, 0x00540000, 0x00580000, 0x005c0000, 0x00600000, 280 | 0x00640000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 281 | 0x01ffffff, 0x00680000, 0x006c0000, 0x00700000, 0x00740000, 0x00780000, 282 | 0x007c0000, 0x00800000, 0x00840000, 0x00880000, 0x008c0000, 0x00900000, 283 | 0x00940000, 0x00980000, 0x009c0000, 0x00a00000, 0x00a40000, 0x00a80000, 284 | 0x00ac0000, 0x00b00000, 0x00b40000, 0x00b80000, 0x00bc0000, 0x00c00000, 285 | 0x00c40000, 0x00c80000, 0x00cc0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 286 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 287 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 288 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 289 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 290 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 291 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 292 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 293 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 294 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 295 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 296 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 297 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 298 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 299 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 300 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 301 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 302 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 303 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 304 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 305 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 306 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 307 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 308 | 309 | std::array constexpr decode_table_1 = { 310 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 311 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 312 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 313 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 314 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 315 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 316 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 317 | 0x01ffffff, 0x0003e000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003f000, 318 | 0x00034000, 0x00035000, 0x00036000, 0x00037000, 0x00038000, 0x00039000, 319 | 0x0003a000, 0x0003b000, 0x0003c000, 0x0003d000, 0x01ffffff, 0x01ffffff, 320 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 321 | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 322 | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 323 | 0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00011000, 0x00012000, 324 | 0x00013000, 0x00014000, 0x00015000, 0x00016000, 0x00017000, 0x00018000, 325 | 0x00019000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 326 | 0x01ffffff, 0x0001a000, 0x0001b000, 0x0001c000, 0x0001d000, 0x0001e000, 327 | 0x0001f000, 0x00020000, 0x00021000, 0x00022000, 0x00023000, 0x00024000, 328 | 0x00025000, 0x00026000, 0x00027000, 0x00028000, 0x00029000, 0x0002a000, 329 | 0x0002b000, 0x0002c000, 0x0002d000, 0x0002e000, 0x0002f000, 0x00030000, 330 | 0x00031000, 0x00032000, 0x00033000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 331 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 332 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 333 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 334 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 335 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 336 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 337 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 338 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 339 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 340 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 341 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 342 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 343 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 344 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 345 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 346 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 347 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 348 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 349 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 350 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 351 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 352 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 353 | 354 | std::array constexpr decode_table_2 = { 355 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 356 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 357 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 358 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 359 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 360 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 361 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 362 | 0x01ffffff, 0x00000f80, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000fc0, 363 | 0x00000d00, 0x00000d40, 0x00000d80, 0x00000dc0, 0x00000e00, 0x00000e40, 364 | 0x00000e80, 0x00000ec0, 0x00000f00, 0x00000f40, 0x01ffffff, 0x01ffffff, 365 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 366 | 0x00000040, 0x00000080, 0x000000c0, 0x00000100, 0x00000140, 0x00000180, 367 | 0x000001c0, 0x00000200, 0x00000240, 0x00000280, 0x000002c0, 0x00000300, 368 | 0x00000340, 0x00000380, 0x000003c0, 0x00000400, 0x00000440, 0x00000480, 369 | 0x000004c0, 0x00000500, 0x00000540, 0x00000580, 0x000005c0, 0x00000600, 370 | 0x00000640, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 371 | 0x01ffffff, 0x00000680, 0x000006c0, 0x00000700, 0x00000740, 0x00000780, 372 | 0x000007c0, 0x00000800, 0x00000840, 0x00000880, 0x000008c0, 0x00000900, 373 | 0x00000940, 0x00000980, 0x000009c0, 0x00000a00, 0x00000a40, 0x00000a80, 374 | 0x00000ac0, 0x00000b00, 0x00000b40, 0x00000b80, 0x00000bc0, 0x00000c00, 375 | 0x00000c40, 0x00000c80, 0x00000cc0, 0x01ffffff, 0x01ffffff, 0x01ffffff, 376 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 377 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 378 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 379 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 380 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 381 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 382 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 383 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 384 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 385 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 386 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 387 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 388 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 389 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 390 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 391 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 392 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 393 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 394 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 395 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 396 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 397 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 398 | 399 | std::array constexpr decode_table_3 = { 400 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 401 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 402 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 403 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 404 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 405 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 406 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 407 | 0x01ffffff, 0x0000003e, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003f, 408 | 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 409 | 0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x01ffffff, 0x01ffffff, 410 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 411 | 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 412 | 0x00000007, 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, 413 | 0x0000000d, 0x0000000e, 0x0000000f, 0x00000010, 0x00000011, 0x00000012, 414 | 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, 415 | 0x00000019, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 416 | 0x01ffffff, 0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d, 0x0000001e, 417 | 0x0000001f, 0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 418 | 0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 419 | 0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030, 420 | 0x00000031, 0x00000032, 0x00000033, 0x01ffffff, 0x01ffffff, 0x01ffffff, 421 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 422 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 423 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 424 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 425 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 426 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 427 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 428 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 429 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 430 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 431 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 432 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 433 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 434 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 435 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 436 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 437 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 438 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 439 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 440 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 441 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 442 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 443 | 444 | // TODO fix decoding tables to avoid the need for different indices in big 445 | // endian? 446 | inline constexpr size_t decidx0{1}; 447 | inline constexpr size_t decidx1{2}; 448 | inline constexpr size_t decidx2{3}; 449 | 450 | #endif 451 | 452 | std::array constexpr encode_table_0 = { 453 | 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 454 | 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', 455 | 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', 456 | 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', 457 | 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R', 'S', 'S', 'S', 458 | 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', 459 | 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', 460 | 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', 461 | 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', 462 | 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', 463 | 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'p', 464 | 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', 465 | 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', 466 | 'w', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', 467 | '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', 468 | '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', 469 | '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', '+', '+', '/', '/', '/', 470 | '/'}; 471 | 472 | std::array constexpr encode_table_1 = { 473 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 474 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 475 | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 476 | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 477 | '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 478 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 479 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 480 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', 481 | '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 482 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 483 | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 484 | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 485 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 486 | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 487 | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 488 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 489 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', 490 | '/'}; 491 | 492 | } // namespace detail 493 | 494 | template 495 | inline OutputBuffer encode_into(InputIterator begin, InputIterator end) { 496 | typedef std::decay_t input_value_type; 497 | static_assert(std::is_same_v || 498 | std::is_same_v || 499 | std::is_same_v || 500 | std::is_same_v); 501 | typedef typename OutputBuffer::value_type output_value_type; 502 | static_assert(std::is_same_v || 503 | std::is_same_v || 504 | std::is_same_v || 505 | std::is_same_v); 506 | const size_t binarytextsize = end - begin; 507 | const size_t encodedsize = (binarytextsize / 3 + (binarytextsize % 3 > 0)) 508 | << 2; 509 | OutputBuffer encoded(encodedsize, detail::padding_char); 510 | 511 | const uint8_t* bytes = reinterpret_cast(&*begin); 512 | char* currEncoding = reinterpret_cast(&encoded[0]); 513 | 514 | for (size_t i = binarytextsize / 3; i; --i) { 515 | const uint8_t t1 = *bytes++; 516 | const uint8_t t2 = *bytes++; 517 | const uint8_t t3 = *bytes++; 518 | *currEncoding++ = detail::encode_table_0[t1]; 519 | *currEncoding++ = 520 | detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 521 | *currEncoding++ = 522 | detail::encode_table_1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; 523 | *currEncoding++ = detail::encode_table_1[t3]; 524 | } 525 | 526 | switch (binarytextsize % 3) { 527 | case 0: { 528 | break; 529 | } 530 | case 1: { 531 | const uint8_t t1 = bytes[0]; 532 | *currEncoding++ = detail::encode_table_0[t1]; 533 | *currEncoding++ = detail::encode_table_1[(t1 & 0x03) << 4]; 534 | // *currEncoding++ = detail::padding_char; 535 | // *currEncoding++ = detail::padding_char; 536 | break; 537 | } 538 | case 2: { 539 | const uint8_t t1 = bytes[0]; 540 | const uint8_t t2 = bytes[1]; 541 | *currEncoding++ = detail::encode_table_0[t1]; 542 | *currEncoding++ = 543 | detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 544 | *currEncoding++ = detail::encode_table_1[(t2 & 0x0F) << 2]; 545 | // *currEncoding++ = detail::padding_char; 546 | break; 547 | } 548 | default: { 549 | throw std::runtime_error{"Invalid base64 encoded data"}; 550 | } 551 | } 552 | 553 | return encoded; 554 | } 555 | 556 | template 557 | inline OutputBuffer encode_into(std::string_view data) { 558 | return encode_into(std::begin(data), std::end(data)); 559 | } 560 | 561 | inline std::string to_base64(std::string_view data) { 562 | return encode_into(std::begin(data), std::end(data)); 563 | } 564 | 565 | template 566 | inline OutputBuffer decode_into(std::string_view base64Text) { 567 | typedef typename OutputBuffer::value_type output_value_type; 568 | static_assert(std::is_same_v || 569 | std::is_same_v || 570 | std::is_same_v || 571 | std::is_same_v); 572 | if (base64Text.empty()) { 573 | return OutputBuffer(); 574 | } 575 | 576 | if ((base64Text.size() & 3) != 0) { 577 | throw std::runtime_error{ 578 | "Invalid base64 encoded data - Size not divisible by 4"}; 579 | } 580 | 581 | const size_t numPadding = 582 | std::count(base64Text.rbegin(), base64Text.rbegin() + 4, '='); 583 | if (numPadding > 2) { 584 | throw std::runtime_error{ 585 | "Invalid base64 encoded data - Found more than 2 padding signs"}; 586 | } 587 | 588 | const size_t decodedsize = (base64Text.size() * 3 >> 2) - numPadding; 589 | OutputBuffer decoded(decodedsize, '.'); 590 | 591 | const uint8_t* bytes = reinterpret_cast(&base64Text[0]); 592 | char* currDecoding = reinterpret_cast(&decoded[0]); 593 | 594 | for (size_t i = (base64Text.size() >> 2) - (numPadding != 0); i; --i) { 595 | const uint8_t t1 = *bytes++; 596 | const uint8_t t2 = *bytes++; 597 | const uint8_t t3 = *bytes++; 598 | const uint8_t t4 = *bytes++; 599 | 600 | const uint32_t d1 = detail::decode_table_0[t1]; 601 | const uint32_t d2 = detail::decode_table_1[t2]; 602 | const uint32_t d3 = detail::decode_table_2[t3]; 603 | const uint32_t d4 = detail::decode_table_3[t4]; 604 | 605 | const uint32_t temp = d1 | d2 | d3 | d4; 606 | 607 | if (temp >= detail::bad_char) { 608 | throw std::runtime_error{ 609 | "Invalid base64 encoded data - Invalid character"}; 610 | } 611 | 612 | // Use bit_cast instead of union and type punning to avoid 613 | // undefined behaviour risk: 614 | // https://en.wikipedia.org/wiki/Type_punning#Use_of_union 615 | const std::array tempBytes = 616 | detail::bit_cast, uint32_t>(temp); 617 | 618 | *currDecoding++ = tempBytes[detail::decidx0]; 619 | *currDecoding++ = tempBytes[detail::decidx1]; 620 | *currDecoding++ = tempBytes[detail::decidx2]; 621 | } 622 | 623 | switch (numPadding) { 624 | case 0: { 625 | break; 626 | } 627 | case 1: { 628 | const uint8_t t1 = *bytes++; 629 | const uint8_t t2 = *bytes++; 630 | const uint8_t t3 = *bytes++; 631 | 632 | const uint32_t d1 = detail::decode_table_0[t1]; 633 | const uint32_t d2 = detail::decode_table_1[t2]; 634 | const uint32_t d3 = detail::decode_table_2[t3]; 635 | 636 | const uint32_t temp = d1 | d2 | d3; 637 | 638 | if (temp >= detail::bad_char) { 639 | throw std::runtime_error{ 640 | "Invalid base64 encoded data - Invalid character"}; 641 | } 642 | 643 | // Use bit_cast instead of union and type punning to avoid 644 | // undefined behaviour risk: 645 | // https://en.wikipedia.org/wiki/Type_punning#Use_of_union 646 | const std::array tempBytes = 647 | detail::bit_cast, uint32_t>(temp); 648 | *currDecoding++ = tempBytes[detail::decidx0]; 649 | *currDecoding++ = tempBytes[detail::decidx1]; 650 | break; 651 | } 652 | case 2: { 653 | const uint8_t t1 = *bytes++; 654 | const uint8_t t2 = *bytes++; 655 | 656 | const uint32_t d1 = detail::decode_table_0[t1]; 657 | const uint32_t d2 = detail::decode_table_1[t2]; 658 | 659 | const uint32_t temp = d1 | d2; 660 | 661 | if (temp >= detail::bad_char) { 662 | throw std::runtime_error{ 663 | "Invalid base64 encoded data - Invalid character"}; 664 | } 665 | 666 | const std::array tempBytes = 667 | detail::bit_cast, uint32_t>(temp); 668 | *currDecoding++ = tempBytes[detail::decidx0]; 669 | break; 670 | } 671 | default: { 672 | throw std::runtime_error{ 673 | "Invalid base64 encoded data - Invalid padding number"}; 674 | } 675 | } 676 | 677 | return decoded; 678 | } 679 | 680 | template 681 | inline OutputBuffer decode_into(InputIterator begin, InputIterator end) { 682 | typedef std::decay_t input_value_type; 683 | static_assert(std::is_same_v || 684 | std::is_same_v || 685 | std::is_same_v || 686 | std::is_same_v); 687 | std::string_view data(reinterpret_cast(&*begin), end - begin); 688 | return decode_into(data); 689 | } 690 | 691 | inline std::string from_base64(std::string_view data) { 692 | return decode_into(data); 693 | } 694 | 695 | } // namespace base64 696 | 697 | #endif // BASE64_HPP_ 698 | --------------------------------------------------------------------------------