Initial commit

This commit is contained in:
Pocakking 2019-03-21 20:18:31 +01:00
commit d65c694d22
100 changed files with 95579 additions and 0 deletions

399
.gitignore vendored Normal file
View File

@ -0,0 +1,399 @@
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
bin/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.iobj
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
**/wwwroot/lib/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# End of https://www.gitignore.io/api/c++,windows,visualstudio

25
BigBaseV2.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BigBaseV2", "src\BigBaseV2.vcxproj", "{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}.Debug|x64.ActiveCfg = Debug|x64
{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}.Debug|x64.Build.0 = Debug|x64
{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}.Release|x64.ActiveCfg = Release|x64
{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {942A81A5-406C-413A-83B5-B8BCB6B7FE26}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,255 @@
#ifndef __STACKWALKER_H__
#define __STACKWALKER_H__
#if defined(_MSC_VER)
/**********************************************************************
*
* StackWalker.h
*
*
*
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
*
* Copyright (c) 2005-2009, Jochen Kalmbach
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* **********************************************************************/
// #pragma once is supported starting with _MSC_VER 1000,
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
#pragma once
#include <windows.h>
#if _MSC_VER >= 1900
#pragma warning(disable : 4091)
#endif
// special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300
typedef unsigned __int64 DWORD64, *PDWORD64;
#if defined(_WIN64)
typedef unsigned __int64 SIZE_T, *PSIZE_T;
#else
typedef unsigned long SIZE_T, *PSIZE_T;
#endif
#endif // _MSC_VER < 1300
class StackWalkerInternal; // forward
class StackWalker
{
public:
typedef enum StackWalkOptions
{
// No addition info will be retrieved
// (only the address is available)
RetrieveNone = 0,
// Try to get the symbol-name
RetrieveSymbol = 1,
// Try to get the line for this symbol
RetrieveLine = 2,
// Try to retrieve the module-infos
RetrieveModuleInfo = 4,
// Also retrieve the version for the DLL/EXE
RetrieveFileVersion = 8,
// Contains all the above
RetrieveVerbose = 0xF,
// Generate a "good" symbol-search-path
SymBuildPath = 0x10,
// Also use the public Microsoft-Symbol-Server
SymUseSymSrv = 0x20,
// Contains all the above "Sym"-options
SymAll = 0x30,
// Contains all options (default)
OptionsAll = 0x3F
} StackWalkOptions;
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
LPCSTR szSymPath = NULL,
DWORD dwProcessId = GetCurrentProcessId(),
HANDLE hProcess = GetCurrentProcess());
StackWalker(DWORD dwProcessId, HANDLE hProcess);
virtual ~StackWalker();
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead,
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
);
BOOL LoadModules();
BOOL ShowCallstack(
HANDLE hThread = GetCurrentThread(),
const CONTEXT* context = NULL,
PReadProcessMemoryRoutine readMemoryFunction = NULL,
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
);
BOOL ShowObject(LPVOID pObject);
#if _MSC_VER >= 1300
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
protected:
#endif
enum
{
STACKWALK_MAX_NAMELEN = 1024
}; // max name length for found symbols
protected:
// Entry for each Callstack-Entry
typedef struct CallstackEntry
{
DWORD64 offset; // if 0, we have no valid entry
CHAR name[STACKWALK_MAX_NAMELEN];
CHAR undName[STACKWALK_MAX_NAMELEN];
CHAR undFullName[STACKWALK_MAX_NAMELEN];
DWORD64 offsetFromSmybol;
DWORD offsetFromLine;
DWORD lineNumber;
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
DWORD symType;
LPCSTR symTypeString;
CHAR moduleName[STACKWALK_MAX_NAMELEN];
DWORD64 baseOfImage;
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
} CallstackEntry;
typedef enum CallstackEntryType
{
firstEntry,
nextEntry,
lastEntry
} CallstackEntryType;
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
virtual void OnLoadModule(LPCSTR img,
LPCSTR mod,
DWORD64 baseAddr,
DWORD size,
DWORD result,
LPCSTR symType,
LPCSTR pdbName,
ULONGLONG fileVersion);
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
virtual void OnOutput(LPCSTR szText);
StackWalkerInternal* m_sw;
HANDLE m_hProcess;
DWORD m_dwProcessId;
BOOL m_modulesLoaded;
LPSTR m_szSymPath;
int m_options;
int m_MaxRecursionCount;
static BOOL __stdcall myReadProcMem(HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead);
friend StackWalkerInternal;
}; // class StackWalker
// The "ugly" assembler-implementation is needed for systems before XP
// If you have a new PSDK and you only compile for XP and later, then you can use
// the "RtlCaptureContext"
// Currently there is no define which determines the PSDK-Version...
// So we just use the compiler-version (and assumes that the PSDK is
// the one which was installed by the VS-IDE)
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
// But I currently use it in x64/IA64 environments...
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
#if defined(_M_IX86)
#ifdef CURRENT_THREAD_VIA_EXCEPTION
// TODO: The following is not a "good" implementation,
// because the callstack is only valid in the "__except" block...
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
EXCEPTION_POINTERS* pExp = NULL; \
__try \
{ \
throw 0; \
} \
__except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
: EXCEPTION_EXECUTE_HANDLER)) \
{ \
} \
if (pExp != NULL) \
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
} while (0);
#else
// clang-format off
// The following should be enough for walking the callstack...
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
__asm call x \
__asm x: pop eax \
__asm mov c.Eip, eax \
__asm mov c.Ebp, ebp \
__asm mov c.Esp, esp \
} while (0)
// clang-format on
#endif
#else
// The following is defined for x86 (XP and higher), x64 and IA64:
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
RtlCaptureContext(&c); \
} while (0);
#endif
#endif //defined(_MSC_VER)
#endif // __STACKWALKER_H__

File diff suppressed because it is too large Load Diff

452
lib/include/fmt/chrono.h Normal file
View File

@ -0,0 +1,452 @@
// Formatting library for C++ - chrono support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_CHRONO_H_
#define FMT_CHRONO_H_
#include "format.h"
#include "locale.h"
#include <chrono>
#include <ctime>
#include <locale>
#include <sstream>
FMT_BEGIN_NAMESPACE
namespace internal{
enum class numeric_system {
standard,
// Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
alternative
};
// Parses a put_time-like format string and invokes handler actions.
template <typename Char, typename Handler>
FMT_CONSTEXPR const Char *parse_chrono_format(
const Char *begin, const Char *end, Handler &&handler) {
auto ptr = begin;
while (ptr != end) {
auto c = *ptr;
if (c == '}') break;
if (c != '%') {
++ptr;
continue;
}
if (begin != ptr)
handler.on_text(begin, ptr);
++ptr; // consume '%'
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case '%':
handler.on_text(ptr - 1, ptr);
break;
case 'n': {
const char newline[] = "\n";
handler.on_text(newline, newline + 1);
break;
}
case 't': {
const char tab[] = "\t";
handler.on_text(tab, tab + 1);
break;
}
// Day of the week:
case 'a':
handler.on_abbr_weekday();
break;
case 'A':
handler.on_full_weekday();
break;
case 'w':
handler.on_dec0_weekday(numeric_system::standard);
break;
case 'u':
handler.on_dec1_weekday(numeric_system::standard);
break;
// Month:
case 'b':
handler.on_abbr_month();
break;
case 'B':
handler.on_full_month();
break;
// Hour, minute, second:
case 'H':
handler.on_24_hour(numeric_system::standard);
break;
case 'I':
handler.on_12_hour(numeric_system::standard);
break;
case 'M':
handler.on_minute(numeric_system::standard);
break;
case 'S':
handler.on_second(numeric_system::standard);
break;
// Other:
case 'c':
handler.on_datetime(numeric_system::standard);
break;
case 'x':
handler.on_loc_date(numeric_system::standard);
break;
case 'X':
handler.on_loc_time(numeric_system::standard);
break;
case 'D':
handler.on_us_date();
break;
case 'F':
handler.on_iso_date();
break;
case 'r':
handler.on_12_hour_time();
break;
case 'R':
handler.on_24_hour_time();
break;
case 'T':
handler.on_iso_time();
break;
case 'p':
handler.on_am_pm();
break;
case 'z':
handler.on_utc_offset();
break;
case 'Z':
handler.on_tz_name();
break;
// Alternative representation:
case 'E': {
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case 'c':
handler.on_datetime(numeric_system::alternative);
break;
case 'x':
handler.on_loc_date(numeric_system::alternative);
break;
case 'X':
handler.on_loc_time(numeric_system::alternative);
break;
default:
throw format_error("invalid format");
}
break;
}
case 'O':
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case 'w':
handler.on_dec0_weekday(numeric_system::alternative);
break;
case 'u':
handler.on_dec1_weekday(numeric_system::alternative);
break;
case 'H':
handler.on_24_hour(numeric_system::alternative);
break;
case 'I':
handler.on_12_hour(numeric_system::alternative);
break;
case 'M':
handler.on_minute(numeric_system::alternative);
break;
case 'S':
handler.on_second(numeric_system::alternative);
break;
default:
throw format_error("invalid format");
}
break;
default:
throw format_error("invalid format");
}
begin = ptr;
}
if (begin != ptr)
handler.on_text(begin, ptr);
return ptr;
}
struct chrono_format_checker {
void report_no_date() { throw format_error("no date"); }
template <typename Char>
void on_text(const Char *, const Char *) {}
void on_abbr_weekday() { report_no_date(); }
void on_full_weekday() { report_no_date(); }
void on_dec0_weekday(numeric_system) { report_no_date(); }
void on_dec1_weekday(numeric_system) { report_no_date(); }
void on_abbr_month() { report_no_date(); }
void on_full_month() { report_no_date(); }
void on_24_hour(numeric_system) {}
void on_12_hour(numeric_system) {}
void on_minute(numeric_system) {}
void on_second(numeric_system) {}
void on_datetime(numeric_system) { report_no_date(); }
void on_loc_date(numeric_system) { report_no_date(); }
void on_loc_time(numeric_system) { report_no_date(); }
void on_us_date() { report_no_date(); }
void on_iso_date() { report_no_date(); }
void on_12_hour_time() {}
void on_24_hour_time() {}
void on_iso_time() {}
void on_am_pm() {}
void on_utc_offset() { report_no_date(); }
void on_tz_name() { report_no_date(); }
};
template <typename Int>
inline int to_int(Int value) {
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)(), "invalid value");
return static_cast<int>(value);
}
template <typename FormatContext, typename OutputIt>
struct chrono_formatter {
FormatContext &context;
OutputIt out;
std::chrono::seconds s;
std::chrono::milliseconds ms;
typedef typename FormatContext::char_type char_type;
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
: context(ctx), out(o) {}
int hour() const { return to_int((s.count() / 3600) % 24); }
int hour12() const {
auto hour = to_int((s.count() / 3600) % 12);
return hour > 0 ? hour : 12;
}
int minute() const { return to_int((s.count() / 60) % 60); }
int second() const { return to_int(s.count() % 60); }
std::tm time() const {
auto time = std::tm();
time.tm_hour = hour();
time.tm_min = minute();
time.tm_sec = second();
return time;
}
void write(int value, int width) {
typedef typename int_traits<int>::main_type main_type;
main_type n = to_unsigned(value);
int num_digits = internal::count_digits(n);
if (width > num_digits)
out = std::fill_n(out, width - num_digits, '0');
out = format_decimal<char_type>(out, n, num_digits);
}
void format_localized(const tm &time, const char *format) {
auto locale = context.locale().template get<std::locale>();
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
std::basic_ostringstream<char_type> os;
os.imbue(locale);
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
auto str = os.str();
std::copy(str.begin(), str.end(), out);
}
void on_text(const char_type *begin, const char_type *end) {
std::copy(begin, end, out);
}
// These are not implemented because durations don't have date information.
void on_abbr_weekday() {}
void on_full_weekday() {}
void on_dec0_weekday(numeric_system) {}
void on_dec1_weekday(numeric_system) {}
void on_abbr_month() {}
void on_full_month() {}
void on_datetime(numeric_system) {}
void on_loc_date(numeric_system) {}
void on_loc_time(numeric_system) {}
void on_us_date() {}
void on_iso_date() {}
void on_utc_offset() {}
void on_tz_name() {}
void on_24_hour(numeric_system ns) {
if (ns == numeric_system::standard)
return write(hour(), 2);
auto time = tm();
time.tm_hour = hour();
format_localized(time, "%OH");
}
void on_12_hour(numeric_system ns) {
if (ns == numeric_system::standard)
return write(hour12(), 2);
auto time = tm();
time.tm_hour = hour();
format_localized(time, "%OI");
}
void on_minute(numeric_system ns) {
if (ns == numeric_system::standard)
return write(minute(), 2);
auto time = tm();
time.tm_min = minute();
format_localized(time, "%OM");
}
void on_second(numeric_system ns) {
if (ns == numeric_system::standard) {
write(second(), 2);
if (ms != std::chrono::milliseconds(0)) {
*out++ = '.';
write(to_int(ms.count()), 3);
}
return;
}
auto time = tm();
time.tm_sec = second();
format_localized(time, "%OS");
}
void on_12_hour_time() { format_localized(time(), "%r"); }
void on_24_hour_time() {
write(hour(), 2);
*out++ = ':';
write(minute(), 2);
}
void on_iso_time() {
on_24_hour_time();
*out++ = ':';
write(second(), 2);
}
void on_am_pm() { format_localized(time(), "%p"); }
};
} // namespace internal
template <typename Period> FMT_CONSTEXPR const char *get_units() {
return FMT_NULL;
}
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
return "m";
}
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
return "h";
}
template <typename Rep, typename Period, typename Char>
struct formatter<std::chrono::duration<Rep, Period>, Char> {
private:
align_spec spec;
internal::arg_ref<Char> width_ref;
mutable basic_string_view<Char> format_str;
typedef std::chrono::duration<Rep, Period> duration;
struct spec_handler {
formatter &f;
basic_parse_context<Char> &context;
typedef internal::arg_ref<Char> arg_ref_type;
template <typename Id>
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
context.check_arg_id(arg_id);
return arg_ref_type(arg_id);
}
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
return arg_ref_type(context.next_arg_id());
}
void on_error(const char *msg) { throw format_error(msg); }
void on_fill(Char fill) { f.spec.fill_ = fill; }
void on_align(alignment align) { f.spec.align_ = align; }
void on_width(unsigned width) { f.spec.width_ = width; }
template <typename Id>
void on_dynamic_width(Id arg_id) {
f.width_ref = make_arg_ref(arg_id);
}
};
public:
formatter() : spec() {}
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
-> decltype(ctx.begin()) {
auto begin = ctx.begin(), end = ctx.end();
if (begin == end) return begin;
spec_handler handler{*this, ctx};
begin = internal::parse_align(begin, end, handler);
if (begin == end) return begin;
begin = internal::parse_width(begin, end, handler);
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
return end;
}
template <typename FormatContext>
auto format(const duration &d, FormatContext &ctx)
-> decltype(ctx.out()) {
auto begin = format_str.begin(), end = format_str.end();
memory_buffer buf;
typedef output_range<decltype(ctx.out()), Char> range;
basic_writer<range> w(range(ctx.out()));
if (begin == end || *begin == '}') {
if (const char *unit = get_units<Period>())
format_to(buf, "{}{}", d.count(), unit);
else if (Period::den == 1)
format_to(buf, "{}[{}]s", d.count(), Period::num);
else
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
internal::handle_dynamic_spec<internal::width_checker>(
spec.width_, width_ref, ctx);
} else {
auto out = std::back_inserter(buf);
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
parse_chrono_format(begin, end, f);
}
w.write(buf.data(), buf.size(), spec);
return w.out();
}
};
FMT_END_NAMESPACE
#endif // FMT_CHRONO_H_

577
lib/include/fmt/color.h Normal file
View File

@ -0,0 +1,577 @@
// Formatting library for C++ - color support
//
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COLOR_H_
#define FMT_COLOR_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
#ifdef FMT_DEPRECATED_COLORS
// color and (v)print_colored are deprecated.
enum color { black, red, green, yellow, blue, magenta, cyan, white };
FMT_API void vprint_colored(color c, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
template <typename... Args>
inline void print_colored(color c, string_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args(args...));
}
template <typename... Args>
inline void print_colored(color c, wstring_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
}
inline void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(internal::data::WRESET_COLOR, stdout);
}
#else
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
enum class terminal_color : uint8_t {
black = 30,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black = 90,
bright_red,
bright_green,
bright_yellow,
bright_blue,
bright_magenta,
bright_cyan,
bright_white
}; // enum class terminal_color
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
}; // enum class emphasis
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb {
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
FMT_CONSTEXPR_DECL rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
};
namespace internal {
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT
: is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
: is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
: is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
union color_union {
uint8_t term_color;
uint32_t rgb_color;
} value;
};
} // namespace internal
// Experimental text formatting support.
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
throw format_error("can't OR a terminal color");
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
throw format_error("can't OR a terminal color");
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR
text_style operator|(text_style lhs, const text_style &rhs) {
return lhs |= rhs;
}
FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
throw format_error("can't AND a terminal color");
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
throw format_error("can't AND a terminal color");
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR
text_style operator&(text_style lhs, const text_style &rhs) {
return lhs &= rhs;
}
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
return set_foreground_color;
}
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
return set_background_color;
}
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
assert(has_foreground() && "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
assert(has_background() && "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
assert(has_emphasis() && "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
internal::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
FMT_NOEXCEPT;
internal::color_type foreground_color;
internal::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/true, foreground);
}
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/false, background);
}
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
return text_style(lhs) | rhs;
}
namespace internal {
template <typename Char>
struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char * esc) FMT_NOEXCEPT {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == internal::data::BACKGROUND_COLOR;
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background)
value += 10u;
std::size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
if (value >= 100u) {
buffer[index++] = static_cast<Char>('1');
value %= 100u;
}
buffer[index++] = static_cast<Char>('0' + value / 10u);
buffer[index++] = static_cast<Char>('0' + value % 10u);
buffer[index++] = static_cast<Char>('m');
buffer[index++] = static_cast<Char>('\0');
return;
}
for (int i = 0; i < 7; i++) {
buffer[i] = static_cast<Char>(esc[i]);
}
rgb color(text_color.value.rgb_color);
to_esc(color.r, buffer + 7, ';');
to_esc(color.g, buffer + 11, ';');
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold))
em_codes[0] = 1;
if (em_bits & static_cast<uint8_t>(emphasis::italic))
em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline))
em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9;
std::size_t index = 0;
for (int i = 0; i < 4; ++i) {
if (!em_codes[i])
continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
buffer[index++] = static_cast<Char>('m');
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
private:
Char buffer[7u + 3u * 4u + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
char delimiter) FMT_NOEXCEPT {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_background_color(internal::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_emphasis(emphasis em) FMT_NOEXCEPT {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
}
template <>
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
}
template <typename Char>
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::RESET_COLOR, stream);
}
template <>
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::WRESET_COLOR, stream);
}
// The following specialiazation disables using std::FILE as a character type,
// which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string.
template <>
struct is_string<std::FILE *> : std::false_type {};
template <>
struct is_string<const std::FILE *> : std::false_type {};
} // namespace internal
template <
typename S, typename Char = typename internal::char_t<S>::type>
void vprint(std::FILE *f, const text_style &ts, const S &format,
basic_format_args<typename buffer_context<Char>::type> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
internal::fputs<Char>(
internal::make_emphasis<Char>(ts.get_emphasis()), f);
}
if (ts.has_foreground()) {
has_style = true;
internal::fputs<Char>(
internal::make_foreground_color<Char>(ts.get_foreground()), f);
}
if (ts.has_background()) {
has_style = true;
internal::fputs<Char>(
internal::make_background_color<Char>(ts.get_background()), f);
}
vprint(f, format, args);
if (has_style) {
internal::reset_color<Char>(f);
}
}
/**
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
Example:
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
std::FILE *f, const text_style &ts, const String &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str);
typedef typename internal::char_t<String>::type char_t;
typedef typename buffer_context<char_t>::type context_t;
format_arg_store<context_t, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context_t>(as));
}
/**
Formats a string and prints it to stdout using ANSI escape sequences to
specify text formatting.
Example:
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
const text_style &ts, const String &format_str,
const Args &... args) {
return print(stdout, ts, format_str, args...);
}
#endif
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

1502
lib/include/fmt/core.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,972 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_FORMAT_INL_H_
#define FMT_FORMAT_INL_H_
#include "format.h"
#include <string.h>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#include <cstring> // for std::memmove
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
# include <locale>
#endif
#if FMT_USE_WINDOWS_H
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true)
# define FMT_CATCH(x) if (false)
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline fmt::internal::null<> strerror_r(int, char *, ...) {
return fmt::internal::null<>();
}
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::null<>();
}
FMT_BEGIN_NAMESPACE
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class dispatcher {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const dispatcher &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
#if !FMT_MSC_VER
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
#endif
public:
dispatcher(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return dispatcher(error_code, buffer, buffer_size).run();
}
void format_error_code(internal::buffer &out, int error_code,
string_view message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential
// bad_alloc.
out.resize(0);
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::int_traits<int>::main_type main_type;
main_type abs_value = static_cast<main_type>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::to_unsigned(internal::count_digits(abs_value));
writer w(out);
if (message.size() <= inline_buffer_size - error_code_size) {
w.write(message);
w.write(SEP);
}
w.write(ERROR_STR);
w.write(error_code);
assert(out.size() <= inline_buffer_size);
}
void report_error(FormatFunc func, int error_code,
string_view message) FMT_NOEXCEPT {
memory_buffer full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
const char8_t *data = s.data();
size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
if ((data[i] & 0xc0) != 0x80)
++num_code_points;
}
return num_code_points;
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace internal {
template <typename Locale>
locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
static_assert(std::is_same<Locale, std::locale>::value, "");
}
template <typename Locale>
Locale locale_ref::get() const {
static_assert(std::is_same<Locale, std::locale>::value, "");
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
}
template <typename Char>
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
return std::use_facet<std::numpunct<Char> >(
loc.get<std::locale>()).thousands_sep();
}
}
#else
template <typename Char>
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
return FMT_STATIC_THOUSANDS_SEPARATOR;
}
#endif
FMT_FUNC void system_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
format_system_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buf, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buf, size, format, value) :
FMT_SNPRINTF(buf, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buf, size, format, value) :
FMT_SWPRINTF(buf, size, format, precision, value);
}
template <typename T>
const char basic_data<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
1, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py.
template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
};
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
// to significands above.
template <typename T>
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
};
template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
// A handmade floating-point number f * pow(2, e).
class fp {
private:
typedef uint64_t significand_type;
// All sizes are in bits.
static FMT_CONSTEXPR_DECL const int char_size =
std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
static FMT_CONSTEXPR_DECL const int double_significand_size =
std::numeric_limits<double>::digits - 1;
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
1ull << double_significand_size;
public:
significand_type f;
int e;
static FMT_CONSTEXPR_DECL const int significand_size =
sizeof(significand_type) * char_size;
fp(): f(0), e(0) {}
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
// errors on platforms where double is not IEEE754.
template <typename Double>
explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits;
const int double_size = static_cast<int>(sizeof(Double) * char_size);
const int exponent_size =
double_size - double_significand_size - 1; // -1 for sign
const uint64_t significand_mask = implicit_bit - 1;
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
auto u = bit_cast<uint64_t>(d);
auto biased_e = (u & exponent_mask) >> double_significand_size;
f = u & significand_mask;
if (biased_e != 0)
f += implicit_bit;
else
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template <int SHIFT = 0>
void normalize() {
// Handle subnormals.
auto shifted_implicit_bit = implicit_bit << SHIFT;
while ((f & shifted_implicit_bit) == 0) {
f <<= 1;
--e;
}
// Subtract 1 to account for hidden bit.
auto offset = significand_size - double_significand_size - SHIFT - 1;
f <<= offset;
e -= offset;
}
// Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
// a boundary is a value half way between the number and its predecessor
// (lower) or successor (upper). The upper boundary is normalized and lower
// has the same exponent but may be not normalized.
void compute_boundaries(fp &lower, fp &upper) const {
lower = f == implicit_bit ?
fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
upper = fp((f << 1) + 1, e - 1);
upper.normalize<1>(); // 1 is to account for the exponent shift above.
lower.f <<= lower.e - upper.e;
lower.e = upper.e;
}
};
// Returns an fp number representing x - y. Result may not be normalized.
inline fp operator-(fp x, fp y) {
FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
return fp(x.f - y.f, x.e);
}
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
FMT_API fp operator*(fp x, fp y);
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
FMT_FUNC fp operator*(fp x, fp y) {
// Multiply 32-bit parts of significands.
uint64_t mask = (1ULL << 32) - 1;
uint64_t a = x.f >> 32, b = x.f & mask;
uint64_t c = y.f >> 32, d = y.f & mask;
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
// Compute mid 64-bit of result and round.
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
}
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil(
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348;
// Difference between 2 consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
FMT_FUNC bool grisu2_round(
char *buf, int &size, int max_digits, uint64_t delta,
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
while (remainder < diff && delta - remainder >= exp &&
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
--buf[size - 1];
remainder += exp;
}
if (size > max_digits) {
--size;
++exp10;
if (buf[size] >= '5')
return false;
}
return true;
}
// Generates output using Grisu2 digit-gen algorithm.
FMT_FUNC bool grisu2_gen_digits(
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
// Generate digits for the most significant part (hi).
while (exp > 0) {
uint32_t digit = 0;
// This optimization by miloyip reduces the number of integer divisions by
// one per iteration.
switch (exp) {
case 10: digit = hi / 1000000000; hi %= 1000000000; break;
case 9: digit = hi / 100000000; hi %= 100000000; break;
case 8: digit = hi / 10000000; hi %= 10000000; break;
case 7: digit = hi / 1000000; hi %= 1000000; break;
case 6: digit = hi / 100000; hi %= 100000; break;
case 5: digit = hi / 10000; hi %= 10000; break;
case 4: digit = hi / 1000; hi %= 1000; break;
case 3: digit = hi / 100; hi %= 100; break;
case 2: digit = hi / 10; hi %= 10; break;
case 1: digit = hi; hi = 0; break;
default:
FMT_ASSERT(false, "invalid number of digits");
}
if (digit != 0 || size != 0)
buf[size++] = static_cast<char>('0' + digit);
--exp;
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
if (remainder <= delta || size > max_digits) {
return grisu2_round(
buf, size, max_digits, delta, remainder,
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
diff.f, exp);
}
}
// Generate digits for the least significant part (lo).
for (;;) {
lo *= 10;
delta *= 10;
char digit = static_cast<char>(lo >> -one.e);
if (digit != 0 || size != 0)
buf[size++] = static_cast<char>('0' + digit);
lo &= one.f - 1;
--exp;
if (lo < delta || size > max_digits) {
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
diff.f * data::POWERS_OF_10_32[-exp], exp);
}
}
}
#if FMT_CLANG_VERSION
# define FMT_FALLTHROUGH [[clang::fallthrough]];
#elif FMT_GCC_VERSION >= 700
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
#else
# define FMT_FALLTHROUGH
#endif
struct gen_digits_params {
int num_digits;
bool fixed;
bool upper;
bool trailing_zeros;
};
struct prettify_handler {
char *data;
ptrdiff_t size;
buffer &buf;
explicit prettify_handler(buffer &b, ptrdiff_t n)
: data(b.data()), size(n), buf(b) {}
~prettify_handler() {
assert(buf.size() >= to_unsigned(size));
buf.resize(to_unsigned(size));
}
template <typename F>
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
f(data + pos);
size += n;
}
void insert(ptrdiff_t pos, char c) {
std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));
data[pos] = c;
++size;
}
void append(ptrdiff_t n, char c) {
std::uninitialized_fill_n(data + size, n, c);
size += n;
}
void append(char c) { data[size++] = c; }
void remove_trailing(char c) {
while (data[size - 1] == c) --size;
}
};
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template <typename Handler>
FMT_FUNC void write_exponent(int exp, Handler &&h) {
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
if (exp < 0) {
h.append('-');
exp = -exp;
} else {
h.append('+');
}
if (exp >= 100) {
h.append(static_cast<char>('0' + exp / 100));
exp %= 100;
const char *d = data::DIGITS + exp * 2;
h.append(d[0]);
h.append(d[1]);
} else {
const char *d = data::DIGITS + exp * 2;
h.append(d[0]);
h.append(d[1]);
}
}
struct fill {
size_t n;
void operator()(char *buf) const {
buf[0] = '0';
buf[1] = '.';
std::uninitialized_fill_n(buf + 2, n, '0');
}
};
// The number is given as v = f * pow(10, exp), where f has size digits.
template <typename Handler>
FMT_FUNC void grisu2_prettify(const gen_digits_params &params,
int size, int exp, Handler &&handler) {
if (!params.fixed) {
// Insert a decimal point after the first digit and add an exponent.
handler.insert(1, '.');
exp += size - 1;
if (size < params.num_digits)
handler.append(params.num_digits - size, '0');
handler.append(params.upper ? 'E' : 'e');
write_exponent(exp, handler);
return;
}
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
int full_exp = size + exp;
const int exp_threshold = 21;
if (size <= full_exp && full_exp <= exp_threshold) {
// 1234e7 -> 12340000000[.0+]
handler.append(full_exp - size, '0');
int num_zeros = params.num_digits - full_exp;
if (num_zeros > 0 && params.trailing_zeros) {
handler.append('.');
handler.append(num_zeros, '0');
}
} else if (full_exp > 0) {
// 1234e-2 -> 12.34[0+]
handler.insert(full_exp, '.');
if (!params.trailing_zeros) {
// Remove trailing zeros.
handler.remove_trailing('0');
} else if (params.num_digits > size) {
// Add trailing zeros.
ptrdiff_t num_zeros = params.num_digits - size;
handler.append(num_zeros, '0');
}
} else {
// 1234e-6 -> 0.001234
handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
}
}
struct char_counter {
ptrdiff_t size;
template <typename F>
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
void insert(ptrdiff_t, char) { ++size; }
void append(ptrdiff_t n, char) { size += n; }
void append(char) { ++size; }
void remove_trailing(char) {}
};
// Converts format specifiers into parameters for digit generation and computes
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
// or 0 if exp == 1.
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
int exp, buffer &buf) {
auto params = gen_digits_params();
int num_digits = specs.precision >= 0 ? specs.precision : 6;
switch (specs.type) {
case 'G':
params.upper = true;
FMT_FALLTHROUGH
case '\0': case 'g':
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
if (-4 <= exp && exp < num_digits + 1) {
params.fixed = true;
if (!specs.type && params.trailing_zeros && exp >= 0)
num_digits = exp + 1;
}
break;
case 'F':
params.upper = true;
FMT_FALLTHROUGH
case 'f': {
params.fixed = true;
params.trailing_zeros = true;
int adjusted_min_digits = num_digits + exp;
if (adjusted_min_digits > 0)
num_digits = adjusted_min_digits;
break;
}
case 'E':
params.upper = true;
FMT_FALLTHROUGH
case 'e':
++num_digits;
break;
}
params.num_digits = num_digits;
char_counter counter{num_digits};
grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
buf.resize(to_unsigned(counter.size));
return params;
}
template <typename Double>
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
FMT_ASSERT(value >= 0, "value is negative");
if (value == 0) {
gen_digits_params params = process_specs(specs, 1, buf);
const size_t size = 1;
buf[0] = '0';
grisu2_prettify(params, size, 0, prettify_handler(buf, size));
return true;
}
fp fp_value(value);
fp lower, upper; // w^- and w^+ in the Grisu paper.
fp_value.compute_boundaries(lower, upper);
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
const int min_exp = -60; // alpha in Grisu.
int cached_exp = 0; // K in Grisu.
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
min_exp - (upper.e + fp::significand_size), cached_exp);
cached_exp = -cached_exp;
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
fp one(1ull << -upper.e, upper.e);
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
// hi = floor(upper / one).
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
int exp = count_digits(hi); // kappa in Grisu.
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
fp_value.normalize();
fp scaled_value = fp_value * cached_pow;
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
uint64_t delta = upper.f - lower.f;
fp diff = upper - scaled_value; // wp_w in Grisu.
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
// lo = supper % one.
uint64_t lo = upper.f & (one.f - 1);
int size = 0;
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
params.num_digits)) {
buf.clear();
return false;
}
grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
return true;
}
template <typename Double>
void sprintf_format(Double value, internal::buffer &buf,
core_format_specs spec) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char format[MAX_FORMAT_SIZE];
char *format_ptr = format;
*format_ptr++ = '%';
if (spec.has(HASH_FLAG))
*format_ptr++ = '#';
if (spec.precision >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
if (std::is_same<Double, long double>::value)
*format_ptr++ = 'L';
*format_ptr++ = spec.type;
*format_ptr = '\0';
// Format using snprintf.
char *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buf.capacity();
start = &buf[0];
int result = internal::char_traits<char>::format_float(
start, buffer_size, format, spec.precision, value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buf.capacity()) {
buf.resize(n);
break; // The buffer is large enough - continue with formatting.
}
buf.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf.reserve(buf.capacity() + 1);
}
}
}
} // namespace internal
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// MultiByteToWideChar does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return;
}
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void windows_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
FMT_FUNC void internal::format_windows_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
wmemory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
wchar_t *system_message = &buf[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
writer w(out);
w.write(message);
w.write(": ");
w.write(utf8_message);
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
memory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
char *system_message = &buf[0];
int result = safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
writer w(out);
w.write(message);
w.write(": ");
w.write(system_message);
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
FMT_FUNC void internal::error_handler::on_error(const char *message) {
FMT_THROW(format_error(message));
}
FMT_FUNC void report_system_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
memory_buffer buffer;
internal::vformat_to(buffer, format_str,
basic_format_args<buffer_context<char>::type>(args));
std::fwrite(buffer.data(), 1, buffer.size(), f);
}
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
internal::vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}
FMT_FUNC void vprint(string_view format_str, format_args args) {
vprint(stdout, format_str, args);
}
FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint(stdout, format_str, args);
}
FMT_END_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif // FMT_FORMAT_INL_H_

3555
lib/include/fmt/format.h Normal file

File diff suppressed because it is too large Load Diff

77
lib/include/fmt/locale.h Normal file
View File

@ -0,0 +1,77 @@
// Formatting library for C++ - std::locale support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include "format.h"
#include <locale>
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
typename buffer_context<Char>::type::iterator vformat_to(
const std::locale &loc, basic_buffer<Char> &buf,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
typedef back_insert_range<basic_buffer<Char> > range;
return vformat_to<arg_formatter<range>>(
buf, to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename Char>
std::basic_string<Char> vformat(
const std::locale &loc, basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer);
}
}
template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char> vformat(
const std::locale &loc, const S &format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
return internal::vformat(loc, to_string_view(format_str), args);
}
template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format(
const std::locale &loc, const S &format_str, const Args &... args) {
return internal::vformat(
loc, to_string_view(format_str),
*internal::checked_args<S, Args...>(format_str, args...));
}
template <typename String, typename OutputIt, typename... Args>
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
OutputIt>::type
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
typedef output_range<OutputIt, FMT_CHAR(String)> range;
return vformat_to<arg_formatter<range>>(
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename OutputIt, typename S, typename... Args>
inline typename std::enable_if<
internal::is_string<S>::value &&
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
format_to(OutputIt out, const std::locale &loc, const S &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str);
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE
#endif // FMT_LOCALE_H_

153
lib/include/fmt/ostream.h Normal file
View File

@ -0,0 +1,153 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char>
class formatbuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
basic_buffer<Char> &buffer_;
public:
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
template <typename Char>
struct test_stream : std::basic_ostream<Char> {
private:
struct null;
// Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null);
};
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
template <typename T, typename Char>
class is_streamable {
private:
template <typename U>
static decltype(
internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
typedef decltype(test<T>(0)) result;
public:
static const bool value = result::value;
};
// Write the content of buf to os.
template <typename Char>
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
const Char *data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(basic_buffer<Char> &buffer, const T &value) {
internal::formatbuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
buffer.resize(buffer.size());
}
} // namespace internal
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T, typename Char>
struct convert_to_int<T, Char, void> {
static const bool value =
convert_to_int<T, Char, int>::value &&
!internal::is_streamable<T, Char>::value;
};
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct formatter<T, Char,
typename std::enable_if<
internal::is_streamable<T, Char>::value &&
!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
};
template <typename Char>
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename S, typename... Args>
inline typename std::enable_if<internal::is_string<S>::value>::type
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
const Args & ... args) {
internal::checked_args<S, Args...> ca(format_str, args...);
vprint(os, to_string_view(format_str), *ca);
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

324
lib/include/fmt/posix.h Normal file
View File

@ -0,0 +1,324 @@
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <locale.h> // for locale_t
#include <stdio.h>
#include <stdlib.h> // for strtod_l
#include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following typedefs for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class basic_cstring_view {
private:
const Char *data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char *c_str() const { return data_; }
};
typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code.
class error_code {
private:
int value_;
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class buffered_file {
private:
FILE *file_;
friend class file;
explicit buffered_file(FILE *f) : file_(f) {}
public:
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
private:
buffered_file(const buffered_file &) = delete;
void operator=(const buffered_file &) = delete;
public:
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = FMT_NULL;
}
buffered_file& operator=(buffered_file &&other) {
close();
file_ = other.file_;
other.file_ = FMT_NULL;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API int (fileno)() const;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args & ... args) {
vprint(format_str, make_format_args(args...));
}
};
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class file {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
private:
file(const file &) = delete;
void operator=(const file &) = delete;
public:
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
file& operator=(file &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API std::size_t read(void *buffer, std::size_t count);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API static void pipe(file &read_end, file &write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API buffered_file fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
!defined(__NEWLIB_H__)
# define FMT_LOCALE
#endif
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
private:
# ifdef _MSC_VER
typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale) {
_free_locale(locale);
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale);
}
# endif
locale_t locale_;
Locale(const Locale &) = delete;
void operator=(const Locale &) = delete;
public:
typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
if (!locale_)
FMT_THROW(system_error(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
Type get() const { return locale_; }
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char *&str) const {
char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
#endif // FMT_LOCALE
FMT_END_NAMESPACE
#endif // FMT_POSIX_H_

855
lib/include/fmt/printf.h Normal file
View File

@ -0,0 +1,855 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits
#include "ostream.h"
FMT_BEGIN_NAMESPACE
namespace internal {
// An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string
// vs string_view.
template <typename Char>
class null_terminating_iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef Char value_type;
typedef const Char* pointer;
typedef const Char& reference;
typedef std::random_access_iterator_tag iterator_category;
null_terminating_iterator() : ptr_(0), end_(0) {}
FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
: ptr_(ptr), end_(end) {}
template <typename Range>
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
: ptr_(r.begin()), end_(r.end()) {}
FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
assert(ptr <= end_);
ptr_ = ptr;
return *this;
}
FMT_CONSTEXPR Char operator*() const {
return ptr_ != end_ ? *ptr_ : Char();
}
FMT_CONSTEXPR null_terminating_iterator operator++() {
++ptr_;
return *this;
}
FMT_CONSTEXPR null_terminating_iterator operator++(int) {
null_terminating_iterator result(*this);
++ptr_;
return result;
}
FMT_CONSTEXPR null_terminating_iterator operator--() {
--ptr_;
return *this;
}
FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
return null_terminating_iterator(ptr_ + n, end_);
}
FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
return null_terminating_iterator(ptr_ - n, end_);
}
FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
ptr_ += n;
return *this;
}
FMT_CONSTEXPR difference_type operator-(
null_terminating_iterator other) const {
return ptr_ - other.ptr_;
}
FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
return ptr_ != other.ptr_;
}
bool operator>=(null_terminating_iterator other) const {
return ptr_ >= other.ptr_;
}
// This should be a friend specialization pointer_from<Char> but the latter
// doesn't compile by gcc 5.1 due to a compiler bug.
template <typename CharT>
friend FMT_CONSTEXPR_DECL const CharT *pointer_from(
null_terminating_iterator<CharT> it);
private:
const Char *ptr_;
const Char *end_;
};
template <typename T>
FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
template <typename Char>
FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
return it.ptr_;
}
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
// that the first character is a digit and presence of a non-digit character at
// the end.
// it: an iterator pointing to the beginning of the input range.
template <typename Iterator, typename ErrorHandler>
FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
assert('0' <= *it && *it <= '9');
if (*it == '0') {
++it;
return 0;
}
unsigned value = 0;
// Convert to unsigned to prevent a warning.
unsigned max_int = (std::numeric_limits<int>::max)();
unsigned big = max_int / 10;
do {
// Check for overflow.
if (value > big) {
value = max_int + 1;
break;
}
value = value * 10 + unsigned(*it - '0');
// Workaround for MSVC "setup_exception stack overflow" error:
auto next = it;
++next;
it = next;
} while ('0' <= *it && *it <= '9');
if (value > max_int)
eh.on_error("number is too big");
return value;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
struct int_checker {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
};
template <>
struct int_checker<true> {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max();
}
static bool fits_in_int(int) { return true; }
};
class printf_precision_handler: public function<int> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type
operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
return static_cast<int>(value);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
FMT_THROW(format_error("precision is not integer"));
return 0;
}
};
// An argument visitor that returns true iff arg is a zero integer.
class is_zero_int: public function<bool> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
operator()(T value) { return value == 0; }
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type
operator()(T) { return false; }
};
template <typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <>
struct make_unsigned_or_bool<bool> {
typedef bool type;
};
template <typename T, typename Context>
class arg_converter: public function<void> {
private:
typedef typename Context::char_type Char;
basic_format_arg<Context> &arg_;
typename Context::char_type type_;
public:
arg_converter(basic_format_arg<Context> &arg, Char type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
if (type_ != 's')
operator()<bool>(value);
}
template <typename U>
typename std::enable_if<std::is_integral<U>::value>::type
operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<
std::is_same<T, void>::value, U, T>::type TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
static_cast<int>(static_cast<TargetType>(value)));
} else {
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
}
} else {
if (is_signed) {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
} else {
arg_ = internal::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
}
template <typename U>
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
// No coversion needed for non-integral types.
}
};
// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) {
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
}
// Converts an integer argument to char for printf.
template <typename Context>
class char_converter: public function<void> {
private:
basic_format_arg<Context> &arg_;
public:
explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) {
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
// No coversion needed for non-integral types.
}
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char>
class printf_width_handler: public function<unsigned> {
private:
typedef basic_format_specs<Char> format_specs;
format_specs &spec_;
public:
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
operator()(T value) {
typedef typename internal::int_traits<T>::main_type UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT;
width = 0 - width;
}
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(format_error("number is too big"));
return static_cast<unsigned>(width);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
operator()(T) {
FMT_THROW(format_error("width is not integer"));
return 0;
}
};
template <typename Char, typename Context>
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
} // namespace internal
using internal::printf; // For printing into memory_buffer.
template <typename Range>
class printf_arg_formatter;
template <
typename OutputIt, typename Char,
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context;
/**
\rst
The ``printf`` argument formatter.
\endrst
*/
template <typename Range>
class printf_arg_formatter:
public internal::function<
typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type> context_type;
context_type &context_;
void write_null_pointer(char) {
this->spec()->type = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->spec()->type = 0;
this->write(L"(nil)");
}
public:
typedef typename base::format_specs format_specs;
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
format_specs &spec, context_type &ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
ctx.locale()),
context_(ctx) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type
operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead.
if (std::is_same<T, bool>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type != 's')
return base::operator()(value ? 1 : 0);
fmt_spec.type = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type && fmt_spec.type != 'c')
return (*this)(static_cast<int>(value));
fmt_spec.flags = 0;
fmt_spec.align_ = ALIGN_RIGHT;
return base::operator()(value);
} else {
return base::operator()(value);
}
return this->out();
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
operator()(T value) {
return base::operator()(value);
}
/** Formats a null-terminated C string. */
iterator operator()(const char *value) {
if (value)
base::operator()(value);
else if (this->spec()->type == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
}
/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t *value) {
if (value)
base::operator()(value);
else if (this->spec()->type == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
}
iterator operator()(basic_string_view<char_type> value) {
return base::operator()(value);
}
iterator operator()(monostate value) {
return base::operator()(value);
}
/** Formats a pointer. */
iterator operator()(const void *value) {
if (value)
return base::operator()(value);
this->spec()->type = 0;
write_null_pointer(char_type());
return this->out();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_);
return this->out();
}
};
template <typename T>
struct printf_formatter {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
template <typename FormatContext>
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
internal::format_value(internal::get_container(ctx.out()), value);
return ctx.out();
}
};
/** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char, typename ArgFormatter>
class basic_printf_context :
// Inherit publicly as a workaround for the icc bug
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
public internal::context_base<
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
public:
/** The character type for the output. */
typedef Char char_type;
template <typename T>
struct formatter_type { typedef printf_formatter<T> type; };
private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
typedef typename base::format_arg format_arg;
typedef basic_format_specs<char_type> format_specs;
typedef internal::null_terminating_iterator<char_type> iterator;
void parse_flags(format_specs &spec, iterator &it);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
format_arg get_arg(
iterator it,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(iterator &it, format_specs &spec);
public:
/**
\rst
Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have
appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
basic_format_args<basic_printf_context> args)
: base(out, format_str, args) {}
using base::parse_context;
using base::out;
using base::advance_to;
/** Formats stored arguments and writes the output to the range. */
void format();
};
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(
format_specs &spec, iterator &it) {
for (;;) {
switch (*it++) {
case '-':
spec.align_ = ALIGN_LEFT;
break;
case '+':
spec.flags |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags |= SIGN_FLAG;
break;
case '#':
spec.flags |= HASH_FLAG;
break;
default:
--it;
return;
}
}
}
template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg
basic_printf_context<OutputIt, Char, AF>::get_arg(
iterator it, unsigned arg_index) {
(void)it;
if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id());
return base::get_arg(arg_index - 1);
}
template <typename OutputIt, typename Char, typename AF>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
internal::error_handler eh;
unsigned value = parse_nonnegative_int(it, eh);
if (*it == '$') { // value is an argument index
++it;
arg_index = value;
} else {
if (c == '0')
spec.fill_ = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec.width_ = value;
return arg_index;
}
}
}
parse_flags(spec, it);
// Parse width.
if (*it >= '0' && *it <= '9') {
internal::error_handler eh;
spec.width_ = parse_nonnegative_int(it, eh);
} else if (*it == '*') {
++it;
spec.width_ = visit_format_arg(
internal::printf_width_handler<char_type>(spec), get_arg(it));
}
return arg_index;
}
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::format() {
auto &buffer = internal::get_container(this->out());
auto start = iterator(this->parse_context());
auto it = start;
using internal::pointer_from;
while (*it) {
char_type c = *it++;
if (c != '%') continue;
if (*it == c) {
buffer.append(pointer_from(start), pointer_from(it));
start = ++it;
continue;
}
buffer.append(pointer_from(start), pointer_from(it) - 1);
format_specs spec;
spec.align_ = ALIGN_RIGHT;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(it, spec);
// Parse precision.
if (*it == '.') {
++it;
if ('0' <= *it && *it <= '9') {
internal::error_handler eh;
spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));
} else if (*it == '*') {
++it;
spec.precision =
visit_format_arg(internal::printf_precision_handler(), get_arg(it));
} else {
spec.precision = 0;
}
}
format_arg arg = get_arg(it, arg_index);
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
if (spec.fill_ == '0') {
if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC;
else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using internal::convert_arg;
switch (*it++) {
case 'h':
if (*it == 'h')
convert_arg<signed char>(arg, *++it);
else
convert_arg<short>(arg, *it);
break;
case 'l':
if (*it == 'l')
convert_arg<long long>(arg, *++it);
else
convert_arg<long>(arg, *it);
break;
case 'j':
convert_arg<intmax_t>(arg, *it);
break;
case 'z':
convert_arg<std::size_t>(arg, *it);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, *it);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--it;
convert_arg<void>(arg, *it);
}
// Parse type.
if (!*it)
FMT_THROW(format_error("invalid format string"));
spec.type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (spec.type) {
case 'i': case 'u':
spec.type = 'd';
break;
case 'c':
// TODO: handle wchar_t better?
visit_format_arg(
internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
start = it;
// Format argument.
visit_format_arg(AF(buffer, spec, *this), arg);
}
buffer.append(pointer_from(start), pointer_from(it));
}
template <typename Buffer>
struct basic_printf_context_t {
typedef basic_printf_context<
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
};
typedef basic_printf_context_t<internal::buffer>::type printf_context;
typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
typedef basic_format_args<printf_context> printf_args;
typedef basic_format_args<wprintf_context> wprintf_args;
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template<typename... Args>
inline format_arg_store<printf_context, Args...>
make_printf_args(const Args &... args) { return {args...}; }
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template<typename... Args>
inline format_arg_store<wprintf_context, Args...>
make_wprintf_args(const Args &... args) { return {args...}; }
template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char>
vsprintf(const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
return to_string(buffer);
}
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
sprintf(const S &format, const Args & ... args) {
internal::check_format_string<Args...>(format);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vsprintf(to_string_view(format),
basic_format_args<context>(as));
}
template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::FILE *f, const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
std::size_t size = buffer.size();
return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
}
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
fprintf(std::FILE *f, const S &format, const Args & ... args) {
internal::check_format_string<Args...>(format);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vfprintf(f, to_string_view(format),
basic_format_args<context>(as));
}
template <typename S, typename Char = FMT_CHAR(S)>
inline int vprintf(const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
return vfprintf(stdout, to_string_view(format), args);
}
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
printf(const S &format_str, const Args & ... args) {
internal::check_format_string<Args...>(format_str);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vprintf(to_string_view(format_str),
basic_format_args<context>(as));
}
template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::basic_ostream<Char> &os,
const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
const S &format_str, const Args & ... args) {
internal::check_format_string<Args...>(format_str);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vfprintf(os, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

308
lib/include/fmt/ranges.h Normal file
View File

@ -0,0 +1,308 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include "format.h"
#include <type_traits>
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE
template <typename Char>
struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
Char prefix;
Char delimiter;
Char postfix;
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> {
Char prefix;
Char delimiter;
Char postfix;
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
namespace internal {
template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
}
template <typename OutputIterator>
void copy(const char *str, OutputIterator out) {
const char *p_curr = str;
while (*p_curr) {
*out++ = *p_curr++;
}
}
template <typename OutputIterator>
void copy(char ch, OutputIterator out) {
*out++ = ch;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T>
class is_like_std_string {
template <typename U>
static auto check(U *p) ->
decltype(p->find('a'), p->length(), p->data(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
template <typename... Ts>
struct conditional_helper {};
template <typename T, typename _ = void>
struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T>
struct is_range_<T, typename std::conditional<
false,
conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
#endif
/// tuple_size and tuple_element check.
template <typename T>
class is_tuple_like_ {
template <typename U>
static auto check(U *p) ->
decltype(std::tuple_size<U>::value,
internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N>
using index_sequence = std::index_sequence<N...>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N>
struct integer_sequence {
typedef T value_type;
static FMT_CONSTEXPR std::size_t size() {
return sizeof...(N);
}
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
get_indexes(T const &) { return {}; }
template <class Tuple, class F>
void for_each(Tuple &&tup, F &&f) {
const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " {}" : "{}";
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
return add_space ? L" \"{}\"" : L"\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
return add_space ? " '{}'" : "'{}'";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
}
} // namespace internal
template <typename T>
struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char,
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private:
// C++11 generic lambda for format()
template <typename FormatContext>
struct format_each {
template <typename T>
void operator()(const T& v) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
template <typename T>
struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(
const RangeT &values, FormatContext &ctx) {
auto out = ctx.out();
internal::copy(formatting.prefix, out);
std::size_t i = 0;
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>");
break;
}
}
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

160
lib/include/fmt/time.h Normal file
View File

@ -0,0 +1,160 @@
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
#include <locale>
FMT_BEGIN_NAMESPACE
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace internal{
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
} // namespace internal
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher lt(time);
// Too big time values may be unsupported.
if (!lt.run())
FMT_THROW(format_error("time_t value out of range"));
return lt.tm_;
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher gt(time);
// Too big time values may be unsupported.
if (!gt.run())
FMT_THROW(format_error("time_t value out of range"));
return gt.tm_;
}
namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format,
const std::tm *time) {
return std::strftime(str, count, format, time);
}
inline std::size_t strftime(wchar_t *str, std::size_t count,
const wchar_t *format, const std::tm *time) {
return std::wcsftime(str, count, format, time);
}
}
template <typename Char>
struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
if (it != ctx.end() && *it == ':')
++it;
auto end = it;
while (end != ctx.end() && *end != '}')
++end;
tm_format.reserve(internal::to_unsigned(end - it + 1));
tm_format.append(it, end);
tm_format.push_back('\0');
return end;
}
template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buf;
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
std::size_t count =
internal::strftime(&buf[start], size, &tm_format[0], &tm);
if (count != 0) {
buf.resize(start + count);
break;
}
if (size >= tm_format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return std::copy(buf.begin(), buf.end(), ctx.out());
}
basic_memory_buffer<Char> tm_format;
};
FMT_END_NAMESPACE
#endif // FMT_TIME_H_

186
lib/include/mh/MinHook.h Normal file
View File

@ -0,0 +1,186 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
#error MinHook supports only x86 and x64 systems.
#endif
#include <windows.h>
// MinHook Error Codes.
typedef enum MH_STATUS
{
// Unknown error. Should not be returned.
MH_UNKNOWN = -1,
// Successful.
MH_OK = 0,
// MinHook is already initialized.
MH_ERROR_ALREADY_INITIALIZED,
// MinHook is not initialized yet, or already uninitialized.
MH_ERROR_NOT_INITIALIZED,
// The hook for the specified target function is already created.
MH_ERROR_ALREADY_CREATED,
// The hook for the specified target function is not created yet.
MH_ERROR_NOT_CREATED,
// The hook for the specified target function is already enabled.
MH_ERROR_ENABLED,
// The hook for the specified target function is not enabled yet, or already
// disabled.
MH_ERROR_DISABLED,
// The specified pointer is invalid. It points the address of non-allocated
// and/or non-executable region.
MH_ERROR_NOT_EXECUTABLE,
// The specified target function cannot be hooked.
MH_ERROR_UNSUPPORTED_FUNCTION,
// Failed to allocate memory.
MH_ERROR_MEMORY_ALLOC,
// Failed to change the memory protection.
MH_ERROR_MEMORY_PROTECT,
// The specified module is not loaded.
MH_ERROR_MODULE_NOT_FOUND,
// The specified function is not found.
MH_ERROR_FUNCTION_NOT_FOUND
}
MH_STATUS;
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
// MH_QueueEnableHook or MH_QueueDisableHook.
#define MH_ALL_HOOKS NULL
#ifdef __cplusplus
extern "C" {
#endif
// Initialize the MinHook library. You must call this function EXACTLY ONCE
// at the beginning of your program.
MH_STATUS WINAPI MH_Initialize(VOID);
// Uninitialize the MinHook library. You must call this function EXACTLY
// ONCE at the end of your program.
MH_STATUS WINAPI MH_Uninitialize(VOID);
// Creates a Hook for the specified target function, in disabled state.
// Parameters:
// pTarget [in] A pointer to the target function, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
// ppTarget [out] A pointer to the target function, which will be used
// with other functions.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
// Removes an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
// Enables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// enabled in one go.
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
// Disables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// disabled in one go.
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
// Queues to enable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be enabled.
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
// Queues to disable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be disabled.
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
// Applies all queued changes in one go.
MH_STATUS WINAPI MH_ApplyQueued(VOID);
// Translates the MH_STATUS to its name as a string.
const char * WINAPI MH_StatusToString(MH_STATUS status);
#ifdef __cplusplus
}
#endif

20406
lib/include/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

285
src/BigBaseV2.vcxproj Normal file
View File

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D436EE4E-DBF5-4B87-9715-A1C2774BC25F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>BigBaseV2</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(SolutionDir)bin\$(Configuration)\int\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
<IncludePath>C:\boost_1_69_0;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(SolutionDir)bin\$(Configuration)\int\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;BIGBASEV2_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<OmitFramePointers>false</OmitFramePointers>
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<StringPooling>true</StringPooling>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderFile>common.hpp</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)lib\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4307;4100;4201;</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<MapExports>true</MapExports>
<AdditionalLibraryDirectories>$(SolutionDir)lib\bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;MinHook/MinHook.lib;StackWalker/StackWalker.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;BIGBASEV2_RELEASE;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<StringPooling>true</StringPooling>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderFile>common.hpp</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)lib\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4307;4100;4201;</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<MapExports>true</MapExports>
<AdditionalLibraryDirectories>$(SolutionDir)lib\bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;MinHook/MinHook.lib;StackWalker/StackWalker.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="common.hpp" />
<ClInclude Include="crossmap.hpp" />
<ClInclude Include="detour_hook.hpp" />
<ClInclude Include="fiber_pool.hpp" />
<ClInclude Include="fonts.hpp" />
<ClInclude Include="function_types.hpp" />
<ClInclude Include="gta\array.hpp" />
<ClInclude Include="features.hpp" />
<ClInclude Include="gta\base.hpp" />
<ClInclude Include="gta\color.hpp" />
<ClInclude Include="gta\enums.hpp" />
<ClInclude Include="gta\extensible.hpp" />
<ClInclude Include="gta\fwddec.hpp" />
<ClInclude Include="gta\matrix.hpp" />
<ClInclude Include="gta\node_list.hpp" />
<ClInclude Include="gta\ped_factory.hpp" />
<ClInclude Include="gta\player.hpp" />
<ClInclude Include="gta\ref_aware.hpp" />
<ClInclude Include="gta\script_program.hpp" />
<ClInclude Include="gta\vector.hpp" />
<ClInclude Include="gta_util.hpp" />
<ClInclude Include="invoker.hpp" />
<ClInclude Include="gta\natives.hpp" />
<ClInclude Include="gta\joaat.hpp" />
<ClInclude Include="gta\net_game_event.hpp" />
<ClInclude Include="gta\script_handler.hpp" />
<ClInclude Include="gta\script_id.hpp" />
<ClInclude Include="gta\script_thread.hpp" />
<ClInclude Include="gta\tls_context.hpp" />
<ClInclude Include="gui.hpp" />
<ClInclude Include="hooking.hpp" />
<ClInclude Include="imgui\imconfig.h" />
<ClInclude Include="imgui\imgui.h" />
<ClInclude Include="imgui\imgui_impl_dx11.h" />
<ClInclude Include="imgui\imgui_impl_win32.h" />
<ClInclude Include="imgui\imgui_internal.h" />
<ClInclude Include="imgui\imstb_rectpack.h" />
<ClInclude Include="imgui\imstb_textedit.h" />
<ClInclude Include="imgui\imstb_truetype.h" />
<ClInclude Include="logger.hpp" />
<ClInclude Include="memory\fwddec.hpp" />
<ClInclude Include="memory\handle.hpp" />
<ClInclude Include="memory\all.hpp" />
<ClInclude Include="memory\module.hpp" />
<ClInclude Include="memory\pattern.hpp" />
<ClInclude Include="memory\pattern_batch.hpp" />
<ClInclude Include="memory\range.hpp" />
<ClInclude Include="natives.hpp" />
<ClInclude Include="pointers.hpp" />
<ClInclude Include="renderer.hpp" />
<ClInclude Include="script.hpp" />
<ClInclude Include="script_global.hpp" />
<ClInclude Include="script_hook.hpp" />
<ClInclude Include="script_mgr.hpp" />
<ClInclude Include="vmt_hook.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="detour_hook.cpp" />
<ClCompile Include="features.cpp" />
<ClCompile Include="fiber_pool.cpp" />
<ClCompile Include="fonts.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="invoker.cpp" />
<ClCompile Include="gui.cpp" />
<ClCompile Include="hooking.cpp" />
<ClCompile Include="imgui\imgui.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="imgui\imgui_demo.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="imgui\imgui_draw.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="imgui\imgui_impl_dx11.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="imgui\imgui_impl_win32.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="imgui\imgui_widgets.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="common.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="memory\module.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../common.hpp</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../common.hpp</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="memory\pattern.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="memory\pattern_batch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="memory\range.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeaderFile>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="pointers.cpp" />
<ClCompile Include="renderer.cpp" />
<ClCompile Include="script.cpp" />
<ClCompile Include="script_global.cpp" />
<ClCompile Include="script_hook.cpp" />
<ClCompile Include="script_mgr.cpp" />
<ClCompile Include="vmt_hook.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="common.hpp" />
<ClInclude Include="logger.hpp" />
<ClInclude Include="pointers.hpp" />
<ClInclude Include="memory\fwddec.hpp" />
<ClInclude Include="memory\handle.hpp" />
<ClInclude Include="memory\module.hpp" />
<ClInclude Include="memory\pattern.hpp" />
<ClInclude Include="memory\pattern_batch.hpp" />
<ClInclude Include="memory\range.hpp" />
<ClInclude Include="memory\all.hpp" />
<ClInclude Include="imgui\imconfig.h" />
<ClInclude Include="imgui\imgui.h" />
<ClInclude Include="imgui\imgui_impl_dx11.h" />
<ClInclude Include="imgui\imgui_impl_win32.h" />
<ClInclude Include="imgui\imgui_internal.h" />
<ClInclude Include="imgui\imstb_rectpack.h" />
<ClInclude Include="imgui\imstb_textedit.h" />
<ClInclude Include="imgui\imstb_truetype.h" />
<ClInclude Include="renderer.hpp" />
<ClInclude Include="gui.hpp" />
<ClInclude Include="detour_hook.hpp" />
<ClInclude Include="script.hpp" />
<ClInclude Include="script_mgr.hpp" />
<ClInclude Include="function_types.hpp" />
<ClInclude Include="gta\fwddec.hpp" />
<ClInclude Include="gta\script_thread.hpp" />
<ClInclude Include="gta\tls_context.hpp" />
<ClInclude Include="gta\array.hpp" />
<ClInclude Include="gta\script_handler.hpp" />
<ClInclude Include="gta\script_id.hpp" />
<ClInclude Include="gta\net_game_event.hpp" />
<ClInclude Include="gta\joaat.hpp" />
<ClInclude Include="features.hpp" />
<ClInclude Include="gta\enums.hpp" />
<ClInclude Include="gta\natives.hpp" />
<ClInclude Include="invoker.hpp" />
<ClInclude Include="crossmap.hpp" />
<ClInclude Include="natives.hpp" />
<ClInclude Include="gta\vector.hpp" />
<ClInclude Include="gta\color.hpp" />
<ClInclude Include="vmt_hook.hpp" />
<ClInclude Include="fonts.hpp" />
<ClInclude Include="gta\ref_aware.hpp" />
<ClInclude Include="gta\base.hpp" />
<ClInclude Include="gta\matrix.hpp" />
<ClInclude Include="fiber_pool.hpp" />
<ClInclude Include="script_global.hpp" />
<ClInclude Include="gta\node_list.hpp" />
<ClInclude Include="hooking.hpp" />
<ClInclude Include="gta_util.hpp" />
<ClInclude Include="gta\player.hpp" />
<ClInclude Include="script_hook.hpp" />
<ClInclude Include="gta\script_program.hpp" />
<ClInclude Include="gta\ped_factory.hpp" />
<ClInclude Include="gta\extensible.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="common.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="hooking.cpp" />
<ClCompile Include="pointers.cpp" />
<ClCompile Include="memory\module.cpp" />
<ClCompile Include="memory\pattern.cpp" />
<ClCompile Include="memory\pattern_batch.cpp" />
<ClCompile Include="memory\range.cpp" />
<ClCompile Include="imgui\imgui.cpp" />
<ClCompile Include="imgui\imgui_demo.cpp" />
<ClCompile Include="imgui\imgui_draw.cpp" />
<ClCompile Include="imgui\imgui_impl_dx11.cpp" />
<ClCompile Include="imgui\imgui_impl_win32.cpp" />
<ClCompile Include="imgui\imgui_widgets.cpp" />
<ClCompile Include="renderer.cpp" />
<ClCompile Include="gui.cpp" />
<ClCompile Include="detour_hook.cpp" />
<ClCompile Include="script.cpp" />
<ClCompile Include="script_mgr.cpp" />
<ClCompile Include="features.cpp" />
<ClCompile Include="invoker.cpp" />
<ClCompile Include="vmt_hook.cpp" />
<ClCompile Include="fonts.cpp" />
<ClCompile Include="fiber_pool.cpp" />
<ClCompile Include="script_global.cpp" />
<ClCompile Include="script_hook.cpp" />
</ItemGroup>
</Project>

1
src/common.cpp Normal file
View File

@ -0,0 +1 @@
#include "common.hpp"

85
src/common.hpp Normal file
View File

@ -0,0 +1,85 @@
#pragma once
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0601
#include <SDKDDKVer.h>
#include <Windows.h>
#include <D3D11.h>
#include <wrl/client.h>
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <chrono>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <atomic>
#include <mutex>
#include <thread>
#include <memory>
#include <new>
#include <sstream>
#include <string>
#include <string_view>
#include <algorithm>
#include <functional>
#include <utility>
#include <stack>
#include <vector>
#include <typeinfo>
#include <type_traits>
#include <exception>
#include <stdexcept>
#include <any>
#include <optional>
#include <variant>
#define FMT_HEADER_ONLY
#include <cpptoml/cpptoml.h>
#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include <StackWalker/StackWalker.h>
#include "logger.hpp"
namespace big
{
using namespace std::chrono_literals;
template <typename T>
using comptr = Microsoft::WRL::ComPtr<T>;
inline HMODULE g_hmodule{};
inline HANDLE g_main_thread{};
inline DWORD g_main_thread_id{};
inline std::atomic_bool g_running{ true };
struct stackwalker : public StackWalker
{
using StackWalker::StackWalker;
void OnOutput(LPCSTR szText) override
{
g_logger->raw(log_color::red, szText);
}
};
inline stackwalker g_stackwalker;
}

5846
src/crossmap.hpp Normal file

File diff suppressed because it is too large Load Diff

88
src/detour_hook.cpp Normal file
View File

@ -0,0 +1,88 @@
#include "common.hpp"
#include "detour_hook.hpp"
#include "logger.hpp"
#include "memory/handle.hpp"
#include <mh/MinHook.h>
namespace big
{
detour_hook::detour_hook(std::string name, void *target, void *detour) :
m_name(std::move(name)),
m_target(target),
m_detour(detour)
{
fix_hook_address();
if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status == MH_OK)
{
LOG_INFO("Created hook '{}'.", m_name);
}
else
{
throw std::runtime_error(fmt::format("Failed to create hook '{}' at 0x{:X} (error: {})", m_name, reinterpret_cast<std::uintptr_t>(m_target), MH_StatusToString(status)));
}
}
detour_hook::~detour_hook() noexcept
{
if (m_target)
{
MH_RemoveHook(m_target);
}
LOG_INFO("Removed hook '{}',", m_name);
}
void detour_hook::enable()
{
if (auto status = MH_EnableHook(m_target); status == MH_OK)
{
LOG_INFO("Enabled hook '{}'.", m_name);
}
else
{
throw std::runtime_error(fmt::format("Failed to enable hook 0x{:X} ({})", reinterpret_cast<std::uintptr_t>(m_target), MH_StatusToString(status)));
}
}
void detour_hook::disable()
{
if (auto status = MH_DisableHook(m_target); status == MH_OK)
{
LOG_INFO("Disabled hook '{}'", m_name);
}
else
{
LOG_ERROR("Failed to disable hook '{}'.", m_name);
}
}
DWORD exp_handler(PEXCEPTION_POINTERS exp, std::string const &name)
{
return exp->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH;
}
void detour_hook::fix_hook_address()
{
__try
{
auto ptr = memory::handle(m_target);
while (ptr.as<std::uint8_t&>() == 0xE9)
{
ptr = ptr.add(1).rip();
}
m_target = ptr.as<void*>();
}
__except (exp_handler(GetExceptionInformation(), m_name))
{
[this]()
{
throw std::runtime_error(fmt::format("Failed to fix hook address for '{}'", m_name));
}();
}
}
}

35
src/detour_hook.hpp Normal file
View File

@ -0,0 +1,35 @@
#pragma once
namespace big
{
class detour_hook
{
public:
explicit detour_hook(std::string name, void *target, void *detour);
~detour_hook() noexcept;
detour_hook(detour_hook&& that) = delete;
detour_hook& operator=(detour_hook&& that) = delete;
detour_hook(detour_hook const&) = delete;
detour_hook& operator=(detour_hook const&) = delete;
void enable();
void disable();
template <typename T>
T get_original();
void fix_hook_address();
private:
std::string m_name;
void *m_target;
void *m_detour;
void *m_original{};
};
template <typename T>
inline T detour_hook::get_original()
{
return static_cast<T>(m_original);
}
}

21
src/features.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "common.hpp"
#include "features.hpp"
#include "logger.hpp"
#include "natives.hpp"
#include "script.hpp"
namespace big
{
void features::run_tick()
{
}
void features::script_func()
{
while (true)
{
run_tick();
script::get_current()->yield();
}
}
}

8
src/features.hpp Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "common.hpp"
namespace big::features
{
void run_tick();
void script_func();
}

53
src/fiber_pool.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "common.hpp"
#include "fiber_pool.hpp"
#include "script.hpp"
#include "script_mgr.hpp"
namespace big
{
fiber_pool::fiber_pool(std::size_t num_fibers)
{
for (std::size_t i = 0; i < num_fibers; ++i)
{
g_script_mgr.add_script(std::make_unique<script>(&fiber_func));
}
g_fiber_pool = this;
}
fiber_pool::~fiber_pool()
{
g_fiber_pool = nullptr;
}
void fiber_pool::queue_job(std::function<void()> func)
{
if (func)
{
std::lock_guard lock(m_mutex);
m_jobs.push(std::move(func));
}
}
void fiber_pool::fiber_tick()
{
std::unique_lock lock(m_mutex);
if (!m_jobs.empty())
{
auto job = std::move(m_jobs.top());
m_jobs.pop();
lock.unlock();
std::invoke(std::move(job));
}
}
void fiber_pool::fiber_func()
{
while (true)
{
g_fiber_pool->fiber_tick();
script::get_current()->yield();
}
}
}

22
src/fiber_pool.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "common.hpp"
namespace big
{
class fiber_pool
{
public:
explicit fiber_pool(std::size_t num_fibers);
~fiber_pool();
void queue_job(std::function<void()> func);
void fiber_tick();
static void fiber_func();
private:
std::recursive_mutex m_mutex;
std::stack<std::function<void()>> m_jobs;
};
inline fiber_pool *g_fiber_pool{};
}

11734
src/fonts.cpp Normal file

File diff suppressed because it is too large Load Diff

4
src/fonts.hpp Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#include <cstdint>
extern const std::uint8_t font_rubik[140732];

11
src/function_types.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "common.hpp"
#include "gta/fwddec.hpp"
#include "gta/natives.hpp"
namespace big::functions
{
using run_script_threads_t = bool(*)(std::uint32_t ops_to_execute);
using get_native_handler_t = rage::scrNativeHandler(*)(rage::scrNativeRegistrationTable*, rage::scrNativeHash);
using fix_vectors_t = void(*)(rage::scrNativeCallContext*);
}

65
src/gta/array.hpp Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
namespace rage
{
template <typename T>
class atArray
{
public:
T *begin()
{
return m_data;
}
T *end()
{
return m_data + m_size;
}
const T *begin() const
{
return m_data;
}
const T *end() const
{
return m_data + m_size;
}
T *data()
{
return m_data;
}
const T *data() const
{
return m_data;
}
std::uint16_t size() const
{
return m_size;
}
std::uint16_t capacity() const
{
return m_capacity;
}
T &operator[](std::uint16_t index)
{
return m_data[index];
}
const T &operator[](std::uint16_t index) const
{
return m_data[index];
}
private:
T *m_data;
std::uint16_t m_size;
std::uint16_t m_capacity;
};
}

18
src/gta/base.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
namespace rage
{
class datBase
{
public:
virtual ~datBase() = default;
};
class pgBase
{
public:
virtual ~pgBase() = default;
private:
void *m_pgunk;
};
}

19
src/gta/color.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
namespace rage
{
struct rgbaColor
{
rgbaColor(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0, std::uint8_t a = 255) :
r(r), g(g), b(b), a(a)
{}
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
std::uint8_t a;
};
static_assert(sizeof(rgbaColor) == sizeof(std::uint8_t) * 4);
}

7
src/gta/enums.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <cstdint>
enum eGameState : std::uint32_t
{
Playing = 0
};

44
src/gta/extensible.hpp Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <cstdint>
#include "ref_aware.hpp"
namespace rage
{
class fwExtension
{
public:
virtual ~fwExtension() = default;
virtual void unk_0x08() = 0;
virtual void unk_0x10() = 0;
virtual std::uint32_t get_id() = 0;
};
class fwExtensionContainer
{
public:
fwExtension *m_entry;
fwExtensionContainer* m_next;
};
class fwExtensibleBase : public fwRefAwareBase
{
public:
virtual bool is_of_type(std::uint32_t hash) = 0;
virtual std::uint32_t const &get_type() = 0;
public:
fwExtensionContainer* m_extension_container; // 0x10
private:
void *m_extensible_unk; // 0x18
public:
template <typename T>
bool is_of_type()
{
static auto name = (typeid(T).name()) + 6; // Skip "class "
static auto name_hash = util::joaat(name);
return is_of_type(name_hash);
}
};
static_assert(sizeof(fwExtensibleBase) == 0x20);
}

68
src/gta/fwddec.hpp Normal file
View File

@ -0,0 +1,68 @@
#pragma once
namespace rage
{
template <typename T>
class atArray;
class datBitBuffer;
class sysMemAllocator;
class scriptIdBase;
class scriptId;
class scriptHandler;
class scriptHandlerNetComponent;
class scriptHandlerObject;
class scriptHandlerMgr;
class scrProgram;
class scrProgramTable;
class scrThreadContext;
class scrThread;
class tlsContext;
class netLoggingInterface;
class netLogStub;
class netPlayer;
class netPlayerMgr;
class netGameEvent;
class netEventMgr;
class netObject;
class netObjectMgrBase;
class scrNativeCallContext;
class scrNativeRegistration;
class scrNativeRegistrationTable;
class fwRefAwareBase;
class fwExtensibleBase;
class fwEntity;
class fwArchetype;
}
class GtaThread;
class CGameScriptId;
class CGameScriptHandler;
class CGameScriptHandlerNetwork;
class CGameScriptHandlerMgr;
class CEntity;
class CDynamicEntity;
class CPhysical;
class CPed;
class CVehicle;
class CObject;
class CPickup;
class CPedFactory;
class CVehicleFactory;
class CNetGamePlayer;
class CNetworkPlayerMgr;
class CPlayerInfo;

84
src/gta/joaat.hpp Normal file
View File

@ -0,0 +1,84 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string_view>
#include <type_traits>
namespace rage
{
using joaat_t = std::uint32_t;
inline constexpr char joaat_to_lower(char c)
{
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
}
template <std::size_t CharCount>
struct constexpr_joaat
{
char data[CharCount];
template <std::size_t... Indices>
constexpr constexpr_joaat(const char *str, std::index_sequence<Indices...>) :
data{ (str[Indices])... }
{
}
constexpr joaat_t operator()()
{
joaat_t hash = 0;
for (std::size_t i = 0; i < CharCount; ++i)
{
hash += joaat_to_lower(data[i]);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
};
inline joaat_t joaat(std::string_view str)
{
joaat_t hash = 0;
for (char c : str)
{
hash += joaat_to_lower(c);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
inline joaat_t joaat(const char *str)
{
joaat_t hash = 0;
while (*str)
{
hash += joaat_to_lower(*(str++));
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
}
#define RAGE_JOAAT_IMPL(str) (::rage::constexpr_joaat<sizeof(str) - 1>((str), std::make_index_sequence<sizeof(str) - 1>())())
#define RAGE_JOAAT(str) (std::integral_constant<rage::joaat_t, RAGE_JOAAT_IMPL(str)>::value)

22
src/gta/matrix.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "vector.hpp"
namespace rage
{
class matrix4x4
{
public:
union
{
struct
{
vector4 _1;
vector4 _2;
vector4 _3;
vector4 _4;
};
float raw[4 * 4] = {};
};
};
}

89
src/gta/natives.hpp Normal file
View File

@ -0,0 +1,89 @@
#pragma once
#include <cstdint>
#include <utility>
#include "fwddec.hpp"
#include "vector.hpp"
namespace rage
{
class scrNativeCallContext
{
public:
void reset()
{
m_arg_count = 0;
m_data_count = 0;
}
template <typename T>
void push_arg(T &&value)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(reinterpret_cast<std::uint64_t*>(m_args) + (m_arg_count++)) = std::forward<T>(value);
}
template <typename T>
T &get_arg(std::size_t index)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
return *reinterpret_cast<T*>(reinterpret_cast<std::uint64_t*>(m_args) + index);
}
template <typename T>
void set_arg(std::size_t index, T &&value)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(reinterpret_cast<std::uint64_t*>(m_args) + index) = std::forward<T>(value);
}
template <typename T>
T *get_return_value()
{
return reinterpret_cast<T*>(m_return_value);
}
template <typename T>
void set_return_value(T &&value)
{
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(m_return_value) = std::forward<T>(value);
}
protected:
void *m_return_value;
std::uint32_t m_arg_count;
void *m_args;
std::int32_t m_data_count;
std::uint32_t m_data[48];
};
using scrNativeHash = std::uint64_t;
using scrNativeMapping = std::pair<scrNativeHash, scrNativeHash>;
using scrNativeHandler = void(*)(scrNativeCallContext*);
class scrNativeRegistration;
#pragma pack(push, 1)
class scrNativeRegistrationTable
{
scrNativeRegistration *m_entries[0xFF];
std::uint32_t m_unk;
bool m_initialized;
};
#pragma pack(pop)
static_assert(sizeof(scrNativeCallContext) == 0xE0);
}
using Void = void;
using Any = std::uint32_t;
using Hash = std::uint32_t;
using Entity = std::int32_t;
using Player = std::int32_t;
using Ped = Entity;
using Vehicle = Entity;
using Cam = std::int32_t;
using Object = Entity;
using Pickup = Object;
using Blip = std::int32_t;
using Camera = Entity;
using ScrHandle = Entity;
using Vector3 = rage::scrVector;

View File

@ -0,0 +1,58 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#pragma pack(push, 1)
namespace rage
{
class netGameEvent
{
public:
virtual ~netGameEvent() = default;
virtual const char *get_name() const = 0;
virtual bool is_applicable_to_player(netPlayer *player) = 0;
virtual bool time_to_resend(std::uint32_t time) = 0;
virtual bool needs_reply() = 0;
virtual void serialize(datBitBuffer *buffer, netPlayer* source_player, netPlayer* target_player) = 0;
virtual void deserialize(datBitBuffer *buffer, netPlayer* source_player, netPlayer* target_player) = 0;
virtual bool handle(netPlayer* source_player, netPlayer* target_player) = 0;
virtual void deserialize_reply(datBitBuffer *buffer, netPlayer* reply_player) = 0;
virtual void serialize_reply(datBitBuffer *buffer, netPlayer* souce_player) = 0;
virtual void deserialize_extra_data(datBitBuffer *buffer, bool is_reply, netPlayer *player, netPlayer *player2) = 0;
virtual void serialize_extra_data(datBitBuffer *buffer, bool is_reply, netPlayer *player, netPlayer *player2) = 0;
virtual void _0x60() = 0;
virtual void _0x68() = 0;
virtual void _0x70() = 0;
virtual void _0x78() = 0;
virtual bool operator==(netGameEvent const& other) = 0;
virtual bool operator!=(netGameEvent const& other) = 0;
virtual bool must_persist() = 0;
virtual bool must_persist_when_out_of_scope() = 0;
virtual bool has_timed_out() = 0;
public:
std::uint16_t m_id; // 0x08
bool m_requires_reply; // 0x0A
private:
char m_padding1[0x05]; // 0x0B
public:
netPlayer* m_source_player; // 0x10
netPlayer* m_target_player; // 0x18
std::uint32_t m_resend_time; // 0x20
std::uint16_t m_0x24; // 0x24
std::uint8_t m_0x26; // 0x26
std::uint8_t m_0x27; // 0x27
std::uint32_t m_0x28; // 0x28
char m_padding2[0x04]; // 0x2C
};
static_assert(sizeof(netGameEvent) == 0x30);
}
#pragma pack(pop)

23
src/gta/node_list.hpp Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "fwddec.hpp"
#include "base.hpp"
namespace rage
{
template <typename T, typename Base = datBase>
class atDNode : public Base
{
public:
T m_data;
void *m_unk;
atDNode<T, Base> *m_next;
};
template <typename Node>
class atDList
{
public:
Node *m_head;
Node *m_tail;
};
}

18
src/gta/ped_factory.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "fwddec.hpp"
#pragma pack(push, 1)
class CPed
{
public:
char m_padding[0x10B8];
CPlayerInfo *m_playerinfo;
};
#pragma pack(pop)
class CPedFactory
{
public:
virtual ~CPedFactory() = default;
CPed *m_local_ped;
};

112
src/gta/player.hpp Normal file
View File

@ -0,0 +1,112 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#include "extensible.hpp"
#include "vector.hpp"
#pragma pack(push, 1)
namespace rage
{
# pragma warning(push)
# pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
union netAddress
{
std::uint32_t m_raw;
struct
{
std::uint8_t m_field4;
std::uint8_t m_field3;
std::uint8_t m_field2;
std::uint8_t m_field1;
};
};
# pragma warning(pop)
class netPlayerData
{
public:
std::uint64_t m_unk1; // 0x00
std::uint64_t m_unk2; // 0x08
std::uint32_t m_sec_key_time; // 0x10
netAddress m_lan_ip; // 0x14
std::uint16_t m_lan_port; // 0x18
char m_pad1[0x02]; // 0x1A
netAddress m_relay_ip; // 0x1C
std::uint16_t m_relay_port; // 0x20
char m_pad2[0x02]; // 0x22
netAddress m_online_ip; // 0x24
std::uint16_t m_online_port; // 0x26
char m_pad3[0x1E]; // 0x28
std::uint64_t m_rockstar_id; // 0x48
bool m_id_flag; // 0x50
char m_pad4[0x0B]; // 0x51
char m_name[0x14]; // 0x5C
};
class nonPhysicalPlayerDataBase
{
public:
virtual ~nonPhysicalPlayerDataBase() = default; // 0 (0x00)
virtual void unk_0x08() = 0; // 1 (0x08)
virtual void unk_0x10() = 0; // 2 (0x10)
virtual void unk_0x18() = 0; // 3 (0x18)
virtual void log(netLoggingInterface* logger) = 0; // 4 (0x20)
};
class netPlayer
{
public:
virtual ~netPlayer() = default; // 0 (0x00)
virtual void reset() = 0; // 1 (0x08)
virtual bool is_valid() const = 0; // 2 (0x10)
virtual const char *get_name() const = 0; // 3 (0x18)
virtual void _0x20() = 0; // 4 (0x20)
virtual bool is_host() = 0; // 5 (0x28)
virtual netPlayerData *get_net_data() = 0; // 6 (0x30)
virtual void _0x38() = 0; // 7 (0x38)
};
class netPlayerMgrBase
{
public:
virtual ~netPlayerMgrBase() = default; // 0 (0x00)
};
}
namespace gta
{
inline constexpr auto num_players = 32;
}
class CNonPhysicalPlayerData : public rage::nonPhysicalPlayerDataBase
{
public:
std::int32_t m_bubble_id; // 0x08
std::int32_t m_player_id; // 0x0C
rage::vector3 m_position; // 0x10
};
class CNetGamePlayer : public rage::netPlayer
{
public:
};
class CWantedData
{
public:
char m_padding[0x98];
std::int32_t m_wanted_level;
};
class CPlayerInfo : public rage::fwExtensibleBase
{
public:
char m_padding1[0x1D8]; // 0x20
std::uint32_t m_frame_flags; // 0x1F8
char m_padding2[0x584]; // 0x1FC
CWantedData m_wanted_data; // 0x780
};
static_assert(sizeof(CNonPhysicalPlayerData) == 0x1C);
#pragma pack(pop)

18
src/gta/ref_aware.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "base.hpp"
namespace rage
{
template <typename T>
class fwRefAwareBaseImpl : public T
{
private:
void *m_ref; // 0x08
};
class fwRefAwareBase : public fwRefAwareBaseImpl<datBase>
{
};
static_assert(sizeof(fwRefAwareBase) == 0x10);
}

185
src/gta/script_handler.hpp Normal file
View File

@ -0,0 +1,185 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#include "node_list.hpp"
#include "script_id.hpp"
#pragma pack(push, 1)
namespace rage
{
class scriptResource
{
public:
virtual ~scriptResource() = default;
};
class scriptResourceEntry
{
public:
scriptResource *m_data; // 0x00
std::uint32_t m_unk; // 0x04
char m_padding[0x0C]; // 0x0C
scriptResourceEntry *m_next; // 0x18
};
class scriptHandlerNetComponent
{
public:
virtual ~scriptHandlerNetComponent() = default;
public:
scriptHandler *m_script_handler; // 0x08
};
class scriptHandler
{
public:
class atDScriptObjectNode : public atDNode<scriptHandlerObject*>
{
};
public:
virtual ~scriptHandler() = default; // 0 (0x00)
virtual bool _0x08() = 0; // 1 (0x08)
virtual void _0x10() = 0; // 2 (0x10)
virtual void cleanup_objects() = 0; // 3 (0x18)
virtual scriptId *_0x20() = 0; // 4 (0x20)
virtual scriptId *get_id() = 0; // 5 (0x28)
// Returns whether the script handler belongs to a networked script.
virtual bool is_networked() = 0; // 6 (0x30)
// Initializes the network component for the script handler.
virtual void init_net_component() = 0; // 7 (0x38)
// Deletes the script handler's network component, if it exists.
virtual void reset_net_component() = 0; // 8 (0x40)
// Destroys the script handler.
virtual bool destroy() = 0; // 9 (0x48)
// Adds the object to the script handler's list of objects.
virtual void add_object(scriptHandlerObject*, bool is_network, bool is_network_and_scriptcheck) = 0; // 10 (0x50)
// Something related to reservations.
virtual void _0x58(void*) = 0; // 11 (0x58)
virtual void register_resource(scriptResource*, void*) = 0; // 12 (0x60)
virtual void _0x68() = 0; // 13 (0x68)
virtual void _0x70() = 0; // 14 (0x70)
virtual void _0x78() = 0; // 15 (0x78)
virtual void _0x80() = 0; // 16 (0x80)
virtual void _0x88() = 0; // 17 (0x88)
virtual void _0x90() = 0; // 18 (0x90)
virtual void _0x98() = 0; // 19 (0x98)
public:
void *m_0x08; // 0x08
void *m_0x10; // 0x10
scrThread *m_script_thread; // 0x18
atDList<atDScriptObjectNode> m_objects; // 0x20
scriptResource *m_resource_list_head; // 0x30
scriptResource *m_resource_list_tail; // 0x38
void *m_0x40; // 0x40
scriptHandlerNetComponent *m_net_component; // 0x48
std::uint32_t m_0x50; // 0x50
std::uint32_t m_0x54; // 0x54
std::uint32_t m_0x58; // 0x58
std::uint32_t m_0x60; // 0x5C
};
class scriptHandlerMgr
{
public:
virtual ~scriptHandlerMgr() = default;
// Initializes some scripting-related pools.
virtual bool initialize() = 0; // 1 (0x08)
// Called every tick.
virtual void _0x10() = 0; // 2 (0x10)
// Frees some scripting-related pools.
virtual void shutdown() = 0; // 3 (0x18)
virtual void _0x20() = 0; // 4 (0x20)
virtual void _0x28() = 0; // 5 (0x28)
virtual void _0x30() = 0; // 6 (0x30)
// Generates a rage::scriptId from the thread and copies it over to a global structure.
virtual void _0x38(scrThread*) = 0; // 7 (0x38)
// Allocates and constructs a script handler.
virtual scriptHandler *create_script_handler() = 0; // 8 (0x40)
// Finds the script handler for a given script id.
virtual scriptHandler *get_script_handler(scriptId*) = 0; // 9 (0x48)
// Attaches a script thread.
virtual void attach_thread(scrThread*) = 0; // 10 (0x50)
// Detaches a script thread.
virtual void detach_thread(scrThread*) = 0; // 11 (0x58)
// Called when a player joins.
virtual void on_player_join(netPlayer*) = 0; // 12 (0x60)
// Called when a player leaves.
virtual void on_player_left(netPlayer*) = 0; // 13 (0x68)
virtual std::int32_t _0x70() = 0; // 14 (0x70)
virtual void *_0x78() = 0; // 15 (0x78)
public:
char m_padding1[0x28]; // 0x08
bool m_initialized; // 0x30
bool m_initialized2; // 0x31
char m_padding2[0x0E]; // 0x32
rage::netLoggingInterface *m_logger; // 0x40
};
}
class CGameScriptHandler : public rage::scriptHandler
{
public:
CGameScriptId m_script_id; // 0x60
};
class CGameScriptHandlerNetwork : public CGameScriptHandler
{
public:
std::uint8_t m_0xA0; // 0xA0
std::uint8_t m_0xA1; // 0xA1
std::uint8_t m_0xA2; // 0xA2
std::uint8_t m_0xA3; // 0xA3
std::uint8_t m_num_players; // 0xA4
std::uint8_t m_0xA5; // 0xA5
std::uint8_t m_0xA6; // 0xA6
std::uint8_t m_0xA7; // 0xA7
std::uint8_t m_0xA8; // 0xA8
std::uint8_t m_0xA9; // 0xA9
std::uint8_t m_0xAA; // 0xAA
std::uint8_t m_0xAB; // 0xAB
std::uint8_t m_0xAC; // 0xAC
std::uint8_t m_0xAD; // 0xAD
std::uint8_t m_0xAE; // 0xAE
std::uint8_t m_0xAF; // 0xAF
};
class CGameScriptHandlerMgr : public rage::scriptHandlerMgr
{
};
static_assert(sizeof(rage::scriptHandler) == 0x60);
static_assert(sizeof(CGameScriptHandler) == 0xA0);
static_assert(sizeof(CGameScriptHandlerNetwork) == 0xB0);
#pragma pack(pop)

72
src/gta/script_id.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#include "joaat.hpp"
#pragma pack(push, 1)
namespace rage
{
class scriptIdBase
{
public:
virtual ~scriptIdBase() = default; // 0 (0x00)
// Assumes the script thread's identity.
virtual void assume_thread_identity(scrThread*) {}; // 1 (0x08)
// Returns whether the hash of the script id is valid.
virtual bool is_valid() {}; // 2 (0x10)
// Gets the hash of the script id.
virtual joaat_t *get_hash(joaat_t *out) {}; // 3 (0x18)
// Gets an unknown value from the script id.
virtual std::uint32_t *get_hash2(std::uint32_t *out) {}; // 4 (0x20)
// Gets the name of the script id.
virtual const char *get_name() {}; // 5 (0x28)
// Serializes the script id from the buffer.
virtual void deserialize(datBitBuffer* buffer) {}; // 6 (0x30)
// Serializes the script id to the buffer.
virtual void serialize(datBitBuffer* buffer) {}; // 7 (0x38)
// Calculates some information with the position hash & instance id.
virtual std::uint32_t _0x40() {}; // 8 (0x40)
// Calls _0x40 and returns it's value added to another value.
virtual std::uint32_t _0x48() {}; // 9 (0x48)
// Logs some information about the script id.
virtual void log_information(netLoggingInterface* logger) {}; // 10 (0x50)
// Copies the information of other to this object.
virtual void copy_data(scriptIdBase *other) {} // 11 (0x58)
// Returns whether the other script id is equal.
virtual bool operator==(scriptIdBase*) {}; // 12 (0x60)
virtual bool _0x68(void*) {}; // 13 (0x68)
};
class scriptId : public scriptIdBase
{
public:
joaat_t m_hash; // 0x08
char m_name[0x20]; // 0x0C
};
}
class CGameScriptId : public rage::scriptId
{
public:
char m_padding[0x04]; // 0x2C
std::int32_t m_timestamp; // 0x30
std::int32_t m_position_hash; // 0x34
std::int32_t m_instance_id; // 0x38
std::int32_t m_unk; // 0x3C
};
static_assert(sizeof(CGameScriptId) == 0x40);
#pragma pack(pop)

145
src/gta/script_program.hpp Normal file
View File

@ -0,0 +1,145 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#include "base.hpp"
#include "joaat.hpp"
#include "script_id.hpp"
#pragma pack(push, 1)
namespace rage
{
class scrProgram : public pgBase
{
public:
std::uint8_t** m_code_blocks; // 0x10
std::uint32_t m_hash; // 0x18
std::uint32_t m_code_size; // 0x1C
std::uint32_t m_arg_count; // 0x20
std::uint32_t m_local_count; // 0x24
std::uint32_t m_global_count; // 0x28
std::uint32_t m_native_count; // 0x2C
void *m_local_data; // 0x30
std::int64_t **m_global_data; // 0x38
void **m_native_entrypoints; // 0x40
char m_padding6[0x10]; // 0x48
std::uint32_t m_name_hash; // 0x58
char m_padding7[0x04]; // 0x5C
const char* m_name; // 0x60
const char** m_strings_data; // 0x68
std::uint32_t m_strings_count; // 0x70
char m_padding8[0x0C]; // 0x74
bool is_valid() const
{
return m_code_size != 0;
}
std::uint32_t get_num_code_pages() const
{
return (m_code_size + 0x3FFF) >> 14;
}
std::uint32_t get_code_page_size(std::uint32_t page) const
{
auto num = get_num_code_pages();
if (page < num)
{
if (page == num - 1)
return m_code_size & 0x3FFF;
return 0x4000;
}
return 0;
}
std::uint32_t get_full_code_size() const
{
auto numPages = get_num_code_pages();
if (!numPages)
return 0;
if (numPages == 1)
--numPages;
return (numPages * 0x4000) + (m_code_size & 0x3FFF);
}
std::uint8_t* get_code_page(std::uint32_t page) const
{
return m_code_blocks[page];
}
std::uint8_t* get_code_address(std::uint32_t index) const
{
if (index < m_code_size)
return &m_code_blocks[index >> 14][index & 0x3FFF];
return nullptr;
}
const char* get_string(std::uint32_t index) const
{
if (index < m_strings_count)
return &m_strings_data[index >> 14][index & 0x3FFF];
return nullptr;
}
void** get_address_of_native_entrypoint(void* entrypoint)
{
for (std::uint32_t i = 0; i < m_native_count; ++i)
{
if (m_native_entrypoints[i] == entrypoint)
{
return m_native_entrypoints + i;
}
}
return nullptr;
}
};
class scrProgramTableEntry
{
public:
scrProgram* m_program; // 0x00
char m_Pad1[0x04]; // 0x08
joaat_t m_hash; // 0x0C
};
class scrProgramTable
{
public:
scrProgramTableEntry* m_data; // 0x00
char m_padding[0x10]; // 0x08
std::uint32_t m_size; // 0x18
scrProgram* find_script(joaat_t hash)
{
for (std::uint32_t i = 0; i < m_size; ++i)
{
if (m_data[i].m_hash == hash)
{
return m_data[i].m_program;
}
}
return nullptr;
}
scrProgramTableEntry* begin()
{
return m_data;
}
scrProgramTableEntry* end()
{
return m_data + m_size;
}
};
static_assert(sizeof(scrProgram) == 0x80);
static_assert(sizeof(scrProgramTableEntry) == 0x10);
static_assert(sizeof(scrProgramTable) == 0x1C);
}
#pragma pack(pop)

83
src/gta/script_thread.hpp Normal file
View File

@ -0,0 +1,83 @@
#pragma once
#include <cstdint>
#include "fwddec.hpp"
#include "joaat.hpp"
#include "tls_context.hpp"
namespace rage
{
enum class eThreadState : std::uint32_t
{
idle,
running,
killed,
unk_3,
unk_4,
};
class scrThreadContext
{
public:
std::uint32_t m_thread_id; // 0x00
joaat_t m_script_hash; // 0x04
eThreadState m_state; // 0x08
std::uint32_t m_instruction_pointer; // 0x0C
std::uint32_t m_frame_pointer; // 0x10
std::uint32_t m_stack_pointer; // 0x14
float m_timer_a; // 0x18
float m_timer_b; // 0x1C
float m_timer_c; // 0x20
char m_padding1[0x2C]; // 0x24
std::uint32_t m_stack_size; // 0x50
char m_padding2[0x54]; // 0x54
static scrThread *get()
{
return rage::tlsContext::get()->m_script_thread;
}
};
class scrThread
{
public:
virtual ~scrThread() = default; // 0 (0x00)
virtual eThreadState reset(std::uint32_t script_hash, void *args, std::uint32_t arg_count) = 0; // 1 (0x08)
virtual eThreadState run() = 0; // 2 (0x10)
virtual eThreadState tick(std::uint32_t ops_to_execute) = 0; // 3 (0x18)
virtual void kill() = 0; // 4 (0x20)
public:
scrThreadContext m_context; // 0x08
void *m_stack; // 0xB0
char m_padding[0x10]; // 0xB8
const char *m_exit_message; // 0xC8
char m_name[0x40]; // 0xD0
scriptHandler *m_handler; // 0x110
scriptHandlerNetComponent *m_net_component; // 0x118
};
static_assert(sizeof(scrThreadContext) == 0xA8);
static_assert(sizeof(scrThread) == 0x120);
}
class GtaThread : public rage::scrThread
{
public:
rage::joaat_t m_script_hash; // 0x120
char m_padding3[0x14]; // 0x124
std::int32_t m_instance_id; // 0x138
char m_padding4[0x04]; // 0x13C
std::uint8_t m_flag1; // 0x140
bool m_safe_for_network_game; // 0x141
char m_padding5[0x05]; // 0x142
bool m_can_be_paused; // 0x147
bool m_can_remove_blips_from_other_scripts; // 0x148
char m_padding6[0x0F]; // 0x149
};
enum
{
auejk = FIELD_OFFSET(GtaThread, m_can_be_paused),
s9tifgjwkosmldxc = sizeof(GtaThread)
};
static_assert(sizeof(GtaThread) == 0x158);

23
src/gta/tls_context.hpp Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <intrin.h>
#include "fwddec.hpp"
namespace rage
{
class tlsContext
{
public:
char m_padding1[0xC8]; // 0x00
sysMemAllocator *m_allocator; // 0xC8
char m_padding2[0x760]; // 0xD0
scrThread *m_script_thread; // 0x830
bool m_is_script_thread_active; // 0x838
static tlsContext *get()
{
return *reinterpret_cast<tlsContext**>(__readgsqword(0x58));
}
};
static_assert(sizeof(tlsContext) == 0x840);
}

49
src/gta/vector.hpp Normal file
View File

@ -0,0 +1,49 @@
#pragma once
namespace rage
{
struct vector2
{
float x{};
float y{};
};
struct vector3
{
float x{};
float y{};
float z{};
};
struct vector4
{
float x{};
float y{};
float z{};
float w{};
};
#pragma pack(push, 1)
class scrVector
{
public:
scrVector() = default;
scrVector(float x, float y, float z) :
x(x), y(y), z(z)
{}
public:
float x{};
private:
char m_padding1[0x04];
public:
float y{};
private:
char m_padding2[0x04];
public:
float z{};
private:
char m_padding3[0x04];
};
#pragma pack(pop)
}

57
src/gta_util.hpp Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include "common.hpp"
#include "gta/array.hpp"
#include "gta/ped_factory.hpp"
#include "gta/player.hpp"
#include "gta/script_thread.hpp"
#include "gta/tls_context.hpp"
#include "pointers.hpp"
namespace big::gta_util
{
inline CPed *get_local_ped()
{
if (auto ped_factory = *g_pointers->m_ped_factory)
{
return ped_factory->m_local_ped;
}
return nullptr;
}
inline CPlayerInfo *get_local_playerinfo()
{
if (auto ped_factory = *g_pointers->m_ped_factory)
{
if (auto ped = ped_factory->m_local_ped)
{
return ped->m_playerinfo;
}
}
return nullptr;
}
template <typename F, typename ...Args>
void execute_as_script(rage::joaat_t script_hash, F &&callback, Args &&...args)
{
auto tls_ctx = rage::tlsContext::get();
for (auto thread : *g_pointers->m_script_threads)
{
if (!thread || !thread->m_context.m_thread_id || thread->m_context.m_script_hash != script_hash)
continue;
auto og_thread = tls_ctx->m_script_thread;
tls_ctx->m_script_thread = thread;
tls_ctx->m_is_script_thread_active = true;
std::invoke(std::forward<F>(callback), std::forward<Args>(args)...);
tls_ctx->m_script_thread = og_thread;
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
return;
}
}
}

172
src/gui.cpp Normal file
View File

@ -0,0 +1,172 @@
#include "common.hpp"
#include "fiber_pool.hpp"
#include "gta/player.hpp"
#include "gta_util.hpp"
#include "gui.hpp"
#include "logger.hpp"
#include "memory/module.hpp"
#include "memory/pattern.hpp"
#include "natives.hpp"
#include "pointers.hpp"
#include "renderer.hpp"
#include "script.hpp"
#include "imgui/imgui.h"
#include <StackWalker/StackWalker.h>
namespace big
{
void gui::dx_init()
{
auto &style = ImGui::GetStyle();
style.WindowPadding = { 10.f, 10.f };
style.PopupRounding = 0.f;
style.FramePadding = { 8.f, 4.f };
style.ItemSpacing = { 10.f, 8.f };
style.ItemInnerSpacing = { 6.f, 6.f };
style.TouchExtraPadding = { 0.f, 0.f };
style.IndentSpacing = 21.f;
style.ScrollbarSize = 15.f;
style.GrabMinSize = 8.f;
style.WindowBorderSize = 1.f;
style.ChildBorderSize = 0.f;
style.PopupBorderSize = 1.f;
style.FrameBorderSize = 0.f;
style.TabBorderSize = 0.f;
style.WindowRounding = 0.f;
style.ChildRounding = 0.f;
style.FrameRounding = 0.f;
style.ScrollbarRounding = 0.f;
style.GrabRounding = 0.f;
style.TabRounding = 0.f;
style.WindowTitleAlign = { 0.5f, 0.5f };
style.ButtonTextAlign = { 0.5f, 0.5f };
style.DisplaySafeAreaPadding = { 3.f, 3.f };
auto &colors = style.Colors;
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(1.00f, 0.90f, 0.19f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.30f, 0.30f, 0.30f, 0.50f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.21f, 0.21f, 0.21f, 0.54f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.21f, 0.21f, 0.21f, 0.78f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.28f, 0.27f, 0.27f, 0.54f);
colors[ImGuiCol_TitleBg] = ImVec4(0.17f, 0.17f, 0.17f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.19f, 0.19f, 0.19f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.34f, 0.34f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.39f, 0.38f, 0.38f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.41f, 0.41f, 0.41f, 0.74f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.41f, 0.41f, 0.41f, 0.78f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.41f, 0.41f, 0.41f, 0.87f);
colors[ImGuiCol_Header] = ImVec4(0.37f, 0.37f, 0.37f, 0.31f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.38f, 0.38f, 0.38f, 0.37f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.37f, 0.37f, 0.37f, 0.51f);
colors[ImGuiCol_Separator] = ImVec4(0.38f, 0.38f, 0.38f, 0.50f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.46f, 0.46f, 0.46f, 0.50f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.46f, 0.46f, 0.46f, 0.64f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
colors[ImGuiCol_Tab] = ImVec4(0.21f, 0.21f, 0.21f, 0.86f);
colors[ImGuiCol_TabHovered] = ImVec4(0.27f, 0.27f, 0.27f, 0.86f);
colors[ImGuiCol_TabActive] = ImVec4(0.34f, 0.34f, 0.34f, 0.86f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.10f, 0.10f, 0.10f, 0.97f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
}
void gui::dx_on_tick()
{
if (ImGui::Begin("BigBaseV2"))
{
static bool demo_bool = true;
static int demo_int = 1;
static float demo_float = 1.f;
static const char *demo_combo[]
{
"One",
"Two",
"Three"
};
static int demo_combo_pos = 0;
ImGui::Checkbox("Bool", &demo_bool);
ImGui::SliderInt("Int", &demo_int, 0, 10);
ImGui::SliderFloat("Float", &demo_float, 0.f, 10.f);
ImGui::Combo("Combo", &demo_combo_pos, demo_combo, sizeof(demo_combo) / sizeof(*demo_combo));
if (ImGui::Button("Spawn a vehicle"))
{
g_fiber_pool->queue_job([]
{
constexpr auto hash = RAGE_JOAAT("adder");
while (!STREAMING::HAS_MODEL_LOADED(hash))
{
STREAMING::REQUEST_MODEL(hash);
script::get_current()->yield();
}
auto pos = ENTITY::GET_ENTITY_COORDS(PLAYER::PLAYER_PED_ID(), true);
auto vehicle = VEHICLE::CREATE_VEHICLE(hash, pos.x, pos.y, pos.z, 0.f, true, true);
if (*g_pointers->m_is_session_started)
{
DECORATOR::DECOR_SET_INT(vehicle, "MPBitset", 0);
}
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
});
}
ImGui::Separator();
if (ImGui::Button("Unload"))
{
g_running = false;
}
}
ImGui::End();
}
void gui::script_init()
{
}
void gui::script_on_tick()
{
if (g_gui.m_opened)
{
CONTROLS::DISABLE_ALL_CONTROL_ACTIONS(0);
}
}
void gui::script_func()
{
g_gui.script_init();
while (true)
{
g_gui.script_on_tick();
script::get_current()->yield();
}
}
}

20
src/gui.hpp Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "common.hpp"
namespace big
{
class gui
{
public:
void dx_init();
void dx_on_tick();
void script_init();
void script_on_tick();
static void script_func();
public:
bool m_opened{};
};
inline gui g_gui;
}

194
src/hooking.cpp Normal file
View File

@ -0,0 +1,194 @@
#include "common.hpp"
#include "function_types.hpp"
#include "logger.hpp"
#include "gta/array.hpp"
#include "gta/player.hpp"
#include "gta/script_thread.hpp"
#include "gui.hpp"
#include "hooking.hpp"
#include "memory/module.hpp"
#include "natives.hpp"
#include "pointers.hpp"
#include "renderer.hpp"
#include "script_mgr.hpp"
#include <mh/MinHook.h>
namespace big
{
static GtaThread *find_script_thread(rage::joaat_t hash)
{
for (auto thread : *g_pointers->m_script_threads)
{
if (thread
&& thread->m_context.m_thread_id
&& thread->m_handler
&& thread->m_script_hash == hash)
{
return thread;
}
}
return nullptr;
}
hooking::hooking() :
m_swapchain_hook(*g_pointers->m_swapchain, hooks::swapchain_num_funcs),
m_set_cursor_pos_hook("SetCursorPos", memory::module("user32.dll").get_export("SetCursorPos").as<void*>(), &hooks::set_cursor_pos),
m_run_script_threads_hook("Script hook", g_pointers->m_run_script_threads, &hooks::run_script_threads),
m_convert_thread_to_fiber_hook("ConvertThreadToFiber", memory::module("kernel32.dll").get_export("ConvertThreadToFiber").as<void*>(), &hooks::convert_thread_to_fiber)
{
m_swapchain_hook.hook(hooks::swapchain_present_index, &hooks::swapchain_present);
m_swapchain_hook.hook(hooks::swapchain_resizebuffers_index, &hooks::swapchain_resizebuffers);
g_hooking = this;
}
hooking::~hooking()
{
if (m_enabled)
disable();
g_hooking = nullptr;
}
void hooking::enable()
{
m_swapchain_hook.enable();
m_og_wndproc = reinterpret_cast<WNDPROC>(SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&hooks::wndproc)));
m_set_cursor_pos_hook.enable();
m_run_script_threads_hook.enable();
m_convert_thread_to_fiber_hook.enable();
ensure_dynamic_hooks();
m_enabled = true;
}
void hooking::disable()
{
m_enabled = false;
if (m_main_persistent_hook)
{
m_main_persistent_hook->disable();
}
m_convert_thread_to_fiber_hook.disable();
m_run_script_threads_hook.disable();
m_set_cursor_pos_hook.disable();
SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_og_wndproc));
m_swapchain_hook.disable();
}
void hooking::ensure_dynamic_hooks()
{
if (!m_main_persistent_hook)
{
if (auto main_persistent = find_script_thread(RAGE_JOAAT("main_persistent")))
{
m_main_persistent_hook = std::make_unique<vmt_hook>(main_persistent->m_handler, hooks::main_persistent_num_funcs);
m_main_persistent_hook->hook(hooks::main_persistent_dtor_index, &hooks::main_persistent_dtor);
m_main_persistent_hook->hook(hooks::main_persistent_is_networked_index, &hooks::main_persistent_is_networked);
m_main_persistent_hook->enable();
}
}
}
minhook_keepalive::minhook_keepalive()
{
MH_Initialize();
}
minhook_keepalive::~minhook_keepalive()
{
MH_Uninitialize();
}
bool hooks::run_script_threads(std::uint32_t ops_to_execute)
{
if (g_running)
{
g_script_mgr.tick();
}
return g_hooking->m_run_script_threads_hook.get_original<functions::run_script_threads_t>()(ops_to_execute);
}
void *hooks::convert_thread_to_fiber(void *param)
{
if (IsThreadAFiber())
{
return GetCurrentFiber();
}
return g_hooking->m_convert_thread_to_fiber_hook.get_original<decltype(&convert_thread_to_fiber)>()(param);
}
HRESULT hooks::swapchain_present(IDXGISwapChain *this_, UINT sync_interval, UINT flags)
{
if (g_running)
{
g_renderer->on_present();
}
return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_present)>(swapchain_present_index)(this_, sync_interval, flags);
}
HRESULT hooks::swapchain_resizebuffers(IDXGISwapChain * this_, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swapchain_flags)
{
if (g_running)
{
g_renderer->pre_reset();
auto result = g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)
(this_, buffer_count, width, height, new_format, swapchain_flags);
if (SUCCEEDED(result))
{
g_renderer->post_reset();
}
return result;
}
return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)
(this_, buffer_count, width, height, new_format, swapchain_flags);
}
LRESULT hooks::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (g_running)
{
g_renderer->wndproc(hwnd, msg, wparam, lparam);
}
return CallWindowProcW(g_hooking->m_og_wndproc, hwnd, msg, wparam, lparam);
}
BOOL hooks::set_cursor_pos(int x, int y)
{
if (g_gui.m_opened)
{
return true;
}
return g_hooking->m_set_cursor_pos_hook.get_original<decltype(&set_cursor_pos)>()(x, y);
}
void hooks::main_persistent_dtor(CGameScriptHandler *this_, bool free_memory)
{
auto og_func = g_hooking->m_main_persistent_hook->get_original<decltype(&main_persistent_dtor)>(main_persistent_dtor_index);
g_hooking->m_main_persistent_hook->disable();
g_hooking->m_main_persistent_hook.reset();
return og_func(this_, free_memory);
}
bool hooks::main_persistent_is_networked(CGameScriptHandler *this_)
{
return *g_pointers->m_is_session_started;
}
}

62
src/hooking.hpp Normal file
View File

@ -0,0 +1,62 @@
#pragma once
#include "common.hpp"
#include "detour_hook.hpp"
#include "gta/fwddec.hpp"
#include "script_hook.hpp"
#include "vmt_hook.hpp"
namespace big
{
struct hooks
{
static bool run_script_threads(std::uint32_t ops_to_execute);
static void *convert_thread_to_fiber(void *param);
static constexpr auto swapchain_num_funcs = 19;
static constexpr auto swapchain_present_index = 8;
static constexpr auto swapchain_resizebuffers_index = 13;
static HRESULT swapchain_present(IDXGISwapChain *this_, UINT sync_interval, UINT flags);
static HRESULT swapchain_resizebuffers(IDXGISwapChain *this_, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swapchain_flags);
static LRESULT wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static BOOL set_cursor_pos(int x, int y);
static constexpr auto main_persistent_num_funcs = 16;
static constexpr auto main_persistent_dtor_index = 0;
static constexpr auto main_persistent_is_networked_index = 6;
static void main_persistent_dtor(CGameScriptHandler *this_, bool free_memory);
static bool main_persistent_is_networked(CGameScriptHandler *this_);
};
struct minhook_keepalive
{
minhook_keepalive();
~minhook_keepalive();
};
class hooking
{
friend hooks;
public:
explicit hooking();
~hooking();
void enable();
void disable();
void ensure_dynamic_hooks();
private:
bool m_enabled{};
minhook_keepalive m_minhook_keepalive;
vmt_hook m_swapchain_hook;
WNDPROC m_og_wndproc;
detour_hook m_set_cursor_pos_hook;
detour_hook m_run_script_threads_hook;
detour_hook m_convert_thread_to_fiber_hook;
std::unique_ptr<vmt_hook> m_main_persistent_hook;
};
inline hooking *g_hooking{};
}

73
src/imgui/imconfig.h Normal file
View File

@ -0,0 +1,73 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h)
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include
// the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty)
//---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp.
//#define IMGUI_DISABLE_DEMO_WINDOWS
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function.
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of imgui cpp files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it.
//#define ImDrawIdx unsigned int
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
}
*/

9355
src/imgui/imgui.cpp Normal file

File diff suppressed because it is too large Load Diff

2132
src/imgui/imgui.h Normal file

File diff suppressed because it is too large Load Diff

4215
src/imgui/imgui_demo.cpp Normal file

File diff suppressed because it is too large Load Diff

3276
src/imgui/imgui_draw.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,512 @@
// dear imgui: Renderer for DirectX11
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX11: Disabling depth-write.
#include "imgui.h"
#include "imgui_impl_dx11.h"
// DirectX
#include <stdio.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
static ID3D11Device* g_pd3dDevice = NULL;
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D11Buffer* g_pVB = NULL;
static ID3D11Buffer* g_pIB = NULL;
static ID3D10Blob* g_pVertexShaderBlob = NULL;
static ID3D11VertexShader* g_pVertexShader = NULL;
static ID3D11InputLayout* g_pInputLayout = NULL;
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10Blob* g_pPixelShaderBlob = NULL;
static ID3D11PixelShader* g_pPixelShader = NULL;
static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = NULL;
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
// Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
// Create and grow vertex/index buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
{
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
{
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
return;
}
// Copy and convert all vertices into a single contiguous buffer
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
return;
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
ctx->Unmap(g_pVB, 0);
ctx->Unmap(g_pIB, 0);
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
{
D3D11_MAPPED_SUBRESOURCE mapped_resource;
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
ctx->Unmap(g_pVertexConstantBuffer, 0);
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX11_STATE
{
UINT ScissorRectsCount, ViewportsCount;
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState* RS;
ID3D11BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D11DepthStencilState* DepthStencilState;
ID3D11ShaderResourceView* PSShaderResource;
ID3D11SamplerState* PSSampler;
ID3D11PixelShader* PS;
ID3D11VertexShader* VS;
UINT PSInstancesCount, VSInstancesCount;
ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
};
BACKUP_DX11_STATE old;
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
ctx->RSGetState(&old.RS);
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
ctx->PSGetSamplers(0, 1, &old.PSSampler);
old.PSInstancesCount = old.VSInstancesCount = 256;
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
ctx->IAGetInputLayout(&old.InputLayout);
// Setup viewport
D3D11_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
ctx->RSSetViewports(1, &vp);
// Bind shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
ctx->IASetInputLayout(g_pInputLayout);
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->VSSetShader(g_pVertexShader, NULL, 0);
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
ctx->PSSetShader(g_pPixelShader, NULL, 0);
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
// Setup render state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
ctx->RSSetState(g_pRasterizerState);
// Render command lists
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback (registered via ImDrawList::AddCallback)
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Apply scissor/clipping rectangle
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - pos.x), (LONG)(pcmd->ClipRect.y - pos.y), (LONG)(pcmd->ClipRect.z - pos.x), (LONG)(pcmd->ClipRect.w - pos.y) };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset);
}
idx_offset += pcmd->ElemCount;
}
vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}
static void ImGui_ImplDX11_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D *pTexture = NULL;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
pTexture->Release();
}
// Store our identifier
io.Fonts->TexID = (ImTextureID)g_pFontTextureView;
// Create texture sampler
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
}
}
bool ImGui_ImplDX11_CreateDeviceObjects()
{
if (!g_pd3dDevice)
return false;
if (g_pFontSampler)
ImGui_ImplDX11_InvalidateDeviceObjects();
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX11 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
struct VS_INPUT\
{\
float2 pos : POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
}";
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
return false;
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
return false;
// Create the input layout
D3D11_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
return false;
// Create the constant buffer
{
D3D11_BUFFER_DESC desc;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
}
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
sampler sampler0;\
Texture2D texture0;\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
return false;
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
return false;
}
// Create the blending setup
{
D3D11_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
}
// Create the rasterizer state
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
}
// Create depth-stencil State
{
D3D11_DEPTH_STENCIL_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.DepthEnable = false;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}
ImGui_ImplDX11_CreateFontsTexture();
return true;
}
void ImGui_ImplDX11_InvalidateDeviceObjects()
{
if (!g_pd3dDevice)
return;
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
}
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
{
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx11";
// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
IDXGIAdapter* pDXGIAdapter = NULL;
IDXGIFactory* pFactory = NULL;
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
{
g_pd3dDevice = device;
g_pd3dDeviceContext = device_context;
g_pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
return true;
}
void ImGui_ImplDX11_Shutdown()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
g_pd3dDevice = NULL;
g_pd3dDeviceContext = NULL;
}
void ImGui_ImplDX11_NewFrame()
{
if (!g_pFontSampler)
ImGui_ImplDX11_CreateDeviceObjects();
}

View File

@ -0,0 +1,23 @@
// dear imgui: Renderer for DirectX11
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
struct ID3D11Device;
struct ID3D11DeviceContext;
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();

View File

@ -0,0 +1,251 @@
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// Missing features:
// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice).
#include "imgui.h"
#include "imgui_impl_win32.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <tchar.h>
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
// Win32 Data
static HWND g_hWnd = 0;
static INT64 g_Time = 0;
static INT64 g_TicksPerSecond = 0;
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
// Functions
bool ImGui_ImplWin32_Init(void* hwnd)
{
if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
return false;
if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
return false;
// Setup back-end capabilities flags
g_hWnd = (HWND)hwnd;
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_win32";
io.ImeWindowHandle = hwnd;
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
io.KeyMap[ImGuiKey_Home] = VK_HOME;
io.KeyMap[ImGuiKey_End] = VK_END;
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
return true;
}
void ImGui_ImplWin32_Shutdown()
{
g_hWnd = (HWND)0;
}
static bool ImGui_ImplWin32_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return false;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
::SetCursor(NULL);
}
else
{
// Show OS mouse cursor
LPTSTR win32_cursor = IDC_ARROW;
switch (imgui_cursor)
{
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
}
::SetCursor(::LoadCursor(NULL, win32_cursor));
}
return true;
}
static void ImGui_ImplWin32_UpdateMousePos()
{
ImGuiIO& io = ImGui::GetIO();
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
{
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
::ClientToScreen(g_hWnd, &pos);
::SetCursorPos(pos.x, pos.y);
}
// Set mouse position
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
POINT pos;
if (::GetActiveWindow() == g_hWnd && ::GetCursorPos(&pos))
if (::ScreenToClient(g_hWnd, &pos))
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
}
void ImGui_ImplWin32_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
RECT rect;
::GetClientRect(g_hWnd, &rect);
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
// Setup time step
INT64 current_time;
::QueryPerformanceCounter((LARGE_INTEGER *)&current_time);
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
g_Time = current_time;
// Read keyboard modifiers inputs
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
io.KeySuper = false;
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
// Update OS mouse position
ImGui_ImplWin32_UpdateMousePos();
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
if (g_LastMouseCursor != mouse_cursor)
{
g_LastMouseCursor = mouse_cursor;
ImGui_ImplWin32_UpdateMouseCursor();
}
}
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
// Process Win32 mouse/keyboard inputs.
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinations when dragging mouse outside of our window bounds.
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui::GetCurrentContext() == NULL)
return 0;
ImGuiIO& io = ImGui::GetIO();
switch (msg)
{
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
{
int button = 0;
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) button = 0;
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) button = 1;
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) button = 2;
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
::SetCapture(hwnd);
io.MouseDown[button] = true;
return 0;
}
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
{
int button = 0;
if (msg == WM_LBUTTONUP) button = 0;
if (msg == WM_RBUTTONUP) button = 1;
if (msg == WM_MBUTTONUP) button = 2;
io.MouseDown[button] = false;
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
::ReleaseCapture();
return 0;
}
case WM_MOUSEWHEEL:
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
return 0;
case WM_MOUSEHWHEEL:
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (wParam < 256)
io.KeysDown[wParam] = 1;
return 0;
case WM_KEYUP:
case WM_SYSKEYUP:
if (wParam < 256)
io.KeysDown[wParam] = 0;
return 0;
case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000)
io.AddInputCharacter((unsigned short)wParam);
return 0;
case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
return 1;
return 0;
}
return 0;
}

View File

@ -0,0 +1,22 @@
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// Missing features:
// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice).
#pragma once
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
// Handler for Win32 messages, update mouse/keyboard data.
// You may or not need this for your implementation, but it can serve as reference for handling inputs.
// Intentionally commented out to avoid dragging dependencies on <windows.h> types. You can COPY this line into your .cpp code instead.
/*
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
*/

1484
src/imgui/imgui_internal.h Normal file

File diff suppressed because it is too large Load Diff

6564
src/imgui/imgui_widgets.cpp Normal file

File diff suppressed because it is too large Load Diff

623
src/imgui/imstb_rectpack.h Normal file
View File

@ -0,0 +1,623 @@
// stb_rect_pack.h - v0.11 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
//
// Version history:
//
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
#ifdef STBRP_LARGE_RECTS
typedef int stbrp_coord;
#else
typedef unsigned short stbrp_coord;
#endif
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
#endif
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
#ifdef STBRP_LARGE_RECTS
context->extra[1].y = (1<<30);
#else
context->extra[1].y = 65535;
#endif
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height < c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
STBRP_ASSERT(y <= best_y);
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
#ifdef STBRP_LARGE_RECTS
#define STBRP__MAXVAL 0xffffffff
#else
#define STBRP__MAXVAL 0xffff
#endif
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
#endif
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

1409
src/imgui/imstb_textedit.h Normal file

File diff suppressed because it is too large Load Diff

4854
src/imgui/imstb_truetype.h Normal file

File diff suppressed because it is too large Load Diff

54
src/invoker.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "common.hpp"
#include "crossmap.hpp"
#include "invoker.hpp"
#include "logger.hpp"
#include "pointers.hpp"
namespace big
{
native_call_context::native_call_context()
{
m_return_value = &m_return_stack[0];
m_args = &m_arg_stack[0];
}
bool native_invoker::map_native(rage::scrNativeHash *hash)
{
for (auto const &mapping : g_crossmap)
{
if (mapping.first == *hash)
{
*hash = mapping.second;
return true;
}
}
return false;
}
void native_invoker::begin_call()
{
m_call_context.reset();
}
void native_invoker::end_call(rage::scrNativeHash hash)
{
map_native(&hash);
if (auto handler = g_pointers->m_get_native_handler(g_pointers->m_native_registration_table, hash))
{
__try
{
handler(&m_call_context);
g_pointers->m_fix_vectors(&m_call_context);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
LOG_ERROR("Exception caught while trying to call 0x{:X} native.", hash);
}
}
else
{
LOG_ERROR("Failed to find 0x{:X} native's handler.", hash);
}
}
}

43
src/invoker.hpp Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "common.hpp"
#include "gta/natives.hpp"
namespace big
{
class native_call_context : public rage::scrNativeCallContext
{
public:
native_call_context();
private:
std::uint64_t m_return_stack[10];
std::uint64_t m_arg_stack[100];
};
class native_invoker
{
public:
explicit native_invoker() = default;
~native_invoker() = default;
bool map_native(rage::scrNativeHash *hash);
void begin_call();
void end_call(rage::scrNativeHash hash);
template <typename T>
void push_arg(T &&value)
{
m_call_context.push_arg(std::forward<T>(value));
}
template <typename T>
T &get_return_value()
{
return *m_call_context.get_return_value<T>();
}
private:
native_call_context m_call_context;
};
inline native_invoker g_native_invoker;
}

188
src/logger.hpp Normal file
View File

@ -0,0 +1,188 @@
#pragma once
#include "common.hpp"
namespace big
{
enum class log_color : std::uint16_t
{
red = FOREGROUND_RED,
green = FOREGROUND_GREEN,
blue = FOREGROUND_BLUE,
intensify = FOREGROUND_INTENSITY
};
inline log_color operator|(log_color a, log_color b)
{
return static_cast<log_color>(static_cast<std::underlying_type_t<log_color>>(a) | static_cast<std::underlying_type_t<log_color>>(b));
}
class logger;
inline logger *g_logger{};
class logger
{
public:
explicit logger() :
m_file_path(std::getenv("appdata"))
{
m_file_path /= "BigBaseV2";
try
{
if (!std::filesystem::exists(m_file_path))
{
std::filesystem::create_directory(m_file_path);
}
else if (!std::filesystem::is_directory(m_file_path))
{
std::filesystem::remove(m_file_path);
std::filesystem::create_directory(m_file_path);
}
m_file_path /= "BigBaseV2.log";
m_file_out.open(m_file_path, std::ios_base::out | std::ios_base::app);
}
catch (std::filesystem::filesystem_error const&)
{
}
if ((m_did_console_exist = AttachConsole(GetCurrentProcessId())) == false)
AllocConsole();
if ((m_console_handle = GetStdHandle(STD_OUTPUT_HANDLE)) != nullptr)
{
SetConsoleTitleA("BigBaseV2");
SetConsoleOutputCP(CP_UTF8);
m_console_out.open("CONOUT$", std::ios_base::out | std::ios_base::app);
}
g_logger = this;
}
~logger()
{
if (!m_did_console_exist)
FreeConsole();
g_logger = nullptr;
}
template <typename ...Args>
void raw(log_color color, Args const &...args)
{
raw_to_console(color, args...);
raw_to_file(args...);
}
template <typename ...Args>
void log(log_color color, std::string_view prefix, std::string_view format, Args const &...args)
{
auto message = fmt::format(format, args...);
auto time_since_epoch = std::time(nullptr);
auto local_time = std::localtime(&time_since_epoch);
auto console_timestamp = fmt::format("[{:0>2}:{:0>2}:{:0>2}]", local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
auto file_timestamp = fmt::format("[{}-{}-{} {:0>2}:{:0>2}:{:0>2}]", local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday, local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
raw_to_console(color, console_timestamp, " [", prefix, "] ", message, "\n");
raw_to_file(file_timestamp, " [", prefix, "] ", message, "\n");
}
private:
template <typename ...Args>
void raw_to_console(log_color color, Args const &...args)
{
if (m_console_handle)
{
SetConsoleTextAttribute(m_console_handle, static_cast<std::uint16_t>(color));
}
if (m_console_out)
{
((m_console_out << args), ...);
m_console_out << std::flush;
}
}
template <typename ...Args>
void raw_to_file(Args const &...args)
{
if (m_file_out)
{
((m_file_out << args), ...);
m_file_out << std::flush;
}
}
private:
bool m_did_console_exist{};
HANDLE m_console_handle{};
std::ofstream m_console_out;
std::filesystem::path m_file_path;
std::ofstream m_file_out;
};
template <typename ...Args>
inline void log_info(std::string_view format, Args const &...args)
{
if (g_logger)
{
g_logger->log(log_color::blue | log_color::intensify, "Info", format, args...);
}
else
{
DebugBreak();
}
}
template <typename ...Args>
inline void log_error(std::string_view format, Args const &...args)
{
if (g_logger)
{
g_logger->log(log_color::green | log_color::intensify, "Error", format, args...);
}
else
{
DebugBreak();
}
}
template <typename ...Args>
inline void log_trace(std::string_view format, Args const &...args)
{
if (g_logger)
{
g_logger->log(log_color::green | log_color::intensify, "Trace", format, args...);
}
else
{
DebugBreak();
}
}
template <typename ...Args>
inline void log_raw(log_color color, Args const &...args)
{
if (g_logger)
{
g_logger->raw(color, args...);
}
else
{
DebugBreak();
}
}
#define LOG_INFO_IMPL(format, ...) (::big::log_info(format, __VA_ARGS__))
#define LOG_INFO(format, ...) LOG_INFO_IMPL(format, __VA_ARGS__)
#define LOG_ERROR_IMPL(format, ...) (::big::log_error(format, __VA_ARGS__))
#define LOG_ERROR(format, ...) LOG_ERROR_IMPL(format, __VA_ARGS__)
#define LOG_TRACE_IMPL(format, ...) (::big::log_trace(format, __VA_ARGS__))
#define LOG_TRACE(format, ...) LOG_TRACE_IMPL(format, __VA_ARGS__)
#define LOG_RAW_IMPL(color, ...) (::big::log_raw(color, __VA_ARGS__))
#define LOG_RAW(color, ...) LOG_RAW_IMPL(color, __VA_ARGS__)
}

128
src/main.cpp Normal file
View File

@ -0,0 +1,128 @@
#include "common.hpp"
#include "features.hpp"
#include "fiber_pool.hpp"
#include "gui.hpp"
#include "logger.hpp"
#include "hooking.hpp"
#include "pointers.hpp"
#include "renderer.hpp"
#include "script_mgr.hpp"
BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
{
using namespace big;
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hmod);
g_hmodule = hmod;
g_main_thread = CreateThread(nullptr, 0, [](PVOID) -> DWORD
{
auto logger_instance = std::make_unique<logger>();
try
{
LOG_RAW(log_color::green | log_color::intensify,
u8R"kek( ...
;::::;
;::::; :;
;:::::' :;
;:::::; ;.
,:::::' ; OOO\
::::::; ; OOOOO\
;:::::; ; OOOOOOOO
,;::::::; ;' / OOOOOOO
;:::::::::`. ,,,;. / / DOOOOOO
.';:::::::::::::::::;, / / DOOOO
,::::::;::::::;;;;::::;, / / DOOO
;`::::::`'::::::;;;::::: ,#/ / DOOO
:`:::::::`;::::::;;::: ;::# / DOOO
::`:::::::`;:::::::: ;::::# / DOO
`:`:::::::`;:::::: ;::::::#/ DOO
:::`:::::::`;; ;:::::::::## OO
::::`:::::::`;::::::::;:::# OO
`:::::`::::::::::::;'`:;::# O
`:::::`::::::::;' / / `:#
::::::`:::::;' / / `#
)kek");
auto pointers_instance = std::make_unique<pointers>();
LOG_INFO("Pointers initialized.");
if (*g_pointers->m_game_state != eGameState::Playing)
{
LOG_INFO("Waiting for the game to load.");
do
{
std::this_thread::sleep_for(100ms);
} while (*g_pointers->m_game_state != eGameState::Playing);
LOG_INFO("The game has loaded.");
}
else
{
LOG_INFO("The game is already loaded.");
}
auto renderer_instance = std::make_unique<renderer>();
LOG_INFO("Renderer initialized.");
auto fiber_pool_instance = std::make_unique<fiber_pool>(10);
LOG_INFO("Fiber pool initialized.");
auto hooking_instance = std::make_unique<hooking>();
LOG_INFO("Hooking initialized.");
g_script_mgr.add_script(std::make_unique<script>(&features::script_func));
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func));
LOG_INFO("Scripts registered.");
g_hooking->enable();
LOG_INFO("Hooking enabled.");
while (g_running)
{
if (GetAsyncKeyState(VK_END) & 0x8000)
g_running = false;
g_hooking->ensure_dynamic_hooks();
std::this_thread::sleep_for(10ms);
}
g_hooking->disable();
LOG_INFO("Hooking disabled.");
std::this_thread::sleep_for(1000ms);
g_script_mgr.remove_all_scripts();
LOG_INFO("Scripts unregistered.");
hooking_instance.reset();
LOG_INFO("Hooking uninitialized.");
fiber_pool_instance.reset();
LOG_INFO("Fiber pool uninitialized.");
renderer_instance.reset();
LOG_INFO("Renderer uninitialized.");
pointers_instance.reset();
LOG_INFO("Pointers uninitialized.");
}
catch (std::exception const &ex)
{
LOG_ERROR("{}", ex.what());
MessageBoxA(nullptr, ex.what(), nullptr, MB_OK | MB_ICONEXCLAMATION);
}
LOG_INFO("Farewell!");
logger_instance.reset();
CloseHandle(g_main_thread);
FreeLibraryAndExitThread(g_hmodule, 0);
}, nullptr, 0, &g_main_thread_id);
}
return true;
}

7
src/memory/all.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "handle.hpp"
#include "module.hpp"
#include "pattern.hpp"
#include "pattern_batch.hpp"
#include "range.hpp"

10
src/memory/fwddec.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace memory
{
class handle;
class range;
class module;
class pattern;
class pattern_batch;
}

96
src/memory/handle.hpp Normal file
View File

@ -0,0 +1,96 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <type_traits>
namespace memory
{
class handle
{
public:
handle(void* ptr = nullptr);
explicit handle(std::uintptr_t ptr);
template <typename T>
std::enable_if_t<std::is_pointer_v<T>, T> as();
template <typename T>
std::enable_if_t<std::is_lvalue_reference_v<T>, T> as();
template <typename T>
std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> as();
template <typename T>
handle add(T offset);
template <typename T>
handle sub(T offset);
handle rip();
explicit operator bool();
friend bool operator==(handle a, handle b);
friend bool operator!=(handle a, handle b);
private:
void* ptr;
};
inline handle::handle(void* ptr) :
ptr(ptr)
{}
inline handle::handle(std::uintptr_t ptr) :
ptr(reinterpret_cast<void*>(ptr))
{}
template <typename T>
inline std::enable_if_t<std::is_pointer_v<T>, T> handle::as()
{
return static_cast<T>(ptr);
}
template <typename T>
inline std::enable_if_t<std::is_lvalue_reference_v<T>, T> handle::as()
{
return *static_cast<std::add_pointer_t<std::remove_reference_t<T>>>(ptr);
}
template <typename T>
inline std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> handle::as()
{
return reinterpret_cast<std::uintptr_t>(ptr);
}
template <typename T>
inline handle handle::add(T offset)
{
return handle(as<std::uintptr_t>() + offset);
}
template <typename T>
inline handle handle::sub(T offset)
{
return handle(as<std::uintptr_t>() - offset);
}
inline handle handle::rip()
{
return add(as<std::int32_t&>()).add(4);
}
inline bool operator==(handle a, handle b)
{
return a.ptr == b.ptr;
}
inline bool operator!=(handle a, handle b)
{
return a.ptr != b.ptr;
}
inline handle::operator bool()
{
return ptr != nullptr;
}
}

33
src/memory/module.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "../common.hpp"
#include "module.hpp"
namespace memory
{
module::module(HMODULE mod) :
range(mod, 0)
{
auto dosHeader = m_base.as<IMAGE_DOS_HEADER*>();
auto ntHeader = m_base.add(dosHeader->e_lfanew).as<IMAGE_NT_HEADERS*>();
m_size = ntHeader->OptionalHeader.SizeOfImage;
}
module::module(std::nullptr_t) :
module(GetModuleHandle(nullptr))
{
}
module::module(std::string_view name) :
module(GetModuleHandleA(name.data()))
{
}
module::module(std::wstring_view name) :
module(GetModuleHandleW(name.data()))
{
}
handle module::get_export(std::string_view symbol_name)
{
return GetProcAddress(m_base.as<HMODULE>(), symbol_name.data());
}
}

16
src/memory/module.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "range.hpp"
namespace memory
{
class module : public range
{
public:
module(HMODULE mod);
explicit module(std::nullptr_t);
explicit module(std::string_view name);
explicit module(std::wstring_view name);
memory::handle get_export(std::string_view symbol_name);
};
}

90
src/memory/pattern.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "../common.hpp"
#include "pattern.hpp"
namespace memory
{
pattern::pattern(std::string_view ida_sig)
{
auto to_upper = [](char c) -> char
{
return c >= 'a' && c <= 'z' ? static_cast<char>(c + ('A' - 'a')) : static_cast<char>(c);
};
auto to_hex = [&](char c) -> std::optional<std::uint8_t>
{
switch (to_upper(c))
{
case '0':
return static_cast<std::uint8_t>(0);
case '1':
return static_cast<std::uint8_t>(1);
case '2':
return static_cast<std::uint8_t>(2);
case '3':
return static_cast<std::uint8_t>(3);
case '4':
return static_cast<std::uint8_t>(4);
case '5':
return static_cast<std::uint8_t>(5);
case '6':
return static_cast<std::uint8_t>(6);
case '7':
return static_cast<std::uint8_t>(7);
case '8':
return static_cast<std::uint8_t>(8);
case '9':
return static_cast<std::uint8_t>(9);
case 'A':
return static_cast<std::uint8_t>(10);
case 'B':
return static_cast<std::uint8_t>(11);
case 'C':
return static_cast<std::uint8_t>(12);
case 'D':
return static_cast<std::uint8_t>(13);
case 'E':
return static_cast<std::uint8_t>(14);
case 'F':
return static_cast<std::uint8_t>(15);
default:
return std::nullopt;
}
};
for (std::size_t i = 0; i < ida_sig.size(); ++i)
{
if (ida_sig[i] == ' ')
continue;
bool last = (i == ida_sig.size() - 1);
if (ida_sig[i] != '?')
{
if (!last)
{
auto c1 = to_hex(ida_sig[i]);
auto c2 = to_hex(ida_sig[i + 1]);
if (c1 && c2)
{
m_bytes.emplace_back(static_cast<std::uint8_t>((*c1 * 0x10) + *c2));
}
}
}
else
{
m_bytes.push_back(std::nullopt);
}
}
}
pattern::pattern(const void *bytes, std::string_view mask)
{
for (std::size_t i = 0; i < mask.size(); ++i)
{
if (mask[i] != '?')
m_bytes.emplace_back(static_cast<const std::uint8_t*>(bytes)[i]);
else
m_bytes.push_back(std::nullopt);
}
}
}

25
src/memory/pattern.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include <optional>
#include <string_view>
#include <vector>
#include "fwddec.hpp"
#include "handle.hpp"
namespace memory
{
class pattern
{
friend pattern_batch;
friend range;
public:
pattern(std::string_view ida_sig);
explicit pattern(const void *bytes, std::string_view mask);
inline pattern(const char* ida_sig) :
pattern(std::string_view(ida_sig))
{}
private:
std::vector<std::optional<std::uint8_t>> m_bytes;
};
}

View File

@ -0,0 +1,39 @@
#include "../common.hpp"
#include "../logger.hpp"
#include "pattern_batch.hpp"
#include "range.hpp"
namespace memory
{
void pattern_batch::add(std::string name, pattern pattern, std::function<void(handle)> callback)
{
m_entries.emplace_back(std::move(name), std::move(pattern), std::move(callback));
}
void pattern_batch::run(range region)
{
bool all_found = true;
for (auto &entry : m_entries)
{
if (auto result = region.scan(entry.m_pattern))
{
if (entry.m_callback)
{
std::invoke(std::move(entry.m_callback), result);
LOG_INFO("Found '{}'.", entry.m_name);
}
else
{
all_found = false;
LOG_ERROR("Failed to find '{}'.", entry.m_name);
}
}
}
m_entries.clear();
if (!all_found)
{
throw std::runtime_error("Failed to find some patterns.");
}
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <functional>
#include <vector>
#include "pattern.hpp"
namespace memory
{
class pattern_batch
{
public:
explicit pattern_batch() = default;
~pattern_batch() noexcept = default;
void add(std::string name, pattern pattern, std::function<void(memory::handle)> callback);
void run(range region);
struct entry
{
std::string m_name;
pattern m_pattern;
std::function<void(memory::handle)> m_callback;
explicit entry(std::string name, pattern pattern, std::function<void(memory::handle)> callback) :
m_name(std::move(name)),
m_pattern(std::move(pattern)),
m_callback(std::move(callback))
{}
};
private:
std::vector<entry> m_entries;
};
}

74
src/memory/range.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "../common.hpp"
#include "range.hpp"
#include "pattern.hpp"
namespace memory
{
range::range(handle base, std::size_t size) :
m_base(base), m_size(size)
{
}
handle range::begin()
{
return m_base;
}
handle range::end()
{
return m_base.add(m_size);
}
std::size_t range::size()
{
return m_size;
}
bool range::contains(handle h)
{
return h.as<std::uintptr_t>() >= begin().as<std::uintptr_t>() && h.as<std::uintptr_t>() <= end().as<std::uintptr_t>();
}
static bool pattern_matches(std::uint8_t* target, const std::optional<std::uint8_t>* sig, std::size_t length)
{
for (std::size_t i = 0; i < length; ++i)
{
if (sig[i] && *sig[i] != target[i])
return false;
}
return true;
};
handle range::scan(pattern const &sig)
{
auto data = sig.m_bytes.data();
auto length = sig.m_bytes.size();
for (std::uintptr_t i = 0; i < m_size - length; ++i)
{
if (pattern_matches(m_base.add(i).as<std::uint8_t*>(), data, length))
{
return m_base.add(i);
}
}
return nullptr;
}
std::vector<handle> range::scan_all(pattern const &sig)
{
std::vector<handle> result;
auto data = sig.m_bytes.data();
auto length = sig.m_bytes.size();
for (std::uintptr_t i = 0; i < m_size - length; ++i)
{
if (pattern_matches(m_base.add(i).as<std::uint8_t*>(), data, length))
{
result.push_back(m_base.add(i));
}
}
return std::move(result);
}
}

25
src/memory/range.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <vector>
#include "fwddec.hpp"
#include "handle.hpp"
namespace memory
{
class range
{
public:
range(handle base, std::size_t size);
handle begin();
handle end();
std::size_t size();
bool contains(handle h);
handle scan(pattern const& sig);
std::vector<handle> scan_all(pattern const& sig);
protected:
handle m_base;
std::size_t m_size;
};
}

5372
src/natives.hpp Normal file

File diff suppressed because it is too large Load Diff

82
src/pointers.cpp Normal file
View File

@ -0,0 +1,82 @@
#include "common.hpp"
#include "logger.hpp"
#include "pointers.hpp"
#include "memory/all.hpp"
namespace big
{
pointers::pointers()
{
memory::pattern_batch main_batch;
main_batch.add("Game state", "83 3D ? ? ? ? ? 75 17 8B 42 20 25", [this](memory::handle ptr)
{
m_game_state = ptr.add(2).rip().as<eGameState*>();
});
main_batch.add("Is session started", "40 38 35 ? ? ? ? 75 0E 4C 8B C3 49 8B D7 49 8B CE", [this](memory::handle ptr)
{
m_is_session_started = ptr.add(3).rip().as<bool*>();
});
main_batch.add("Ped factory", "48 8B 05 ? ? ? ? 48 8B 48 08 48 85 C9 74 52 8B 81", [this](memory::handle ptr)
{
m_ped_factory = ptr.add(3).rip().as<CPedFactory**>();
});
main_batch.add("Network player manager", "48 8B 0D ? ? ? ? 8A D3 48 8B 01 FF 50 ? 4C 8B 07 48 8B CF", [this](memory::handle ptr)
{
m_network_player_mgr = ptr.add(3).rip().as<CNetworkPlayerMgr**>();
});
main_batch.add("Native handlers", "48 8D 0D ? ? ? ? 48 8B 14 FA E8 ? ? ? ? 48 85 C0 75 0A", [this](memory::handle ptr)
{
m_native_registration_table = ptr.add(3).rip().as<rage::scrNativeRegistrationTable*>();
m_get_native_handler = ptr.add(12).rip().as<functions::get_native_handler_t>();
});
main_batch.add("Fix vectors", "83 79 18 00 48 8B D1 74 4A FF 4A 18 48 63 4A 18 48 8D 41 04 48 8B 4C CA", [this](memory::handle ptr)
{
m_fix_vectors = ptr.as<functions::fix_vectors_t>();
});
main_batch.add("Script threads", "45 33 F6 8B E9 85 C9 B8", [this](memory::handle ptr)
{
m_script_threads = ptr.sub(4).rip().sub(8).as<decltype(m_script_threads)>();
m_run_script_threads = ptr.sub(0x1F).as<functions::run_script_threads_t>();
});
main_batch.add("Script programs", "44 8B 0D ? ? ? ? 4C 8B 1D ? ? ? ? 48 8B 1D ? ? ? ? 41 83 F8 FF 74 3F 49 63 C0 42 0F B6 0C 18 81 E1", [this](memory::handle ptr)
{
m_script_program_table = ptr.add(17).rip().as<decltype(m_script_program_table)>();
});
main_batch.add("Script globals", "48 8D 15 ? ? ? ? 4C 8B C0 E8 ? ? ? ? 48 85 FF 48 89 1D", [this](memory::handle ptr)
{
m_script_globals = ptr.add(3).rip().as<std::int64_t**>();
});
main_batch.add("CGameScriptHandlerMgr", "48 8B 0D ? ? ? ? 4C 8B CE E8 ? ? ? ? 48 85 C0 74 05 40 32 FF", [this](memory::handle ptr)
{
m_script_handler_mgr = ptr.add(3).rip().as<CGameScriptHandlerMgr**>();
});
main_batch.add("Swapchain", "48 8B 0D ? ? ? ? 48 8B 01 44 8D 43 01 33 D2 FF 50 40 8B C8", [this](memory::handle ptr)
{
m_swapchain = ptr.add(3).rip().as<IDXGISwapChain**>();
});
main_batch.run(memory::module(nullptr));
m_hwnd = FindWindowW(L"grcWindow", nullptr);
if (!m_hwnd)
throw std::runtime_error("Failed to find the game's window.");
g_pointers = this;
}
pointers::~pointers()
{
g_pointers = nullptr;
}
}

38
src/pointers.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "common.hpp"
#include "gta/fwddec.hpp"
#include "gta/enums.hpp"
#include "function_types.hpp"
namespace big
{
class pointers
{
public:
explicit pointers();
~pointers();
public:
HWND m_hwnd{};
eGameState *m_game_state{};
bool *m_is_session_started{};
CPedFactory **m_ped_factory{};
CNetworkPlayerMgr **m_network_player_mgr{};
rage::scrNativeRegistrationTable *m_native_registration_table{};
functions::get_native_handler_t m_get_native_handler{};
functions::fix_vectors_t m_fix_vectors{};
rage::atArray<GtaThread*> *m_script_threads{};
rage::scrProgramTable *m_script_program_table{};
functions::run_script_threads_t m_run_script_threads{};
std::int64_t **m_script_globals{};
CGameScriptHandlerMgr **m_script_handler_mgr{};
IDXGISwapChain **m_swapchain{};
};
inline pointers *g_pointers{};
}

100
src/renderer.cpp Normal file
View File

@ -0,0 +1,100 @@
#include "common.hpp"
#include "fonts.hpp"
#include "logger.hpp"
#include "gui.hpp"
#include "pointers.hpp"
#include "renderer.hpp"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx11.h"
#include "imgui/imgui_impl_win32.h"
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace big
{
renderer::renderer() :
m_dxgi_swapchain(*g_pointers->m_swapchain)
{
void *d3d_device{};
if (SUCCEEDED(m_dxgi_swapchain->GetDevice(__uuidof(ID3D11Device), &d3d_device)))
{
m_d3d_device.Attach(static_cast<ID3D11Device*>(d3d_device));
}
else
{
throw std::runtime_error("Failed to get D3D device.");
}
m_d3d_device->GetImmediateContext(m_d3d_device_context.GetAddressOf());
ImGui::CreateContext();
ImGui_ImplDX11_Init(m_d3d_device.Get(), m_d3d_device_context.Get());
ImGui_ImplWin32_Init(g_pointers->m_hwnd);
ImFontConfig font_cfg{};
font_cfg.FontDataOwnedByAtlas = false;
std::strcpy(font_cfg.Name, "Rubik");
m_font = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<std::uint8_t*>(font_rubik), sizeof(font_rubik), 20.f, &font_cfg);
m_monospace_font = ImGui::GetIO().Fonts->AddFontDefault();
g_gui.dx_init();
g_renderer = this;
}
renderer::~renderer()
{
ImGui_ImplWin32_Shutdown();
ImGui_ImplDX11_Shutdown();
ImGui::DestroyContext();
g_renderer = nullptr;
}
void renderer::on_present()
{
if (g_gui.m_opened)
{
ImGui::GetIO().MouseDrawCursor = true;
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
}
else
{
ImGui::GetIO().MouseDrawCursor = false;
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouse;
}
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
if (g_gui.m_opened)
{
g_gui.dx_on_tick();
}
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
void renderer::pre_reset()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
}
void renderer::post_reset()
{
ImGui_ImplDX11_CreateDeviceObjects();
}
void renderer::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (msg == WM_KEYUP && wparam == VK_INSERT)
g_gui.m_opened ^= true;
if (g_gui.m_opened)
{
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
}
}
}

29
src/renderer.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "common.hpp"
#include "imgui/imgui.h"
namespace big
{
class renderer
{
public:
explicit renderer();
~renderer();
void on_present();
void pre_reset();
void post_reset();
void wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
public:
ImFont *m_font;
ImFont *m_monospace_font;
private:
comptr<IDXGISwapChain> m_dxgi_swapchain;
comptr<ID3D11Device> m_d3d_device;
comptr<ID3D11DeviceContext> m_d3d_device_context;
};
inline renderer *g_renderer{};
}

92
src/script.cpp Normal file
View File

@ -0,0 +1,92 @@
#pragma once
#include "common.hpp"
#include "logger.hpp"
#include "script.hpp"
namespace big
{
static void script_exception_handler(PEXCEPTION_POINTERS exp)
{
LOG_ERROR("Script threw an exception!");
g_stackwalker.ShowCallstack(GetCurrentThread(), exp->ContextRecord);
}
script::script(func_t func, std::optional<std::size_t> stack_size) :
m_func(func),
m_script_fiber(nullptr),
m_main_fiber(nullptr)
{
m_script_fiber = CreateFiber(stack_size.has_value() ? stack_size.value() : 0, [](void* param)
{
auto this_script = static_cast<script*>(param);
this_script->fiber_func();
}, this);
}
script::~script()
{
if (m_script_fiber)
DeleteFiber(m_script_fiber);
}
void script::tick()
{
m_main_fiber = GetCurrentFiber();
if (!m_wake_time.has_value() || m_wake_time.value() <= std::chrono::high_resolution_clock::now())
{
SwitchToFiber(m_script_fiber);
}
}
void script::yield(std::optional<std::chrono::high_resolution_clock::duration> time)
{
if (time.has_value())
{
m_wake_time = std::chrono::high_resolution_clock::now() + time.value();
}
else
{
m_wake_time = std::nullopt;
}
SwitchToFiber(m_main_fiber);
}
script *script::get_current()
{
return static_cast<script*>(GetFiberData());
}
void script::fiber_func()
{
__try
{
[this]()
{
try
{
m_func();
}
catch (std::exception const &ex)
{
auto ex_class = typeid(ex).name() + 6;
LOG_INFO("Script threw an C++ expection! {}: {}", ex_class, ex.what());
}
catch (...)
{
LOG_INFO("Script threw a C++ exception!");
}
}();
}
__except (script_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
{
LOG_INFO("Script threw an exception!");
}
LOG_INFO("Script finished!");
while (true)
{
yield();
}
}
}

25
src/script.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "common.hpp"
namespace big
{
class script
{
public:
using func_t = void(*)();
public:
explicit script(func_t func, std::optional<std::size_t> stack_size = std::nullopt);
~script();
void tick();
void yield(std::optional<std::chrono::high_resolution_clock::duration> time = std::nullopt);
static script *get_current();
private:
void fiber_func();
private:
void *m_script_fiber;
void *m_main_fiber;
func_t m_func;
std::optional<std::chrono::high_resolution_clock::time_point> m_wake_time;
};
}

26
src/script_global.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "common.hpp"
#include "pointers.hpp"
#include "script_global.hpp"
namespace big
{
script_global::script_global(std::size_t index) :
m_index(index)
{
}
script_global script_global::at(std::ptrdiff_t index)
{
return script_global(m_index + index);
}
script_global script_global::at(std::ptrdiff_t index, std::size_t size)
{
return script_global(m_index + 1 + (index * size));
}
void *script_global::get()
{
return g_pointers->m_script_globals[m_index >> 0x12 & 0x3F] + (m_index & 0x3FFFF);
}
}

29
src/script_global.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "common.hpp"
namespace big
{
class script_global
{
public:
explicit script_global(std::size_t index);
script_global at(std::ptrdiff_t index);
script_global at(std::ptrdiff_t index, std::size_t size);
template <typename T>
std::enable_if_t<std::is_pointer_v<T>, T> as()
{
return static_cast<T>(get());
}
template <typename T>
std::enable_if_t<std::is_lvalue_reference_v<T>, T> as()
{
return *static_cast<std::add_pointer_t<std::remove_reference_t<T>>>(get());
}
private:
void *get();
std::size_t m_index;
};
}

107
src/script_hook.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "common.hpp"
#include "crossmap.hpp"
#include "gta/script_program.hpp"
#include "logger.hpp"
#include "pointers.hpp"
#include "script_hook.hpp"
namespace big
{
inline std::unordered_map<rage::scrProgram*, script_hook*> script_hook::s_map;
static bool map_native(rage::scrNativeHash *hash)
{
for (auto const &mapping : g_crossmap)
{
if (mapping.first == *hash)
{
*hash = mapping.second;
return true;
}
}
return false;
}
script_hook::script_hook(rage::joaat_t script_hash, std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements) :
m_script_hash(script_hash),
m_native_replacements(std::move(native_replacements))
{
ensure();
}
script_hook::~script_hook()
{
if (m_program)
{
for (auto[hash, handler_ptr] : m_native_handler_ptrs)
{
auto og_handler = g_pointers->m_get_native_handler(g_pointers->m_native_registration_table, hash);
*handler_ptr = og_handler;
}
}
if (m_vmt_hook)
{
m_vmt_hook->disable();
s_map.erase(m_program);
}
}
void script_hook::ensure()
{
if (m_vmt_hook)
return;
if (auto program = g_pointers->m_script_program_table->find_script(m_script_hash))
{
if (program->is_valid())
{
hook_instance(program);
LOG_INFO("Hooked {} script ({})", program->m_name, static_cast<void*>(program));
}
}
}
void script_hook::hook_instance(rage::scrProgram *program)
{
m_program = program;
s_map.emplace(m_program, this);
m_vmt_hook = std::make_unique<vmt_hook>(m_program, 3);
m_vmt_hook->hook(0, &scrprogram_dtor);
for (auto [replacement_hash, replacement_handler] : m_native_replacements)
{
auto hash = replacement_hash;
map_native(&hash);
auto og_handler = g_pointers->m_get_native_handler(g_pointers->m_native_registration_table, hash);
if (!og_handler)
continue;
auto handler_ptr = m_program->get_address_of_native_entrypoint(og_handler);
if (!handler_ptr)
continue;
m_native_handler_ptrs.emplace(hash, reinterpret_cast<rage::scrNativeHandler*>(handler_ptr));
*handler_ptr = replacement_handler;
}
}
void script_hook::scrprogram_dtor(rage::scrProgram *this_, bool free_memory)
{
if (auto it = s_map.find(this_); it != s_map.end())
{
auto hook = it->second;
hook->m_program = nullptr;
s_map.erase(it);
auto og_func = hook->m_vmt_hook->get_original<decltype(&scrprogram_dtor)>(0);
hook->m_vmt_hook->disable();
hook->m_vmt_hook.reset();
og_func(this_, free_memory);
}
}
}

29
src/script_hook.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "common.hpp"
#include "gta/fwddec.hpp"
#include "gta/joaat.hpp"
#include "gta/natives.hpp"
#include "vmt_hook.hpp"
namespace big
{
class script_hook
{
public:
explicit script_hook(rage::joaat_t script_hash, std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements);
~script_hook();
void ensure();
private:
void hook_instance(rage::scrProgram *program);
static void scrprogram_dtor(rage::scrProgram *this_, bool free_memory);
static std::unordered_map<rage::scrProgram*, script_hook*> s_map;
rage::joaat_t m_script_hash;
rage::scrProgram* m_program;
std::unique_ptr<vmt_hook> m_vmt_hook;
std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> m_native_replacements;
std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler*> m_native_handler_ptrs;
};
}

38
src/script_mgr.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "common.hpp"
#include "gta/array.hpp"
#include "gta/script_thread.hpp"
#include "gta/tls_context.hpp"
#include "gta_util.hpp"
#include "pointers.hpp"
#include "script_mgr.hpp"
namespace big
{
void script_mgr::add_script(std::unique_ptr<script> script)
{
std::lock_guard lock(m_mutex);
m_scripts.push_back(std::move(script));
}
void script_mgr::remove_all_scripts()
{
std::lock_guard lock(m_mutex);
m_scripts.clear();
}
void script_mgr::tick()
{
gta_util::execute_as_script(RAGE_JOAAT("main_persistent"), std::mem_fn(&script_mgr::tick_internal), this);
}
void script_mgr::tick_internal()
{
static bool ensure_main_fiber = (ConvertThreadToFiber(nullptr), true);
std::lock_guard lock(m_mutex);
for (auto const &script : m_scripts)
{
script->tick();
}
}
}

25
src/script_mgr.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "common.hpp"
#include "script.hpp"
namespace big
{
class script_mgr
{
public:
explicit script_mgr() = default;
~script_mgr() = default;
void add_script(std::unique_ptr<script> script);
void remove_all_scripts();
void tick();
private:
void tick_internal();
private:
std::recursive_mutex m_mutex;
std::vector<std::unique_ptr<script>> m_scripts;
};
inline script_mgr g_script_mgr;
}

34
src/vmt_hook.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "common.hpp"
#include "vmt_hook.hpp"
namespace big
{
vmt_hook::vmt_hook(void* obj, std::size_t num_funcs) :
m_object(static_cast<void***>(obj)),
m_num_funcs(num_funcs + 1),
m_original_table(*m_object),
m_new_table(std::make_unique<void*[]>(m_num_funcs))
{
std::copy_n(m_original_table - 1, m_num_funcs, m_new_table.get());
}
void vmt_hook::hook(std::size_t index, void* func)
{
m_new_table[index + 1] = func;
}
void vmt_hook::unhook(std::size_t index)
{
m_new_table[index + 1] = m_original_table[index];
}
void vmt_hook::enable()
{
*m_object = m_new_table.get() + 1;
}
void vmt_hook::disable()
{
*m_object = m_original_table;
}
}

37
src/vmt_hook.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include "common.hpp"
namespace big
{
class vmt_hook
{
public:
explicit vmt_hook(void* obj, std::size_t num_funcs);
vmt_hook(vmt_hook&& that) = delete;
vmt_hook& operator=(vmt_hook&& that) = delete;
vmt_hook(vmt_hook const&) = delete;
vmt_hook& operator=(vmt_hook const&) = delete;
void hook(std::size_t index, void* func);
void unhook(std::size_t index);
template <typename T>
T get_original(std::size_t index);
void enable();
void disable();
private:
void*** m_object;
std::size_t m_num_funcs;
void** m_original_table;
std::unique_ptr<void*[]> m_new_table;
};
template<typename T>
inline T vmt_hook::get_original(std::size_t index)
{
return static_cast<T>(m_original_table[index]);
}
}