commit 759118f8307ca9b4358d6811a1bfc109e05fbc18 Author: CallowBlack <37184274+CallowBlack@users.noreply.github.com> Date: Sun Feb 27 14:38:51 2022 +0300 Add project files. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## 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 + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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/ + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# 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/ + +# 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/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/cheat-library/cheat-library.vcxproj b/cheat-library/cheat-library.vcxproj new file mode 100644 index 0000000..f0ce3a5 --- /dev/null +++ b/cheat-library/cheat-library.vcxproj @@ -0,0 +1,271 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {704c8746-1bd9-4bc8-9ebe-8187f1a1ad72} + cheatlibrary + 10.0 + + + + DynamicLibrary + true + v143 + MultiByte + + + DynamicLibrary + false + v143 + true + MultiByte + + + DynamicLibrary + true + v143 + MultiByte + + + DynamicLibrary + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + CLibrary + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + + + BuildCompile + + + true + CLibrary + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + Run + + + true + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + CLibrary + + + BuildCompile + + + true + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + CLibrary + Run + + + + Level3 + true + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING; _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;WIN32;_DEBUG;CHEATLIBRARY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + Default + $(ProjectDir)src/appdata;$(ProjectDir)src/framework;$(ProjectDir)src/user;$(ProjectDir)vendor/include; + + + Windows + true + false + false + $(ProjectDir)vendor/libraries/ + HookLib\HookLib-$(PlatformShortName)-$(Configuration).lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + copy "$(OutDir)$(TargetName)$(TargetExt)" /Y "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\CLibrary.dll" + + + cd $(ProjectDir)batch +inject-dll.bat "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\injector.exe" "$(OutDir)$(TargetFileName)" "GenshinImpact.exe" + + + + + + + Level3 + true + true + true + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING; _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;WIN32;NDEBUG;CHEATLIBRARY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + Default + $(ProjectDir)src/appdata;$(ProjectDir)src/framework;$(ProjectDir)src/user;$(ProjectDir)vendor/include; + + + Windows + true + true + true + false + false + $(ProjectDir)vendor/libraries/ + spdlogd.lib;HookLib\HookLib-$(PlatformShortName)-$(Configuration).lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + copy "$(OutDir)$(TargetName)$(TargetExt)" /Y "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\CLibrary.dll" + + + + + Level3 + true + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING; _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_DEBUG;CHEATLIBRARY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch-il2cpp.h + $(ProjectDir)src/appdata;$(ProjectDir)src/framework;$(ProjectDir)src/user;$(ProjectDir)vendor/include; + stdcpp17 + + + Default + true + + + Windows + true + false + false + $(ProjectDir)vendor/libraries/ + HookLib\HookLib-$(PlatformShortName)-$(Configuration).lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + +copy "$(OutDir)$(TargetName)$(TargetExt)" /Y "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\CLibrary.dll" +exit 0 + + + cd $(ProjectDir)batch +inject-dll.bat "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\injector.exe" "$(OutDir)$(TargetFileName)" "GenshinImpact.exe" + + + + + + + Level3 + true + true + true + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING; _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;NDEBUG;CHEATLIBRARY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + Default + $(ProjectDir)src/appdata;$(ProjectDir)src/framework;$(ProjectDir)src/user;$(ProjectDir)vendor/include; + + + Windows + true + true + true + false + false + $(ProjectDir)vendor/libraries/ + spdlogd.lib;HookLib\HookLib-$(PlatformShortName)-$(Configuration).lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + copy "$(OutDir)$(TargetName)$(TargetExt)" /Y "$(SolutionDir)injector\bin\$(PlatformShortName)\$(Configuration)\CLibrary.dll" + + + + + + + + + + + + + + + + + + + + + + + + + + CppCode + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/cheat-library/cheat-library.vcxproj.filters b/cheat-library/cheat-library.vcxproj.filters new file mode 100644 index 0000000..e239ffc --- /dev/null +++ b/cheat-library/cheat-library.vcxproj.filters @@ -0,0 +1,111 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Source Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + \ No newline at end of file diff --git a/cheat-library/packages.config b/cheat-library/packages.config new file mode 100644 index 0000000..0231060 --- /dev/null +++ b/cheat-library/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/cheat-library/src/appdata/il2cpp-api-functions-ptr.h b/cheat-library/src/appdata/il2cpp-api-functions-ptr.h new file mode 100644 index 0000000..a354981 --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-api-functions-ptr.h @@ -0,0 +1,207 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +// ****************************************************************************** +// * IL2CPP API function pointers +// ****************************************************************************** + +#define il2cpp_add_internal_call_ptr 0x084D67A0 +#define il2cpp_alloc_ptr 0x084D67B0 +#define il2cpp_array_class_get_ptr 0x084D67C0 +#define il2cpp_array_element_size_ptr 0x084D67D0 +#define il2cpp_array_get_byte_length_ptr 0x084D67E0 +#define il2cpp_array_length_ptr 0x084D67F0 +#define il2cpp_array_new_ptr 0x084D6800 +#define il2cpp_array_new_full_ptr 0x084D6810 +#define il2cpp_array_new_specific_ptr 0x084D6820 +#define il2cpp_assembly_get_image_ptr 0x084D6830 +#define il2cpp_bounded_array_class_get_ptr 0x084D6840 +#define il2cpp_capture_memory_snapshot_ptr 0x084D6850 +#define il2cpp_class_array_element_size_ptr 0x084D6860 +#define il2cpp_class_enum_basetype_ptr 0x084D6870 +#define il2cpp_class_from_il2cpp_type_ptr 0x084D68A0 +#define il2cpp_class_from_name_ptr 0x084D6880 +#define il2cpp_class_from_system_type_ptr 0x084D6890 +#define il2cpp_class_from_type_ptr 0x084D68A0 +#define il2cpp_class_get_assemblyname_ptr 0x084D68B0 +#define il2cpp_class_get_bitmap_ptr 0x084D68C0 +#define il2cpp_class_get_bitmap_size_ptr 0x084D68E0 +#define il2cpp_class_get_declaring_type_ptr 0x084D68F0 +#define il2cpp_class_get_element_class_ptr 0x084D6900 +#define il2cpp_class_get_events_ptr 0x084D6910 +#define il2cpp_class_get_field_from_name_ptr 0x084D6920 +#define il2cpp_class_get_fields_ptr 0x084D6930 +#define il2cpp_class_get_flags_ptr 0x084D6940 +#define il2cpp_class_get_image_ptr 0x084D6EF0 +#define il2cpp_class_get_interfaces_ptr 0x084D6950 +#define il2cpp_class_get_method_from_name_ptr 0x084D6960 +#define il2cpp_class_get_methods_ptr 0x084D6970 +#define il2cpp_class_get_name_ptr 0x084D7050 +#define il2cpp_class_get_namespace_ptr 0x084D7010 +#define il2cpp_class_get_nested_types_ptr 0x084D6980 +#define il2cpp_class_get_parent_ptr 0x084D6990 +#define il2cpp_class_get_properties_ptr 0x084D69A0 +#define il2cpp_class_get_property_from_name_ptr 0x084D69B0 +#define il2cpp_class_get_type_ptr 0x084D70A0 +#define il2cpp_class_has_attribute_ptr 0x084D69C0 +#define il2cpp_class_has_parent_ptr 0x084D69D0 +#define il2cpp_class_has_references_ptr 0x084D69E0 +#define il2cpp_class_instance_size_ptr 0x084D69F0 +#define il2cpp_class_is_abstract_ptr 0x084D6A00 +#define il2cpp_class_is_assignable_from_ptr 0x0048D2A0 +#define il2cpp_class_is_blittable_ptr 0x084D6A10 +#define il2cpp_class_is_enum_ptr 0x084D6A20 +#define il2cpp_class_is_generic_ptr 0x084D6A30 +#define il2cpp_class_is_inflated_ptr 0x084D6A40 +#define il2cpp_class_is_interface_ptr 0x084D6A50 +#define il2cpp_class_is_subclass_of_ptr 0x084D6A60 +#define il2cpp_class_is_valuetype_ptr 0x084D6A70 +#define il2cpp_class_num_fields_ptr 0x084D6A80 +#define il2cpp_class_value_size_ptr 0x084D6A90 +#define il2cpp_current_thread_get_frame_at_ptr 0x084D6AA0 +#define il2cpp_current_thread_get_stack_depth_ptr 0x084D6AB0 +#define il2cpp_current_thread_get_top_frame_ptr 0x084D6AD0 +#define il2cpp_current_thread_walk_frame_stack_ptr 0x084D6AE0 +#define il2cpp_domain_assembly_open_ptr 0x084D6AF0 +#define il2cpp_domain_get_ptr 0x084D6B00 +#define il2cpp_domain_get_assemblies_ptr 0x084D6B10 +#define il2cpp_enable_object_type_mutex_ptr 0x084D6B40 +#define il2cpp_exception_from_name_msg_ptr 0x084D6B50 +#define il2cpp_field_get_flags_ptr 0x084D6B60 +#define il2cpp_field_get_name_ptr 0x084D6EF0 +#define il2cpp_field_get_offset_ptr 0x084D6B70 +#define il2cpp_field_get_parent_ptr 0x084D7050 +#define il2cpp_field_get_type_ptr 0x084D6B80 +#define il2cpp_field_get_value_ptr 0x084D6B90 +#define il2cpp_field_get_value_object_ptr 0x084D6BA0 +#define il2cpp_field_has_attribute_ptr 0x084D6BB0 +#define il2cpp_field_set_value_ptr 0x084D6BC0 +#define il2cpp_field_set_value_object_ptr 0x084D6BD0 +#define il2cpp_field_static_get_value_ptr 0x084D6BE0 +#define il2cpp_field_static_set_value_ptr 0x084D6BF0 +#define il2cpp_format_exception_ptr 0x084D6C00 +#define il2cpp_format_stack_trace_ptr 0x084D6CB0 +#define il2cpp_free_ptr 0x084D6D60 +#define il2cpp_free_captured_memory_snapshot_ptr 0x084D6D70 +#define il2cpp_gc_collect_ptr 0x08520560 +#define il2cpp_gc_collect_a_little_ptr 0x084D6D80 +#define il2cpp_gc_disable_ptr 0x084D6D90 +#define il2cpp_gc_dump_append_text_to_log_ptr 0x084D6DA0 +#define il2cpp_gc_dump_info_ptr 0x084D6DB0 +#define il2cpp_gc_dump_set_large_allocated_block_found_callback_ptr 0x084D6DC0 +#define il2cpp_gc_dump_set_small_allocated_block_found_callback_ptr 0x084D6DD0 +#define il2cpp_gc_enable_ptr 0x084D6DE0 +#define il2cpp_gc_get_heap_size_ptr 0x084D6DF0 +#define il2cpp_gc_get_used_size_ptr 0x084D6E00 +#define il2cpp_gc_set_object_malloc_callback_ptr 0x084D6E10 +#define il2cpp_gc_set_object_return_freelist_callback_ptr 0x084D6E20 +#define il2cpp_gchandle_free_ptr 0x085116A0 +#define il2cpp_gchandle_get_target_ptr 0x084D6E30 +#define il2cpp_gchandle_new_ptr 0x084D6E40 +#define il2cpp_gchandle_new_weakref_ptr 0x084D6E50 +#define il2cpp_get_committed_memory_size_ptr 0x084D6E60 +#define il2cpp_get_corlib_ptr 0x084D6E70 +#define il2cpp_get_exception_argument_null_ptr 0x084D6E80 +#define il2cpp_get_gc_suspend_wait_tick_ptr 0x084D6E90 +#define il2cpp_get_hash_table_memory_ptr 0x084D6EA0 +#define il2cpp_get_meta_data_pool_memory_ptr 0x084D6EB0 +#define il2cpp_image_get_assembly_ptr 0x084D6ED0 +#define il2cpp_image_get_entry_point_ptr 0x084D6EE0 +#define il2cpp_image_get_filename_ptr 0x084D6EF0 +#define il2cpp_image_get_name_ptr 0x084D6EF0 +#define il2cpp_init_ptr 0x084D6F00 +#define il2cpp_init_security_ptr 0x084D6F30 +#define il2cpp_init_utf16_ptr 0x084D6F50 +#define il2cpp_is_vm_thread_ptr 0x084D7000 +#define il2cpp_method_get_class_ptr 0x084D7010 +#define il2cpp_method_get_declaring_type_ptr 0x084D7010 +#define il2cpp_method_get_flags_ptr 0x084D7020 +#define il2cpp_method_get_name_ptr 0x084D7050 +#define il2cpp_method_get_object_ptr 0x084D7060 +#define il2cpp_method_get_param_ptr 0x084D7070 +#define il2cpp_method_get_param_count_ptr 0x084D7080 +#define il2cpp_method_get_param_name_ptr 0x084D7090 +#define il2cpp_method_get_return_type_ptr 0x084D70A0 +#define il2cpp_method_get_token_ptr 0x084D70B0 +#define il2cpp_method_has_attribute_ptr 0x084D70C0 +#define il2cpp_method_is_generic_ptr 0x084D70D0 +#define il2cpp_method_is_inflated_ptr 0x084D70E0 +#define il2cpp_method_is_instance_ptr 0x084D70F0 +#define il2cpp_monitor_enter_ptr 0x084D7100 +#define il2cpp_monitor_exit_ptr 0x084D7110 +#define il2cpp_monitor_pulse_ptr 0x084D7120 +#define il2cpp_monitor_pulse_all_ptr 0x084D7130 +#define il2cpp_monitor_try_enter_ptr 0x084D7140 +#define il2cpp_monitor_try_wait_ptr 0x084D7150 +#define il2cpp_monitor_wait_ptr 0x084D7160 +#define il2cpp_object_get_class_ptr 0x084D6EF0 +#define il2cpp_object_get_size_ptr 0x084D7170 +#define il2cpp_object_get_virtual_method_ptr 0x084D7180 +#define il2cpp_object_new_ptr 0x084D7190 +#define il2cpp_object_unbox_ptr 0x084D71B0 +#define il2cpp_profiler_install_ptr 0x084D71C0 +#define il2cpp_profiler_install_allocation_ptr 0x084D71D0 +#define il2cpp_profiler_install_enter_leave_ptr 0x084D71E0 +#define il2cpp_profiler_install_fileio_ptr 0x084D71F0 +#define il2cpp_profiler_install_gc_ptr 0x084D7200 +#define il2cpp_profiler_set_events_ptr 0x084D7210 +#define il2cpp_property_get_flags_ptr 0x084D7220 +#define il2cpp_property_get_get_method_ptr 0x084D7050 +#define il2cpp_property_get_name_ptr 0x084D6B80 +#define il2cpp_property_get_parent_ptr 0x084D6EF0 +#define il2cpp_property_get_set_method_ptr 0x084D7010 +#define il2cpp_raise_exception_ptr 0x084D7230 +#define il2cpp_register_filedelete_callback_ptr 0x084D7240 +#define il2cpp_register_filemodify_callback_ptr 0x084D7250 +#define il2cpp_register_log_callback_ptr 0x084D7260 +#define il2cpp_resolve_icall_ptr 0x084D7270 +#define il2cpp_runtime_class_init_ptr 0x084D7280 +#define il2cpp_runtime_invoke_ptr 0x084D7290 +#define il2cpp_runtime_invoke_convert_args_ptr 0x084D72B0 +#define il2cpp_runtime_object_init_ptr 0x084D72D0 +#define il2cpp_runtime_object_init_exception_ptr 0x084D72E0 +#define il2cpp_runtime_unhandled_exception_policy_set_ptr 0x084D72F0 +#define il2cpp_set_commandline_arguments_ptr 0x084D7300 +#define il2cpp_set_commandline_arguments_utf16_ptr 0x084D7310 +#define il2cpp_set_config_ptr 0x084D7320 +#define il2cpp_set_config_dir_ptr 0x084D7330 +#define il2cpp_set_config_utf16_ptr 0x084D7340 +#define il2cpp_set_data_dir_ptr 0x084D7350 +#define il2cpp_set_disable_gc_parallel_mark_ptr 0x084D7360 +#define il2cpp_set_find_plugin_callback_ptr 0x084D7370 +#define il2cpp_set_gc_suspend_wait_tick_ptr 0x084D7380 +#define il2cpp_set_memory_callbacks_ptr 0x084D7390 +#define il2cpp_set_output_redirected_file_path_ptr 0x084D73A0 +#define il2cpp_set_parallel_android_affinity_ptr 0x084D73B0 +#define il2cpp_set_parallel_android_cupcount_ptr 0x084D73C0 +#define il2cpp_set_temp_dir_ptr 0x084D73D0 +#define il2cpp_shutdown_ptr 0x084D73E0 +#define il2cpp_stats_dump_to_file_ptr 0x084D73F0 +#define il2cpp_stats_get_value_ptr 0x084D7670 +#define il2cpp_string_chars_ptr 0x084D76F0 +#define il2cpp_string_intern_ptr 0x084D7700 +#define il2cpp_string_is_interned_ptr 0x084D7710 +#define il2cpp_string_length_ptr 0x084D7720 +#define il2cpp_string_new_ptr 0x084D7730 +#define il2cpp_string_new_len_ptr 0x084D7740 +#define il2cpp_string_new_utf16_ptr 0x084D7750 +#define il2cpp_string_new_wrapper_ptr 0x084D7730 +#define il2cpp_thread_attach_ptr 0x084D7760 +#define il2cpp_thread_current_ptr 0x084D7770 +#define il2cpp_thread_detach_ptr 0x084D7780 +#define il2cpp_thread_get_all_attached_threads_ptr 0x084D7790 +#define il2cpp_thread_get_frame_at_ptr 0x084D77A0 +#define il2cpp_thread_get_name_ptr 0x084D77B0 +#define il2cpp_thread_get_stack_depth_ptr 0x084D77C0 +#define il2cpp_thread_get_top_frame_ptr 0x084D77D0 +#define il2cpp_thread_walk_frame_stack_ptr 0x084D77E0 +#define il2cpp_type_get_class_or_element_class_ptr 0x084D77F0 +#define il2cpp_type_get_name_ptr 0x084D7800 +#define il2cpp_type_get_object_ptr 0x084D78C0 +#define il2cpp_type_get_type_ptr 0x084D78D0 +#define il2cpp_unhandled_exception_ptr 0x084D78E0 +#define il2cpp_unity_liveness_calculation_begin_ptr 0x084D78F0 +#define il2cpp_unity_liveness_calculation_end_ptr 0x084D7900 +#define il2cpp_unity_liveness_calculation_from_root_ptr 0x084D7910 +#define il2cpp_unity_liveness_calculation_from_statics_ptr 0x084D7920 +#define il2cpp_value_box_ptr 0x0048CF00 diff --git a/cheat-library/src/appdata/il2cpp-api-functions.h b/cheat-library/src/appdata/il2cpp-api-functions.h new file mode 100644 index 0000000..57e2944 --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-api-functions.h @@ -0,0 +1,480 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +#include "il2cpp-appdata.h" + +#ifndef DO_API_NO_RETURN + +#define DO_API_NO_RETURN(r, n, p) DO_API(r,n,p) + +#endif + +DO_API(void, il2cpp_init, (const char* domain_name)); + +DO_API(void, il2cpp_init_utf16, (const Il2CppChar * domain_name)); + +DO_API(void, il2cpp_shutdown, ()); + +DO_API(void, il2cpp_set_config_dir, (const char *config_path)); + +DO_API(void, il2cpp_set_data_dir, (const char *data_path)); + +DO_API(void, il2cpp_set_temp_dir, (const char *temp_path)); + +DO_API(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir)); + +DO_API(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar * const argv[], const char* basedir)); + +DO_API(void, il2cpp_set_config_utf16, (const Il2CppChar * executablePath)); + +DO_API(void, il2cpp_set_config, (const char* executablePath)); + + + +DO_API(void, il2cpp_set_memory_callbacks, (Il2CppMemoryCallbacks * callbacks)); + +DO_API(const Il2CppImage*, il2cpp_get_corlib, ()); + +DO_API(void, il2cpp_add_internal_call, (const char* name, Il2CppMethodPointer method)); + +DO_API(Il2CppMethodPointer, il2cpp_resolve_icall, (const char* name)); + + + +DO_API(void*, il2cpp_alloc, (size_t size)); + +DO_API(void, il2cpp_free, (void* ptr)); + + + +// array + +DO_API(Il2CppClass*, il2cpp_array_class_get, (Il2CppClass * element_class, uint32_t rank)); + +DO_API(uint32_t, il2cpp_array_length, (Il2CppArray * array)); + +DO_API(uint32_t, il2cpp_array_get_byte_length, (Il2CppArray * array)); + +DO_API(Il2CppArray*, il2cpp_array_new, (Il2CppClass * elementTypeInfo, il2cpp_array_size_t length)); + +DO_API(Il2CppArray*, il2cpp_array_new_specific, (Il2CppClass * arrayTypeInfo, il2cpp_array_size_t length)); + +DO_API(Il2CppArray*, il2cpp_array_new_full, (Il2CppClass * array_class, il2cpp_array_size_t * lengths, il2cpp_array_size_t * lower_bounds)); + +DO_API(Il2CppClass*, il2cpp_bounded_array_class_get, (Il2CppClass * element_class, uint32_t rank, bool bounded)); + +DO_API(int, il2cpp_array_element_size, (const Il2CppClass * array_class)); + + + +// assembly + +DO_API(const Il2CppImage*, il2cpp_assembly_get_image, (const Il2CppAssembly * assembly)); + + + +// class + +DO_API(const Il2CppType*, il2cpp_class_enum_basetype, (Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_generic, (const Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_inflated, (const Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_assignable_from, (Il2CppClass * klass, Il2CppClass * oklass)); + +DO_API(bool, il2cpp_class_is_subclass_of, (Il2CppClass * klass, Il2CppClass * klassc, bool check_interfaces)); + +DO_API(bool, il2cpp_class_has_parent, (Il2CppClass * klass, Il2CppClass * klassc)); + +DO_API(Il2CppClass*, il2cpp_class_from_il2cpp_type, (const Il2CppType * type)); + +DO_API(Il2CppClass*, il2cpp_class_from_name, (const Il2CppImage * image, const char* namespaze, const char *name)); + +DO_API(Il2CppClass*, il2cpp_class_from_system_type, (Il2CppReflectionType * type)); + +DO_API(Il2CppClass*, il2cpp_class_get_element_class, (Il2CppClass * klass)); + +DO_API(const EventInfo*, il2cpp_class_get_events, (Il2CppClass * klass, void* *iter)); + +DO_API(FieldInfo*, il2cpp_class_get_fields, (Il2CppClass * klass, void* *iter)); + +DO_API(Il2CppClass*, il2cpp_class_get_nested_types, (Il2CppClass * klass, void* *iter)); + +DO_API(Il2CppClass*, il2cpp_class_get_interfaces, (Il2CppClass * klass, void* *iter)); + +DO_API(const PropertyInfo*, il2cpp_class_get_properties, (Il2CppClass * klass, void* *iter)); + +DO_API(const PropertyInfo*, il2cpp_class_get_property_from_name, (Il2CppClass * klass, const char *name)); + +DO_API(FieldInfo*, il2cpp_class_get_field_from_name, (Il2CppClass * klass, const char *name)); + +DO_API(const MethodInfo*, il2cpp_class_get_methods, (Il2CppClass * klass, void* *iter)); + +DO_API(const MethodInfo*, il2cpp_class_get_method_from_name, (Il2CppClass * klass, const char* name, int argsCount)); + +DO_API(const char*, il2cpp_class_get_name, (Il2CppClass * klass)); + +DO_API(const char*, il2cpp_class_get_namespace, (Il2CppClass * klass)); + +DO_API(Il2CppClass*, il2cpp_class_get_parent, (Il2CppClass * klass)); + +DO_API(Il2CppClass*, il2cpp_class_get_declaring_type, (Il2CppClass * klass)); + +DO_API(int32_t, il2cpp_class_instance_size, (Il2CppClass * klass)); + +DO_API(size_t, il2cpp_class_num_fields, (const Il2CppClass * enumKlass)); + +DO_API(bool, il2cpp_class_is_valuetype, (const Il2CppClass * klass)); + +DO_API(int32_t, il2cpp_class_value_size, (Il2CppClass * klass, uint32_t * align)); + +DO_API(bool, il2cpp_class_is_blittable, (const Il2CppClass * klass)); + +DO_API(int, il2cpp_class_get_flags, (const Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_abstract, (const Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_interface, (const Il2CppClass * klass)); + +DO_API(int, il2cpp_class_array_element_size, (const Il2CppClass * klass)); + +DO_API(Il2CppClass*, il2cpp_class_from_type, (const Il2CppType * type)); + +DO_API(const Il2CppType*, il2cpp_class_get_type, (Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_has_attribute, (Il2CppClass * klass, Il2CppClass * attr_class)); + +DO_API(bool, il2cpp_class_has_references, (Il2CppClass * klass)); + +DO_API(bool, il2cpp_class_is_enum, (const Il2CppClass * klass)); + +DO_API(const Il2CppImage*, il2cpp_class_get_image, (Il2CppClass * klass)); + +DO_API(const char*, il2cpp_class_get_assemblyname, (const Il2CppClass * klass)); + + + +// testing only + +DO_API(size_t, il2cpp_class_get_bitmap_size, (const Il2CppClass * klass)); + +DO_API(void, il2cpp_class_get_bitmap, (Il2CppClass * klass, size_t * bitmap)); + + + +// stats + +DO_API(bool, il2cpp_stats_dump_to_file, (const char *path)); + +DO_API(uint64_t, il2cpp_stats_get_value, (Il2CppStat stat)); + + + +// domain + +DO_API(Il2CppDomain*, il2cpp_domain_get, ()); + +DO_API(const Il2CppAssembly*, il2cpp_domain_assembly_open, (Il2CppDomain * domain, const char* name)); + +DO_API(const Il2CppAssembly**, il2cpp_domain_get_assemblies, (const Il2CppDomain * domain, size_t * size)); + + + +// exception + +DO_API_NO_RETURN(void, il2cpp_raise_exception, (Il2CppException*)); + +DO_API(Il2CppException*, il2cpp_exception_from_name_msg, (const Il2CppImage * image, const char *name_space, const char *name, const char *msg)); + +DO_API(Il2CppException*, il2cpp_get_exception_argument_null, (const char *arg)); + +DO_API(void, il2cpp_format_exception, (const Il2CppException * ex, char* message, int message_size)); + +DO_API(void, il2cpp_format_stack_trace, (const Il2CppException * ex, char* output, int output_size)); + +DO_API(void, il2cpp_unhandled_exception, (Il2CppException*)); + + + +// field + +DO_API(int, il2cpp_field_get_flags, (FieldInfo * field)); + +DO_API(const char*, il2cpp_field_get_name, (FieldInfo * field)); + +DO_API(Il2CppClass*, il2cpp_field_get_parent, (FieldInfo * field)); + +DO_API(size_t, il2cpp_field_get_offset, (FieldInfo * field)); + +DO_API(const Il2CppType*, il2cpp_field_get_type, (FieldInfo * field)); + +DO_API(void, il2cpp_field_get_value, (Il2CppObject * obj, FieldInfo * field, void *value)); + +DO_API(Il2CppObject*, il2cpp_field_get_value_object, (FieldInfo * field, Il2CppObject * obj)); + +DO_API(bool, il2cpp_field_has_attribute, (FieldInfo * field, Il2CppClass * attr_class)); + +DO_API(void, il2cpp_field_set_value, (Il2CppObject * obj, FieldInfo * field, void *value)); + +DO_API(void, il2cpp_field_static_get_value, (FieldInfo * field, void *value)); + +DO_API(void, il2cpp_field_static_set_value, (FieldInfo * field, void *value)); + +DO_API(void, il2cpp_field_set_value_object, (Il2CppObject * instance, FieldInfo * field, Il2CppObject * value)); + + + +// gc + +DO_API(void, il2cpp_gc_collect, (int maxGenerations)); + +DO_API(int32_t, il2cpp_gc_collect_a_little, ()); + +DO_API(void, il2cpp_gc_disable, ()); + +DO_API(void, il2cpp_gc_enable, ()); + +DO_API(int64_t, il2cpp_gc_get_used_size, ()); + +DO_API(int64_t, il2cpp_gc_get_heap_size, ()); + + + +// gchandle + +DO_API(uint32_t, il2cpp_gchandle_new, (Il2CppObject * obj, bool pinned)); + +DO_API(uint32_t, il2cpp_gchandle_new_weakref, (Il2CppObject * obj, bool track_resurrection)); + +DO_API(Il2CppObject*, il2cpp_gchandle_get_target , (uint32_t gchandle)); + +DO_API(void, il2cpp_gchandle_free, (uint32_t gchandle)); + + + +// liveness + +DO_API(void*, il2cpp_unity_liveness_calculation_begin, (Il2CppClass * filter, int max_object_count, il2cpp_register_object_callback callback, void* userdata, il2cpp_WorldChangedCallback onWorldStarted, il2cpp_WorldChangedCallback onWorldStopped)); + +DO_API(void, il2cpp_unity_liveness_calculation_end, (void* state)); + +DO_API(void, il2cpp_unity_liveness_calculation_from_root, (Il2CppObject * root, void* state)); + +DO_API(void, il2cpp_unity_liveness_calculation_from_statics, (void* state)); + + + +// method + +DO_API(const Il2CppType*, il2cpp_method_get_return_type, (const MethodInfo * method)); + +DO_API(Il2CppClass*, il2cpp_method_get_declaring_type, (const MethodInfo * method)); + +DO_API(const char*, il2cpp_method_get_name, (const MethodInfo * method)); + +DO_API(Il2CppReflectionMethod*, il2cpp_method_get_object, (const MethodInfo * method, Il2CppClass * refclass)); + +DO_API(bool, il2cpp_method_is_generic, (const MethodInfo * method)); + +DO_API(bool, il2cpp_method_is_inflated, (const MethodInfo * method)); + +DO_API(bool, il2cpp_method_is_instance, (const MethodInfo * method)); + +DO_API(uint32_t, il2cpp_method_get_param_count, (const MethodInfo * method)); + +DO_API(const Il2CppType*, il2cpp_method_get_param, (const MethodInfo * method, uint32_t index)); + +DO_API(Il2CppClass*, il2cpp_method_get_class, (const MethodInfo * method)); + +DO_API(bool, il2cpp_method_has_attribute, (const MethodInfo * method, Il2CppClass * attr_class)); + +DO_API(uint32_t, il2cpp_method_get_flags, (const MethodInfo * method, uint32_t * iflags)); + +DO_API(uint32_t, il2cpp_method_get_token, (const MethodInfo * method)); + +DO_API(const char*, il2cpp_method_get_param_name, (const MethodInfo * method, uint32_t index)); + + + +// profiler + +#if IL2CPP_ENABLE_PROFILER + + + + + +#endif + + + +// property + +DO_API(uint32_t, il2cpp_property_get_flags, (PropertyInfo * prop)); + +DO_API(const MethodInfo*, il2cpp_property_get_get_method, (PropertyInfo * prop)); + +DO_API(const MethodInfo*, il2cpp_property_get_set_method, (PropertyInfo * prop)); + +DO_API(const char*, il2cpp_property_get_name, (PropertyInfo * prop)); + +DO_API(Il2CppClass*, il2cpp_property_get_parent, (PropertyInfo * prop)); + + + +// object + +DO_API(Il2CppClass*, il2cpp_object_get_class, (Il2CppObject * obj)); + +DO_API(uint32_t, il2cpp_object_get_size, (Il2CppObject * obj)); + +DO_API(const MethodInfo*, il2cpp_object_get_virtual_method, (Il2CppObject * obj, const MethodInfo * method)); + +DO_API(Il2CppObject*, il2cpp_object_new, (const Il2CppClass * klass)); + +DO_API(void*, il2cpp_object_unbox, (Il2CppObject * obj)); + + + +DO_API(Il2CppObject*, il2cpp_value_box, (Il2CppClass * klass, void* data)); + + + +// monitor + +DO_API(void, il2cpp_monitor_enter, (Il2CppObject * obj)); + +DO_API(bool, il2cpp_monitor_try_enter, (Il2CppObject * obj, uint32_t timeout)); + +DO_API(void, il2cpp_monitor_exit, (Il2CppObject * obj)); + +DO_API(void, il2cpp_monitor_pulse, (Il2CppObject * obj)); + +DO_API(void, il2cpp_monitor_pulse_all, (Il2CppObject * obj)); + +DO_API(void, il2cpp_monitor_wait, (Il2CppObject * obj)); + +DO_API(bool, il2cpp_monitor_try_wait, (Il2CppObject * obj, uint32_t timeout)); + + + +// runtime + +DO_API(Il2CppObject*, il2cpp_runtime_invoke, (const MethodInfo * method, void *obj, void **params, Il2CppException **exc)); + +DO_API(Il2CppObject*, il2cpp_runtime_invoke_convert_args, (const MethodInfo * method, void *obj, Il2CppObject **params, int paramCount, Il2CppException **exc)); + +DO_API(void, il2cpp_runtime_class_init, (Il2CppClass * klass)); + +DO_API(void, il2cpp_runtime_object_init, (Il2CppObject * obj)); + + + +DO_API(void, il2cpp_runtime_object_init_exception, (Il2CppObject * obj, Il2CppException** exc)); + + + +DO_API(void, il2cpp_runtime_unhandled_exception_policy_set, (Il2CppRuntimeUnhandledExceptionPolicy value)); + + + +// string + +DO_API(int32_t, il2cpp_string_length, (Il2CppString * str)); + +DO_API(Il2CppChar*, il2cpp_string_chars, (Il2CppString * str)); + +DO_API(Il2CppString*, il2cpp_string_new, (const char* str)); + +DO_API(Il2CppString*, il2cpp_string_new_len, (const char* str, uint32_t length)); + +DO_API(Il2CppString*, il2cpp_string_new_utf16, (const Il2CppChar * text, int32_t len)); + +DO_API(Il2CppString*, il2cpp_string_new_wrapper, (const char* str)); + +DO_API(Il2CppString*, il2cpp_string_intern, (Il2CppString * str)); + +DO_API(Il2CppString*, il2cpp_string_is_interned, (Il2CppString * str)); + + + +// thread + +DO_API(char*, il2cpp_thread_get_name, (Il2CppThread * thread, uint32_t * len)); + +DO_API(Il2CppThread*, il2cpp_thread_current, ()); + +DO_API(Il2CppThread*, il2cpp_thread_attach, (Il2CppDomain * domain)); + +DO_API(void, il2cpp_thread_detach, (Il2CppThread * thread)); + + + +DO_API(Il2CppThread**, il2cpp_thread_get_all_attached_threads, (size_t * size)); + +DO_API(bool, il2cpp_is_vm_thread, (Il2CppThread * thread)); + + + +// stacktrace + +DO_API(void, il2cpp_current_thread_walk_frame_stack, (Il2CppFrameWalkFunc func, void* user_data)); + +DO_API(void, il2cpp_thread_walk_frame_stack, (Il2CppThread * thread, Il2CppFrameWalkFunc func, void* user_data)); + +DO_API(bool, il2cpp_current_thread_get_top_frame, (Il2CppStackFrameInfo & frame)); + +DO_API(bool, il2cpp_thread_get_top_frame, (Il2CppThread * thread, Il2CppStackFrameInfo & frame)); + +DO_API(bool, il2cpp_current_thread_get_frame_at, (int32_t offset, Il2CppStackFrameInfo & frame)); + +DO_API(bool, il2cpp_thread_get_frame_at, (Il2CppThread * thread, int32_t offset, Il2CppStackFrameInfo & frame)); + +DO_API(int32_t, il2cpp_current_thread_get_stack_depth, ()); + +DO_API(int32_t, il2cpp_thread_get_stack_depth, (Il2CppThread * thread)); + + + +// type + +DO_API(Il2CppObject*, il2cpp_type_get_object, (const Il2CppType * type)); + +DO_API(int, il2cpp_type_get_type, (const Il2CppType * type)); + +DO_API(Il2CppClass*, il2cpp_type_get_class_or_element_class, (const Il2CppType * type)); + +DO_API(char*, il2cpp_type_get_name, (const Il2CppType * type)); + + + +// image + +DO_API(const Il2CppAssembly*, il2cpp_image_get_assembly, (const Il2CppImage * image)); + +DO_API(const char*, il2cpp_image_get_name, (const Il2CppImage * image)); + +DO_API(const char*, il2cpp_image_get_filename, (const Il2CppImage * image)); + +DO_API(const MethodInfo*, il2cpp_image_get_entry_point, (const Il2CppImage * image)); + + + +// Memory information + +DO_API(Il2CppManagedMemorySnapshot*, il2cpp_capture_memory_snapshot, ()); + +DO_API(void, il2cpp_free_captured_memory_snapshot, (Il2CppManagedMemorySnapshot * snapshot)); + + + +DO_API(void, il2cpp_set_find_plugin_callback, (Il2CppSetFindPlugInCallback method)); + + + +// Logging + +DO_API(void, il2cpp_register_log_callback, (Il2CppLogCallback method)); + + diff --git a/cheat-library/src/appdata/il2cpp-functions.h b/cheat-library/src/appdata/il2cpp-functions.h new file mode 100644 index 0000000..01fb34b --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-functions.h @@ -0,0 +1,45 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +// ****************************************************************************** +// * IL2CPP application-specific method definition addresses and signatures +// ****************************************************************************** +using namespace app; + +DO_APP_FUNC(0x05CDB4C0, void, Object__ctor, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x067D4FB0, bool, Object_Equals, (Object* __this, Object* obj, MethodInfo* method)); +DO_APP_FUNC(0x067D4F70, bool, Object_Equals_1, (void* __this, Object* objA, Object* objB, MethodInfo* method)); +DO_APP_FUNC(0x05CDB4C0, void, Object_Finalize, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x067D4FC0, int32_t, Object_GetHashCode, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x067D4FD0, Type*, Object_GetType, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x067D4FF0, Object*, Object_MemberwiseClone, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x067D5000, String*, Object_ToString, (Object* __this, MethodInfo* method)); +DO_APP_FUNC(0x079EA1F0, bool, Object_ReferenceEquals, (void* __this, Object* objA, Object* objB, MethodInfo* method)); +DO_APP_FUNC(0x067D4FE0, int32_t, Object_InternalGetHashCode, (void* __this, Object* o, MethodInfo* method)); +DO_APP_FUNC(0x067D5030, void*, Object_obj_address, (Object* __this, MethodInfo* method)); + +DO_APP_FUNC(0x052CC900, Byte__Array*, LuaManager_LoadCustomLuaFile, (LuaManager* __this, String** filePath, bool* recycleBytes, MethodInfo* method)); + +// ELIHHCKMPNE_ALEDHGAIDHN +DO_APP_FUNC(0x0175BD10, void, GameLogin_CheckGameIntegrity, (GameLogin* __this, String* someString, uint32_t someInt, MethodInfo* method)); + +DO_APP_FUNC(0x06C66FF0, String*, DateTime_ToLongDateString, (DateTime__Boxed* __this, MethodInfo* method)); +DO_APP_FUNC(0x06C67070, String*, DateTime_ToLongTimeString, (DateTime__Boxed* __this, MethodInfo* method)); +DO_APP_FUNC(0x06C671B0, double, DateTime_ToOADate, (DateTime__Boxed* __this, MethodInfo* method)); +DO_APP_FUNC(0x06C671C0, String*, DateTime_ToShortDateString, (DateTime__Boxed* __this, MethodInfo* method)); +DO_APP_FUNC(0x06C67200, String*, DateTime_ToShortTimeString, (DateTime__Boxed* __this, MethodInfo* method)); +DO_APP_FUNC(0x06C67500, String*, DateTime_ToString, (DateTime__Boxed* __this, MethodInfo* method)); + +DO_APP_FUNC(0x037B8580, void, GameLogin_SendInfo_2, (GameLogin* __this, GKOJAICIOPA* info, MethodInfo* method)); +DO_APP_FUNC_METHODINFO(0x0B25C800, GameLogin_SendInfo_2__MethodInfo); + +DO_APP_FUNC(0x03747530, void, GKOJAICIOPA_JINHMKCMECH, (GKOJAICIOPA* __this, String* JOJAAEDKLKK, MethodInfo* method)); +DO_APP_FUNC(0x03743E30, String*, GKOJAICIOPA_GJLJLNPHKBA, (GKOJAICIOPA* __this, MethodInfo* method)); + +DO_APP_FUNC(0x0705AB30, Array*, Array_CreateInstance, (void* __this, app::Type* elementType, int32_t length, MethodInfo* method)); +DO_APP_FUNC(0x0705E3C0, int32_t, Array_get_Length, (Array* __this, MethodInfo* method)); +DO_APP_FUNC(0x0705CC70, void, Array_SetValue_1, (Array* __this, Object* value, int64_t index, MethodInfo* method)); +DO_APP_FUNC_METHODINFO(0x0B1AA908, Array_SetValue_1__MethodInfo); + +DO_APP_FUNC(0x074AAAB0, Byte__Array*, Application_RecordUserData, (void* __this, int32_t nType, MethodInfo* method)); +DO_APP_FUNC(0x070598A0, Object*, Array_Clone, (Array* __this, MethodInfo* method)); \ No newline at end of file diff --git a/cheat-library/src/appdata/il2cpp-metadata-version.h b/cheat-library/src/appdata/il2cpp-metadata-version.h new file mode 100644 index 0000000..4dbb6ed --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-metadata-version.h @@ -0,0 +1,4 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +#define __IL2CPP_METADATA_VERSION 240 diff --git a/cheat-library/src/appdata/il2cpp-types-ptr.h b/cheat-library/src/appdata/il2cpp-types-ptr.h new file mode 100644 index 0000000..e0fb0df --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-types-ptr.h @@ -0,0 +1,8 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +// ****************************************************************************** +// * IL2CPP application-specific type definition addresses +// ****************************************************************************** + +DO_TYPEDEF(0x0B2FD1A8, Byte); \ No newline at end of file diff --git a/cheat-library/src/appdata/il2cpp-types.h b/cheat-library/src/appdata/il2cpp-types.h new file mode 100644 index 0000000..21aaf8b --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-types.h @@ -0,0 +1,3416 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Target Unity version: 2017.4.15 - 2017.4.40 + +#if defined(_GHIDRA_) || defined(_IDA_) +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +#endif + +#if defined(_GHIDRA_) +typedef __int64 size_t; +typedef size_t intptr_t; +typedef size_t uintptr_t; +#endif + +#if !defined(_GHIDRA_) && !defined(_IDA_) +#define _CPLUSPLUS_ +#endif + +// ****************************************************************************** +// * IL2CPP internal types +// ****************************************************************************** + +typedef uint32_t Il2CppMethodSlot; +const uint32_t kInvalidIl2CppMethodSlot = 65535; +const int ipv6AddressSize = 16; +typedef int32_t il2cpp_hresult_t; +typedef struct Il2CppClass Il2CppClass; +typedef struct Il2CppType Il2CppType; +typedef struct EventInfo EventInfo; +typedef struct MethodInfo MethodInfo; +typedef struct FieldInfo FieldInfo; +typedef struct PropertyInfo PropertyInfo; +typedef struct Il2CppAssembly Il2CppAssembly; +typedef struct Il2CppArray Il2CppArray; +typedef struct Il2CppDelegate Il2CppDelegate; +typedef struct Il2CppDomain Il2CppDomain; +typedef struct Il2CppImage Il2CppImage; +typedef struct Il2CppException Il2CppException; +typedef struct Il2CppProfiler Il2CppProfiler; +typedef struct Il2CppObject Il2CppObject; +typedef struct Il2CppReflectionMethod Il2CppReflectionMethod; +typedef struct Il2CppReflectionType Il2CppReflectionType; +typedef struct Il2CppString Il2CppString; +typedef struct Il2CppThread Il2CppThread; +typedef struct Il2CppAsyncResult Il2CppAsyncResult; +typedef enum Il2CppProfileFlags +{ + IL2CPP_PROFILE_NONE = 0, + IL2CPP_PROFILE_APPDOMAIN_EVENTS = 1 << 0, + IL2CPP_PROFILE_ASSEMBLY_EVENTS = 1 << 1, + IL2CPP_PROFILE_MODULE_EVENTS = 1 << 2, + IL2CPP_PROFILE_CLASS_EVENTS = 1 << 3, + IL2CPP_PROFILE_JIT_COMPILATION = 1 << 4, + IL2CPP_PROFILE_INLINING = 1 << 5, + IL2CPP_PROFILE_EXCEPTIONS = 1 << 6, + IL2CPP_PROFILE_ALLOCATIONS = 1 << 7, + IL2CPP_PROFILE_GC = 1 << 8, + IL2CPP_PROFILE_THREADS = 1 << 9, + IL2CPP_PROFILE_REMOTING = 1 << 10, + IL2CPP_PROFILE_TRANSITIONS = 1 << 11, + IL2CPP_PROFILE_ENTER_LEAVE = 1 << 12, + IL2CPP_PROFILE_COVERAGE = 1 << 13, + IL2CPP_PROFILE_INS_COVERAGE = 1 << 14, + IL2CPP_PROFILE_STATISTICAL = 1 << 15, + IL2CPP_PROFILE_METHOD_EVENTS = 1 << 16, + IL2CPP_PROFILE_MONITOR_EVENTS = 1 << 17, + IL2CPP_PROFILE_IOMAP_EVENTS = 1 << 18, + IL2CPP_PROFILE_GC_MOVES = 1 << 19, + IL2CPP_PROFILE_FILEIO = 1 << 20 +} Il2CppProfileFlags; +typedef enum Il2CppProfileFileIOKind +{ + IL2CPP_PROFILE_FILEIO_WRITE = 0, + IL2CPP_PROFILE_FILEIO_READ +} Il2CppProfileFileIOKind; +typedef enum Il2CppGCEvent +{ + IL2CPP_GC_EVENT_START, + IL2CPP_GC_EVENT_MARK_START, + IL2CPP_GC_EVENT_MARK_END, + IL2CPP_GC_EVENT_RECLAIM_START, + IL2CPP_GC_EVENT_RECLAIM_END, + IL2CPP_GC_EVENT_END, + IL2CPP_GC_EVENT_PRE_STOP_WORLD, + IL2CPP_GC_EVENT_POST_STOP_WORLD, + IL2CPP_GC_EVENT_PRE_START_WORLD, + IL2CPP_GC_EVENT_POST_START_WORLD +} Il2CppGCEvent; +typedef enum Il2CppStat +{ + IL2CPP_STAT_NEW_OBJECT_COUNT, + IL2CPP_STAT_INITIALIZED_CLASS_COUNT, + IL2CPP_STAT_METHOD_COUNT, + IL2CPP_STAT_CLASS_STATIC_DATA_SIZE, + IL2CPP_STAT_GENERIC_INSTANCE_COUNT, + IL2CPP_STAT_GENERIC_CLASS_COUNT, + IL2CPP_STAT_INFLATED_METHOD_COUNT, + IL2CPP_STAT_INFLATED_TYPE_COUNT, +} Il2CppStat; +typedef enum Il2CppRuntimeUnhandledExceptionPolicy +{ + IL2CPP_UNHANDLED_POLICY_LEGACY, + IL2CPP_UNHANDLED_POLICY_CURRENT +} Il2CppRuntimeUnhandledExceptionPolicy; +typedef struct Il2CppStackFrameInfo +{ + const MethodInfo* method; +} Il2CppStackFrameInfo; +typedef struct +{ + void* (*malloc_func)(size_t size); + void* (*aligned_malloc_func)(size_t size, size_t alignment); + void (*free_func)(void* ptr); + void (*aligned_free_func)(void* ptr); + void* (*calloc_func)(size_t nmemb, size_t size); + void* (*realloc_func)(void* ptr, size_t size); + void* (*aligned_realloc_func)(void* ptr, size_t size, size_t alignment); +} Il2CppMemoryCallbacks; +typedef uint16_t Il2CppChar; +typedef char Il2CppNativeChar; +typedef void (*il2cpp_register_object_callback)(Il2CppObject** arr, int size, void* userdata); +typedef void (*il2cpp_WorldChangedCallback)(); +typedef void (*Il2CppFrameWalkFunc) (const Il2CppStackFrameInfo* info, void* user_data); +typedef void (*Il2CppProfileFunc) (Il2CppProfiler* prof); +typedef void (*Il2CppProfileMethodFunc) (Il2CppProfiler* prof, const MethodInfo* method); +typedef void (*Il2CppProfileAllocFunc) (Il2CppProfiler* prof, Il2CppObject* obj, Il2CppClass* klass); +typedef void (*Il2CppProfileGCFunc) (Il2CppProfiler* prof, Il2CppGCEvent event, int generation); +typedef void (*Il2CppProfileGCResizeFunc) (Il2CppProfiler* prof, int64_t new_size); +typedef void (*Il2CppProfileFileIOFunc) (Il2CppProfiler* prof, Il2CppProfileFileIOKind kind, int count); +typedef const Il2CppNativeChar* (*Il2CppSetFindPlugInCallback)(const Il2CppNativeChar*); +typedef void (*Il2CppLogCallback)(const char*); +typedef struct Il2CppManagedMemorySnapshot Il2CppManagedMemorySnapshot; +typedef void (*Il2CppMethodPointer)(); +typedef uintptr_t il2cpp_array_size_t; +typedef struct Il2CppMetadataField +{ + uint32_t offset; + uint32_t typeIndex; + const char* name; + bool isStatic; +} Il2CppMetadataField; +typedef enum Il2CppMetadataTypeFlags +{ + kNone = 0, + kValueType = 1 << 0, + kArray = 1 << 1, + kArrayRankMask = 0xFFFF0000 +} Il2CppMetadataTypeFlags; +typedef struct Il2CppMetadataType +{ + Il2CppMetadataTypeFlags flags; + Il2CppMetadataField* fields; + uint32_t fieldCount; + uint32_t staticsSize; + uint8_t* statics; + uint32_t baseOrElementTypeIndex; + char* name; + const char* assemblyName; + uint64_t typeInfoAddress; + uint32_t size; +} Il2CppMetadataType; +typedef struct Il2CppMetadataSnapshot +{ + uint32_t typeCount; + Il2CppMetadataType* types; +} Il2CppMetadataSnapshot; +typedef struct Il2CppManagedMemorySection +{ + uint64_t sectionStartAddress; + uint32_t sectionSize; + uint8_t* sectionBytes; +} Il2CppManagedMemorySection; +typedef struct Il2CppManagedHeap +{ + uint32_t sectionCount; + Il2CppManagedMemorySection* sections; +} Il2CppManagedHeap; +typedef struct Il2CppStacks +{ + uint32_t stackCount; + Il2CppManagedMemorySection* stacks; +} Il2CppStacks; +typedef struct NativeObject +{ + uint32_t gcHandleIndex; + uint32_t size; + uint32_t instanceId; + uint32_t classId; + uint32_t referencedNativeObjectIndicesCount; + uint32_t* referencedNativeObjectIndices; +} NativeObject; +typedef struct Il2CppGCHandles +{ + uint32_t trackedObjectCount; + uint64_t* pointersToObjects; +} Il2CppGCHandles; +typedef struct Il2CppRuntimeInformation +{ + uint32_t pointerSize; + uint32_t objectHeaderSize; + uint32_t arrayHeaderSize; + uint32_t arrayBoundsOffsetInHeader; + uint32_t arraySizeOffsetInHeader; + uint32_t allocationGranularity; +} Il2CppRuntimeInformation; +typedef struct Il2CppManagedMemorySnapshot +{ + Il2CppManagedHeap heap; + Il2CppStacks stacks; + Il2CppMetadataSnapshot metadata; + Il2CppGCHandles gcHandles; + Il2CppRuntimeInformation runtimeInformation; + void* additionalUserInformation; +} Il2CppManagedMemorySnapshot; +typedef enum Il2CppTypeEnum +{ + IL2CPP_TYPE_END = 0x00, + IL2CPP_TYPE_VOID = 0x01, + IL2CPP_TYPE_BOOLEAN = 0x02, + IL2CPP_TYPE_CHAR = 0x03, + IL2CPP_TYPE_I1 = 0x04, + IL2CPP_TYPE_U1 = 0x05, + IL2CPP_TYPE_I2 = 0x06, + IL2CPP_TYPE_U2 = 0x07, + IL2CPP_TYPE_I4 = 0x08, + IL2CPP_TYPE_U4 = 0x09, + IL2CPP_TYPE_I8 = 0x0a, + IL2CPP_TYPE_U8 = 0x0b, + IL2CPP_TYPE_R4 = 0x0c, + IL2CPP_TYPE_R8 = 0x0d, + IL2CPP_TYPE_STRING = 0x0e, + IL2CPP_TYPE_PTR = 0x0f, + IL2CPP_TYPE_BYREF = 0x10, + IL2CPP_TYPE_VALUETYPE = 0x11, + IL2CPP_TYPE_CLASS = 0x12, + IL2CPP_TYPE_VAR = 0x13, + IL2CPP_TYPE_ARRAY = 0x14, + IL2CPP_TYPE_GENERICINST = 0x15, + IL2CPP_TYPE_TYPEDBYREF = 0x16, + IL2CPP_TYPE_I = 0x18, + IL2CPP_TYPE_U = 0x19, + IL2CPP_TYPE_FNPTR = 0x1b, + IL2CPP_TYPE_OBJECT = 0x1c, + IL2CPP_TYPE_SZARRAY = 0x1d, + IL2CPP_TYPE_MVAR = 0x1e, + IL2CPP_TYPE_CMOD_REQD = 0x1f, + IL2CPP_TYPE_CMOD_OPT = 0x20, + IL2CPP_TYPE_INTERNAL = 0x21, + IL2CPP_TYPE_MODIFIER = 0x40, + IL2CPP_TYPE_SENTINEL = 0x41, + IL2CPP_TYPE_PINNED = 0x45, + IL2CPP_TYPE_ENUM = 0x55 +} Il2CppTypeEnum; +typedef int32_t TypeIndex; +typedef int32_t TypeDefinitionIndex; +typedef int32_t FieldIndex; +typedef int32_t DefaultValueIndex; +typedef int32_t DefaultValueDataIndex; +typedef int32_t CustomAttributeIndex; +typedef int32_t ParameterIndex; +typedef int32_t MethodIndex; +typedef int32_t GenericMethodIndex; +typedef int32_t PropertyIndex; +typedef int32_t EventIndex; +typedef int32_t GenericContainerIndex; +typedef int32_t GenericParameterIndex; +typedef int16_t GenericParameterConstraintIndex; +typedef int32_t NestedTypeIndex; +typedef int32_t InterfacesIndex; +typedef int32_t VTableIndex; +typedef int32_t InterfaceOffsetIndex; +typedef int32_t RGCTXIndex; +typedef int32_t StringIndex; +typedef int32_t StringLiteralIndex; +typedef int32_t GenericInstIndex; +typedef int32_t ImageIndex; +typedef int32_t AssemblyIndex; +typedef int32_t InteropDataIndex; +const TypeIndex kTypeIndexInvalid = -1; +const TypeDefinitionIndex kTypeDefinitionIndexInvalid = -1; +const DefaultValueDataIndex kDefaultValueIndexNull = -1; +const EventIndex kEventIndexInvalid = -1; +const FieldIndex kFieldIndexInvalid = -1; +const MethodIndex kMethodIndexInvalid = -1; +const PropertyIndex kPropertyIndexInvalid = -1; +const GenericContainerIndex kGenericContainerIndexInvalid = -1; +const GenericParameterIndex kGenericParameterIndexInvalid = -1; +const RGCTXIndex kRGCTXIndexInvalid = -1; +const StringLiteralIndex kStringLiteralIndexInvalid = -1; +const InteropDataIndex kInteropDataIndexInvalid = -1; +typedef uint32_t EncodedMethodIndex; +typedef enum Il2CppMetadataUsage +{ + kIl2CppMetadataUsageInvalid, + kIl2CppMetadataUsageTypeInfo, + kIl2CppMetadataUsageIl2CppType, + kIl2CppMetadataUsageMethodDef, + kIl2CppMetadataUsageFieldInfo, + kIl2CppMetadataUsageStringLiteral, + kIl2CppMetadataUsageMethodRef, +} Il2CppMetadataUsage; +static inline Il2CppMetadataUsage GetEncodedIndexType(EncodedMethodIndex index) +{ + return (Il2CppMetadataUsage)((index & 0xE0000000) >> 29); +} +static inline uint32_t GetDecodedMethodIndex(EncodedMethodIndex index) +{ + return index & 0x1FFFFFFFU; +} +typedef struct Il2CppImage Il2CppImage; +typedef struct Il2CppType Il2CppType; +typedef struct Il2CppTypeDefinitionMetadata Il2CppTypeDefinitionMetadata; +typedef union Il2CppRGCTXDefinitionData +{ + int32_t rgctxDataDummy; + MethodIndex methodIndex; + TypeIndex typeIndex; +} Il2CppRGCTXDefinitionData; +typedef enum Il2CppRGCTXDataType +{ + IL2CPP_RGCTX_DATA_INVALID, + IL2CPP_RGCTX_DATA_TYPE, + IL2CPP_RGCTX_DATA_CLASS, + IL2CPP_RGCTX_DATA_METHOD, + IL2CPP_RGCTX_DATA_ARRAY, +} Il2CppRGCTXDataType; +typedef struct Il2CppRGCTXDefinition +{ + Il2CppRGCTXDataType type; + Il2CppRGCTXDefinitionData data; +} Il2CppRGCTXDefinition; +typedef struct Il2CppInterfaceOffsetPair +{ + TypeIndex interfaceTypeIndex; + int32_t offset; +} Il2CppInterfaceOffsetPair; +typedef struct Il2CppTypeDefinition +{ + StringIndex nameIndex; + StringIndex namespaceIndex; + CustomAttributeIndex customAttributeIndex; + TypeIndex byvalTypeIndex; + TypeIndex byrefTypeIndex; + TypeIndex declaringTypeIndex; + TypeIndex parentIndex; + TypeIndex elementTypeIndex; + RGCTXIndex rgctxStartIndex; + int32_t rgctxCount; + GenericContainerIndex genericContainerIndex; + uint32_t flags; + FieldIndex fieldStart; + MethodIndex methodStart; + EventIndex eventStart; + PropertyIndex propertyStart; + NestedTypeIndex nestedTypesStart; + InterfacesIndex interfacesStart; + VTableIndex vtableStart; + InterfacesIndex interfaceOffsetsStart; + uint16_t method_count; + uint16_t property_count; + uint16_t field_count; + uint16_t event_count; + uint16_t nested_type_count; + uint16_t vtable_count; + uint16_t interfaces_count; + uint16_t interface_offsets_count; + uint32_t bitfield; + uint32_t token; +} Il2CppTypeDefinition; +typedef struct Il2CppFieldDefinition +{ + StringIndex nameIndex; + TypeIndex typeIndex; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} Il2CppFieldDefinition; +typedef struct Il2CppFieldDefaultValue +{ + FieldIndex fieldIndex; + TypeIndex typeIndex; + DefaultValueDataIndex dataIndex; +} Il2CppFieldDefaultValue; +typedef struct Il2CppFieldMarshaledSize +{ + FieldIndex fieldIndex; + TypeIndex typeIndex; + int32_t size; +} Il2CppFieldMarshaledSize; +typedef struct Il2CppFieldRef +{ + TypeIndex typeIndex; + FieldIndex fieldIndex; +} Il2CppFieldRef; +typedef struct Il2CppParameterDefinition +{ + StringIndex nameIndex; + uint32_t token; + CustomAttributeIndex customAttributeIndex; + TypeIndex typeIndex; +} Il2CppParameterDefinition; +typedef struct Il2CppParameterDefaultValue +{ + ParameterIndex parameterIndex; + TypeIndex typeIndex; + DefaultValueDataIndex dataIndex; +} Il2CppParameterDefaultValue; +typedef struct Il2CppMethodDefinition +{ + StringIndex nameIndex; + TypeDefinitionIndex declaringType; + TypeIndex returnType; + ParameterIndex parameterStart; + CustomAttributeIndex customAttributeIndex; + GenericContainerIndex genericContainerIndex; + MethodIndex methodIndex; + MethodIndex invokerIndex; + MethodIndex reversePInvokeWrapperIndex; + RGCTXIndex rgctxStartIndex; + int32_t rgctxCount; + uint32_t token; + uint16_t flags; + uint16_t iflags; + uint16_t slot; + uint16_t parameterCount; +} Il2CppMethodDefinition; +typedef struct Il2CppEventDefinition +{ + StringIndex nameIndex; + TypeIndex typeIndex; + MethodIndex add; + MethodIndex remove; + MethodIndex raise; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} Il2CppEventDefinition; +typedef struct Il2CppPropertyDefinition +{ + StringIndex nameIndex; + MethodIndex get; + MethodIndex set; + uint32_t attrs; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} Il2CppPropertyDefinition; +typedef struct Il2CppMethodSpec +{ + MethodIndex methodDefinitionIndex; + GenericInstIndex classIndexIndex; + GenericInstIndex methodIndexIndex; +} Il2CppMethodSpec; +typedef struct Il2CppStringLiteral +{ + uint32_t length; + StringLiteralIndex dataIndex; +} Il2CppStringLiteral; +typedef struct Il2CppGenericMethodIndices +{ + MethodIndex methodIndex; + MethodIndex invokerIndex; +} Il2CppGenericMethodIndices; +typedef struct Il2CppGenericMethodFunctionsDefinitions +{ + GenericMethodIndex genericMethodIndex; + Il2CppGenericMethodIndices indices; +} Il2CppGenericMethodFunctionsDefinitions; +const int kPublicKeyByteLength = 8; +typedef struct Il2CppAssemblyName +{ + StringIndex nameIndex; + StringIndex cultureIndex; + StringIndex hashValueIndex; + StringIndex publicKeyIndex; + uint32_t hash_alg; + int32_t hash_len; + uint32_t flags; + int32_t major; + int32_t minor; + int32_t build; + int32_t revision; + uint8_t publicKeyToken[8]; +} Il2CppAssemblyName; +typedef struct Il2CppImageDefinition +{ + StringIndex nameIndex; + AssemblyIndex assemblyIndex; + TypeDefinitionIndex typeStart; + uint32_t typeCount; + TypeDefinitionIndex exportedTypeStart; + uint32_t exportedTypeCount; + MethodIndex entryPointIndex; + uint32_t token; +} Il2CppImageDefinition; +typedef struct Il2CppAssembly +{ + ImageIndex imageIndex; + CustomAttributeIndex customAttributeIndex; + int32_t referencedAssemblyStart; + int32_t referencedAssemblyCount; + Il2CppAssemblyName aname; +} Il2CppAssembly; +typedef struct Il2CppMetadataUsageList +{ + uint32_t start; + uint32_t count; +} Il2CppMetadataUsageList; +typedef struct Il2CppMetadataUsagePair +{ + uint32_t destinationIndex; + uint32_t encodedSourceIndex; +} Il2CppMetadataUsagePair; +typedef struct Il2CppCustomAttributeTypeRange +{ + int32_t start; + int32_t count; +} Il2CppCustomAttributeTypeRange; +typedef struct Il2CppRange +{ + int32_t start; + int32_t length; +} Il2CppRange; +typedef struct Il2CppWindowsRuntimeTypeNamePair +{ + StringIndex nameIndex; + TypeIndex typeIndex; +} Il2CppWindowsRuntimeTypeNamePair; +#pragma pack(push, p1,4) +typedef struct Il2CppGlobalMetadataHeader +{ + int32_t sanity; + int32_t version; + int32_t stringLiteralOffset; + int32_t stringLiteralCount; + int32_t stringLiteralDataOffset; + int32_t stringLiteralDataCount; + int32_t stringOffset; + int32_t stringCount; + int32_t eventsOffset; + int32_t eventsCount; + int32_t propertiesOffset; + int32_t propertiesCount; + int32_t methodsOffset; + int32_t methodsCount; + int32_t parameterDefaultValuesOffset; + int32_t parameterDefaultValuesCount; + int32_t fieldDefaultValuesOffset; + int32_t fieldDefaultValuesCount; + int32_t fieldAndParameterDefaultValueDataOffset; + int32_t fieldAndParameterDefaultValueDataCount; + int32_t fieldMarshaledSizesOffset; + int32_t fieldMarshaledSizesCount; + int32_t parametersOffset; + int32_t parametersCount; + int32_t fieldsOffset; + int32_t fieldsCount; + int32_t genericParametersOffset; + int32_t genericParametersCount; + int32_t genericParameterConstraintsOffset; + int32_t genericParameterConstraintsCount; + int32_t genericContainersOffset; + int32_t genericContainersCount; + int32_t nestedTypesOffset; + int32_t nestedTypesCount; + int32_t interfacesOffset; + int32_t interfacesCount; + int32_t vtableMethodsOffset; + int32_t vtableMethodsCount; + int32_t interfaceOffsetsOffset; + int32_t interfaceOffsetsCount; + int32_t typeDefinitionsOffset; + int32_t typeDefinitionsCount; + int32_t rgctxEntriesOffset; + int32_t rgctxEntriesCount; + int32_t imagesOffset; + int32_t imagesCount; + int32_t assembliesOffset; + int32_t assembliesCount; + int32_t metadataUsageListsOffset; + int32_t metadataUsageListsCount; + int32_t metadataUsagePairsOffset; + int32_t metadataUsagePairsCount; + int32_t fieldRefsOffset; + int32_t fieldRefsCount; + int32_t referencedAssembliesOffset; + int32_t referencedAssembliesCount; + int32_t attributesInfoOffset; + int32_t attributesInfoCount; + int32_t attributeTypesOffset; + int32_t attributeTypesCount; + int32_t unresolvedVirtualCallParameterTypesOffset; + int32_t unresolvedVirtualCallParameterTypesCount; + int32_t unresolvedVirtualCallParameterRangesOffset; + int32_t unresolvedVirtualCallParameterRangesCount; + int32_t windowsRuntimeTypeNamesOffset; + int32_t windowsRuntimeTypeNamesSize; + int32_t exportedTypeDefinitionsOffset; + int32_t exportedTypeDefinitionsCount; +} Il2CppGlobalMetadataHeader; +#pragma pack(pop, p1) +typedef struct Il2CppClass Il2CppClass; +typedef struct MethodInfo MethodInfo; +typedef struct Il2CppType Il2CppType; +typedef struct Il2CppArrayType +{ + const Il2CppType* etype; + uint8_t rank; + uint8_t numsizes; + uint8_t numlobounds; + int* sizes; + int* lobounds; +} Il2CppArrayType; +typedef struct Il2CppGenericInst +{ + uint32_t type_argc; + const Il2CppType** type_argv; +} Il2CppGenericInst; +typedef struct Il2CppGenericContext +{ + const Il2CppGenericInst* class_inst; + const Il2CppGenericInst* method_inst; +} Il2CppGenericContext; +typedef struct Il2CppGenericParameter +{ + GenericContainerIndex ownerIndex; + StringIndex nameIndex; + GenericParameterConstraintIndex constraintsStart; + int16_t constraintsCount; + uint16_t num; + uint16_t flags; +} Il2CppGenericParameter; +typedef struct Il2CppGenericContainer +{ + int32_t ownerIndex; + int32_t type_argc; + int32_t is_method; + GenericParameterIndex genericParameterStart; +} Il2CppGenericContainer; +typedef struct Il2CppGenericClass +{ + TypeDefinitionIndex typeDefinitionIndex; + Il2CppGenericContext context; + Il2CppClass* cached_class; +} Il2CppGenericClass; +typedef struct Il2CppGenericMethod +{ + const MethodInfo* methodDefinition; + Il2CppGenericContext context; +} Il2CppGenericMethod; +typedef struct Il2CppType +{ + union + { + void* dummy; + TypeDefinitionIndex klassIndex; + const Il2CppType* type; + Il2CppArrayType* array; + GenericParameterIndex genericParameterIndex; + Il2CppGenericClass* generic_class; + } data; + unsigned int attrs : 16; + Il2CppTypeEnum type : 8; + unsigned int num_mods : 6; + unsigned int byref : 1; + unsigned int pinned : 1; +} Il2CppType; +typedef enum +{ + IL2CPP_CALL_DEFAULT, + IL2CPP_CALL_C, + IL2CPP_CALL_STDCALL, + IL2CPP_CALL_THISCALL, + IL2CPP_CALL_FASTCALL, + IL2CPP_CALL_VARARG +} Il2CppCallConvention; +typedef enum Il2CppCharSet +{ + CHARSET_ANSI, + CHARSET_UNICODE +} Il2CppCharSet; +typedef struct Il2CppClass Il2CppClass; +typedef struct Il2CppGuid Il2CppGuid; +typedef struct Il2CppImage Il2CppImage; +typedef struct Il2CppAssembly Il2CppAssembly; +typedef struct Il2CppAppDomain Il2CppAppDomain; +typedef struct Il2CppAppDomainSetup Il2CppAppDomainSetup; +typedef struct Il2CppDelegate Il2CppDelegate; +typedef struct Il2CppAppContext Il2CppAppContext; +typedef struct Il2CppNameToTypeDefinitionIndexHashTable Il2CppNameToTypeDefinitionIndexHashTable; +typedef struct VirtualInvokeData +{ + Il2CppMethodPointer methodPtr; + const MethodInfo* method; +} VirtualInvokeData; +typedef enum Il2CppTypeNameFormat +{ + IL2CPP_TYPE_NAME_FORMAT_IL, + IL2CPP_TYPE_NAME_FORMAT_REFLECTION, + IL2CPP_TYPE_NAME_FORMAT_FULL_NAME, + IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED +} Il2CppTypeNameFormat; +extern bool g_il2cpp_is_fully_initialized; +typedef struct +{ + Il2CppImage* corlib; + Il2CppClass* object_class; + Il2CppClass* byte_class; + Il2CppClass* void_class; + Il2CppClass* boolean_class; + Il2CppClass* sbyte_class; + Il2CppClass* int16_class; + Il2CppClass* uint16_class; + Il2CppClass* int32_class; + Il2CppClass* uint32_class; + Il2CppClass* int_class; + Il2CppClass* uint_class; + Il2CppClass* int64_class; + Il2CppClass* uint64_class; + Il2CppClass* single_class; + Il2CppClass* double_class; + Il2CppClass* char_class; + Il2CppClass* string_class; + Il2CppClass* enum_class; + Il2CppClass* array_class; + Il2CppClass* delegate_class; + Il2CppClass* multicastdelegate_class; + Il2CppClass* asyncresult_class; + Il2CppClass* manualresetevent_class; + Il2CppClass* typehandle_class; + Il2CppClass* fieldhandle_class; + Il2CppClass* methodhandle_class; + Il2CppClass* systemtype_class; + Il2CppClass* monotype_class; + Il2CppClass* exception_class; + Il2CppClass* threadabortexception_class; + Il2CppClass* thread_class; + Il2CppClass* internal_thread_class; + Il2CppClass* appdomain_class; + Il2CppClass* appdomain_setup_class; + Il2CppClass* field_info_class; + Il2CppClass* method_info_class; + Il2CppClass* property_info_class; + Il2CppClass* event_info_class; + Il2CppClass* mono_event_info_class; + Il2CppClass* stringbuilder_class; + Il2CppClass* stack_frame_class; + Il2CppClass* stack_trace_class; + Il2CppClass* marshal_class; + Il2CppClass* typed_reference_class; + Il2CppClass* marshalbyrefobject_class; + Il2CppClass* generic_ilist_class; + Il2CppClass* generic_icollection_class; + Il2CppClass* generic_ienumerable_class; + Il2CppClass* generic_ireadonlylist_class; + Il2CppClass* generic_ireadonlycollection_class; + Il2CppClass* runtimetype_class; + Il2CppClass* generic_nullable_class; + Il2CppClass* il2cpp_com_object_class; + Il2CppClass* customattribute_data_class; + Il2CppClass* version; + Il2CppClass* culture_info; + Il2CppClass* async_call_class; + Il2CppClass* assembly_class; + Il2CppClass* mono_assembly_class; + Il2CppClass* assembly_name_class; + Il2CppClass* mono_field_class; + Il2CppClass* mono_method_class; + Il2CppClass* mono_method_info_class; + Il2CppClass* mono_property_info_class; + Il2CppClass* parameter_info_class; + Il2CppClass* mono_parameter_info_class; + Il2CppClass* module_class; + Il2CppClass* pointer_class; + Il2CppClass* system_exception_class; + Il2CppClass* argument_exception_class; + Il2CppClass* wait_handle_class; + Il2CppClass* safe_handle_class; + Il2CppClass* sort_key_class; + Il2CppClass* dbnull_class; + Il2CppClass* error_wrapper_class; + Il2CppClass* missing_class; + Il2CppClass* value_type_class; + Il2CppClass* threadpool_wait_callback_class; + MethodInfo* threadpool_perform_wait_callback_method; + Il2CppClass* mono_method_message_class; + Il2CppClass* ireference_class; + Il2CppClass* ikey_value_pair_class; + Il2CppClass* key_value_pair_class; + Il2CppClass* windows_foundation_uri_class; + Il2CppClass* windows_foundation_iuri_runtime_class_class; + Il2CppClass* system_uri_class; +} Il2CppDefaults; +extern Il2CppDefaults il2cpp_defaults; +typedef struct Il2CppClass Il2CppClass; +typedef struct MethodInfo MethodInfo; +typedef struct FieldInfo FieldInfo; +typedef struct Il2CppObject Il2CppObject; +typedef struct MemberInfo MemberInfo; +typedef struct CustomAttributesCache +{ + int count; + Il2CppObject** attributes; +} CustomAttributesCache; +typedef struct CustomAttributeTypeCache +{ + int count; + Il2CppClass** attributeTypes; +} CustomAttributeTypeCache; +typedef void (*CustomAttributesCacheGenerator)(CustomAttributesCache*); +const int THREAD_STATIC_FIELD_OFFSET = -1; +typedef struct FieldInfo +{ + const char* name; + const Il2CppType* type; + Il2CppClass* parent; + int32_t offset; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} FieldInfo; +typedef struct PropertyInfo +{ + Il2CppClass* parent; + const char* name; + const MethodInfo* get; + const MethodInfo* set; + uint32_t attrs; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} PropertyInfo; +typedef struct EventInfo +{ + const char* name; + const Il2CppType* eventType; + Il2CppClass* parent; + const MethodInfo* add; + const MethodInfo* remove; + const MethodInfo* raise; + CustomAttributeIndex customAttributeIndex; + uint32_t token; +} EventInfo; +typedef struct ParameterInfo +{ + const char* name; + int32_t position; + uint32_t token; + CustomAttributeIndex customAttributeIndex; + const Il2CppType* parameter_type; +} ParameterInfo; +typedef void* (*InvokerMethod)(Il2CppMethodPointer, const MethodInfo*, void*, void**); +typedef union Il2CppRGCTXData +{ + void* rgctxDataDummy; + const MethodInfo* method; + const Il2CppType* type; + Il2CppClass* klass; +} Il2CppRGCTXData; +typedef struct MethodInfo +{ + Il2CppMethodPointer methodPointer; + InvokerMethod invoker_method; + const char* name; + Il2CppClass* declaring_type; + const Il2CppType* return_type; + const ParameterInfo* parameters; + union + { + const Il2CppRGCTXData* rgctx_data; + const Il2CppMethodDefinition* methodDefinition; + }; + union + { + const Il2CppGenericMethod* genericMethod; + const Il2CppGenericContainer* genericContainer; + }; + CustomAttributeIndex customAttributeIndex; + uint32_t token; + uint16_t flags; + uint16_t iflags; + uint16_t slot; + uint8_t parameters_count; + uint8_t is_generic : 1; + uint8_t is_inflated : 1; +} MethodInfo; +typedef struct Il2CppRuntimeInterfaceOffsetPair +{ + Il2CppClass* interfaceType; + int32_t offset; +} Il2CppRuntimeInterfaceOffsetPair; +typedef void (*PInvokeMarshalToNativeFunc)(void* managedStructure, void* marshaledStructure); +typedef void (*PInvokeMarshalFromNativeFunc)(void* marshaledStructure, void* managedStructure); +typedef void (*PInvokeMarshalCleanupFunc)(void* marshaledStructure); +typedef struct Il2CppIUnknown* (*CreateCCWFunc)(Il2CppObject* obj); +typedef struct Il2CppInteropData +{ + Il2CppMethodPointer delegatePInvokeWrapperFunction; + PInvokeMarshalToNativeFunc pinvokeMarshalToNativeFunction; + PInvokeMarshalFromNativeFunc pinvokeMarshalFromNativeFunction; + PInvokeMarshalCleanupFunc pinvokeMarshalCleanupFunction; + CreateCCWFunc createCCWFunction; + const Il2CppGuid* guid; + const Il2CppType* type; +} Il2CppInteropData; +typedef struct Il2CppClass +{ + const Il2CppImage* image; + void* gc_desc; + const char* name; + const char* namespaze; + const Il2CppType* byval_arg; + const Il2CppType* this_arg; + Il2CppClass* element_class; + Il2CppClass* castClass; + Il2CppClass* declaringType; + Il2CppClass* parent; + Il2CppGenericClass* generic_class; + const Il2CppTypeDefinition* typeDefinition; + const Il2CppInteropData* interopData; + FieldInfo* fields; + const EventInfo* events; + const PropertyInfo* properties; + const MethodInfo** methods; + Il2CppClass** nestedTypes; + Il2CppClass** implementedInterfaces; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + void* static_fields; + const Il2CppRGCTXData* rgctx_data; + struct Il2CppClass** typeHierarchy; + uint32_t cctor_started; + uint32_t cctor_finished; + __declspec(align(8)) uint64_t cctor_thread; + GenericContainerIndex genericContainerIndex; + CustomAttributeIndex customAttributeIndex; + uint32_t instance_size; + uint32_t actualSize; + uint32_t element_size; + int32_t native_size; + uint32_t static_fields_size; + uint32_t thread_static_fields_size; + int32_t thread_static_fields_offset; + uint32_t flags; + uint32_t token; + uint16_t method_count; + uint16_t property_count; + uint16_t field_count; + uint16_t event_count; + uint16_t nested_type_count; + uint16_t vtable_count; + uint16_t interfaces_count; + uint16_t interface_offsets_count; + uint8_t typeHierarchyDepth; + uint8_t genericRecursionDepth; + uint8_t rank; + uint8_t minimumAlignment; + uint8_t packingSize; + uint8_t valuetype : 1; + uint8_t initialized : 1; + uint8_t enumtype : 1; + uint8_t is_generic : 1; + uint8_t has_references : 1; + uint8_t init_pending : 1; + uint8_t size_inited : 1; + uint8_t has_finalize : 1; + uint8_t has_cctor : 1; + uint8_t is_blittable : 1; + uint8_t is_import_or_windows_runtime : 1; + uint8_t is_vtable_initialized : 1; + VirtualInvokeData vtable[32]; +} Il2CppClass; + +typedef struct Il2CppClass_0 { + const Il2CppImage* image; + void* gc_desc; + const char* name; + const char* namespaze; + const Il2CppType* byval_arg; + const Il2CppType* this_arg; + Il2CppClass* element_class; + Il2CppClass* castClass; + Il2CppClass* declaringType; + Il2CppClass* parent; + Il2CppGenericClass* generic_class; + const Il2CppTypeDefinition* typeDefinition; + const Il2CppInteropData* interopData; + FieldInfo* fields; + const EventInfo* events; + const PropertyInfo* properties; + const MethodInfo** methods; + Il2CppClass** nestedTypes; + Il2CppClass** implementedInterfaces; +} Il2CppClass_0; + +typedef struct Il2CppClass_1 { + struct Il2CppClass** typeHierarchy; + uint32_t cctor_started; + uint32_t cctor_finished; +#ifdef IS_32BIT + uint32_t cctor_thread__padding; + uint32_t cctor_thread; + uint32_t cctor_thread__hi; +#else + __declspec(align(8)) uint64_t cctor_thread; +#endif + GenericContainerIndex genericContainerIndex; + CustomAttributeIndex customAttributeIndex; + uint32_t instance_size; + uint32_t actualSize; + uint32_t element_size; + int32_t native_size; + uint32_t static_fields_size; + uint32_t thread_static_fields_size; + int32_t thread_static_fields_offset; + uint32_t flags; + uint32_t token; + uint16_t method_count; + uint16_t property_count; + uint16_t field_count; + uint16_t event_count; + uint16_t nested_type_count; + uint16_t vtable_count; + uint16_t interfaces_count; + uint16_t interface_offsets_count; + uint8_t typeHierarchyDepth; + uint8_t genericRecursionDepth; + uint8_t rank; + uint8_t minimumAlignment; + uint8_t packingSize; + uint8_t valuetype : 1; + uint8_t initialized : 1; + uint8_t enumtype : 1; + uint8_t is_generic : 1; + uint8_t has_references : 1; + uint8_t init_pending : 1; + uint8_t size_inited : 1; + uint8_t has_finalize : 1; + uint8_t has_cctor : 1; + uint8_t is_blittable : 1; + uint8_t is_import_or_windows_runtime : 1; + uint8_t is_vtable_initialized : 1; +} Il2CppClass_1; + +typedef struct __declspec(align(8)) Il2CppClass_Merged { + struct Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + void* static_fields; + const Il2CppRGCTXData* rgctx_data; + struct Il2CppClass_1 _1; + VirtualInvokeData vtable[32]; +} Il2CppClass_Merged; + +typedef struct Il2CppTypeDefinitionSizes +{ + uint32_t instance_size; + int32_t native_size; + uint32_t static_fields_size; + uint32_t thread_static_fields_size; +} Il2CppTypeDefinitionSizes; +typedef struct Il2CppDomain +{ + Il2CppAppDomain* domain; + Il2CppAppDomainSetup* setup; + Il2CppAppContext* default_context; + const char* friendly_name; + uint32_t domain_id; + volatile int threadpool_jobs; +} Il2CppDomain; +typedef struct Il2CppImage +{ + const char* name; + const char* nameNoExt; + AssemblyIndex assemblyIndex; + TypeDefinitionIndex typeStart; + uint32_t typeCount; + TypeDefinitionIndex exportedTypeStart; + uint32_t exportedTypeCount; + MethodIndex entryPointIndex; + Il2CppNameToTypeDefinitionIndexHashTable* nameToClassHashTable; + uint32_t token; +} Il2CppImage; +typedef struct Il2CppCodeGenOptions +{ + bool enablePrimitiveValueTypeGenericSharing; +} Il2CppCodeGenOptions; +typedef struct Il2CppCodeRegistration +{ + uint32_t methodPointersCount; + const Il2CppMethodPointer* methodPointers; + uint32_t reversePInvokeWrapperCount; + const Il2CppMethodPointer* reversePInvokeWrappers; + uint32_t genericMethodPointersCount; + const Il2CppMethodPointer* genericMethodPointers; + uint32_t invokerPointersCount; + const InvokerMethod* invokerPointers; + CustomAttributeIndex customAttributeCount; + const CustomAttributesCacheGenerator* customAttributeGenerators; + uint32_t unresolvedVirtualCallCount; + const Il2CppMethodPointer* unresolvedVirtualCallPointers; + uint32_t interopDataCount; + Il2CppInteropData* interopData; +} Il2CppCodeRegistration; +typedef struct Il2CppMetadataRegistration +{ + int32_t genericClassesCount; + Il2CppGenericClass* const* genericClasses; + int32_t genericInstsCount; + const Il2CppGenericInst* const* genericInsts; + int32_t genericMethodTableCount; + const Il2CppGenericMethodFunctionsDefinitions* genericMethodTable; + int32_t typesCount; + const Il2CppType* const* types; + int32_t methodSpecsCount; + const Il2CppMethodSpec* methodSpecs; + FieldIndex fieldOffsetsCount; + const int32_t** fieldOffsets; + TypeDefinitionIndex typeDefinitionsSizesCount; + const Il2CppTypeDefinitionSizes** typeDefinitionsSizes; + const size_t metadataUsagesCount; + void** const* metadataUsages; +} Il2CppMetadataRegistration; +typedef struct Il2CppRuntimeStats +{ + uint64_t new_object_count; + uint64_t initialized_class_count; + uint64_t method_count; + uint64_t class_static_data_size; + uint64_t generic_instance_count; + uint64_t generic_class_count; + uint64_t inflated_method_count; + uint64_t inflated_type_count; + bool enabled; +} Il2CppRuntimeStats; +extern Il2CppRuntimeStats il2cpp_runtime_stats; +typedef struct Il2CppPerfCounters +{ + uint32_t jit_methods; + uint32_t jit_bytes; + uint32_t jit_time; + uint32_t jit_failures; + uint32_t exceptions_thrown; + uint32_t exceptions_filters; + uint32_t exceptions_finallys; + uint32_t exceptions_depth; + uint32_t aspnet_requests_queued; + uint32_t aspnet_requests; + uint32_t gc_collections0; + uint32_t gc_collections1; + uint32_t gc_collections2; + uint32_t gc_promotions0; + uint32_t gc_promotions1; + uint32_t gc_promotion_finalizers; + uint32_t gc_gen0size; + uint32_t gc_gen1size; + uint32_t gc_gen2size; + uint32_t gc_lossize; + uint32_t gc_fin_survivors; + uint32_t gc_num_handles; + uint32_t gc_allocated; + uint32_t gc_induced; + uint32_t gc_time; + uint32_t gc_total_bytes; + uint32_t gc_committed_bytes; + uint32_t gc_reserved_bytes; + uint32_t gc_num_pinned; + uint32_t gc_sync_blocks; + uint32_t remoting_calls; + uint32_t remoting_channels; + uint32_t remoting_proxies; + uint32_t remoting_classes; + uint32_t remoting_objects; + uint32_t remoting_contexts; + uint32_t loader_classes; + uint32_t loader_total_classes; + uint32_t loader_appdomains; + uint32_t loader_total_appdomains; + uint32_t loader_assemblies; + uint32_t loader_total_assemblies; + uint32_t loader_failures; + uint32_t loader_bytes; + uint32_t loader_appdomains_uloaded; + uint32_t thread_contentions; + uint32_t thread_queue_len; + uint32_t thread_queue_max; + uint32_t thread_num_logical; + uint32_t thread_num_physical; + uint32_t thread_cur_recognized; + uint32_t thread_num_recognized; + uint32_t interop_num_ccw; + uint32_t interop_num_stubs; + uint32_t interop_num_marshals; + uint32_t security_num_checks; + uint32_t security_num_link_checks; + uint32_t security_time; + uint32_t security_depth; + uint32_t unused; + uint64_t threadpool_workitems; + uint64_t threadpool_ioworkitems; + unsigned int threadpool_threads; + unsigned int threadpool_iothreads; +} Il2CppPerfCounters; +typedef struct Il2CppClass Il2CppClass; +typedef struct MethodInfo MethodInfo; +typedef struct PropertyInfo PropertyInfo; +typedef struct FieldInfo FieldInfo; +typedef struct EventInfo EventInfo; +typedef struct Il2CppType Il2CppType; +typedef struct Il2CppAssembly Il2CppAssembly; +typedef struct Il2CppException Il2CppException; +typedef struct Il2CppImage Il2CppImage; +typedef struct Il2CppDomain Il2CppDomain; +typedef struct Il2CppString Il2CppString; +typedef struct Il2CppReflectionMethod Il2CppReflectionMethod; +typedef struct Il2CppAsyncCall Il2CppAsyncCall; +typedef struct Il2CppIUnknown Il2CppIUnknown; +typedef struct Il2CppWaitHandle Il2CppWaitHandle; +typedef struct MonitorData MonitorData; +typedef struct FastMutex FastMutex; +typedef struct Thread Thread; +typedef struct Il2CppReflectionAssembly Il2CppReflectionAssembly; +typedef struct Il2CppObject +{ + Il2CppClass* klass; + MonitorData* monitor; +} Il2CppObject; +typedef int32_t il2cpp_array_lower_bound_t; +typedef struct Il2CppArrayBounds +{ + il2cpp_array_size_t length; + il2cpp_array_lower_bound_t lower_bound; +} Il2CppArrayBounds; +typedef struct Il2CppArray +{ + Il2CppObject Object; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; +} Il2CppArray; +typedef struct Il2CppArraySize +{ + Il2CppArray Array; + __declspec(align(8)) void* vector; +} Il2CppArraySize; +typedef struct Il2CppString +{ + Il2CppObject object; + int32_t length; + Il2CppChar chars[32]; +} Il2CppString; +typedef struct Il2CppReflectionType +{ + Il2CppObject object; + const Il2CppType* type; +} Il2CppReflectionType; +typedef struct Il2CppReflectionRuntimeType +{ + Il2CppReflectionType type; + Il2CppObject* type_info; + Il2CppObject* genericCache; + Il2CppObject* serializationCtor; +} Il2CppReflectionRuntimeType; +typedef struct Il2CppReflectionMonoType +{ + Il2CppReflectionRuntimeType type; +} Il2CppReflectionMonoType; +typedef struct Il2CppReflectionEvent +{ + Il2CppObject object; + Il2CppObject* cached_add_event; +} Il2CppReflectionEvent; +typedef struct Il2CppReflectionMonoEvent +{ + Il2CppReflectionEvent event; + Il2CppReflectionType* reflectedType; + const EventInfo* eventInfo; +} Il2CppReflectionMonoEvent; +typedef struct Il2CppReflectionMonoEventInfo +{ + Il2CppReflectionType* declaringType; + Il2CppReflectionType* reflectedType; + Il2CppString* name; + Il2CppReflectionMethod* addMethod; + Il2CppReflectionMethod* removeMethod; + Il2CppReflectionMethod* raiseMethod; + uint32_t eventAttributes; + Il2CppArray* otherMethods; +} Il2CppReflectionMonoEventInfo; +typedef struct Il2CppReflectionField +{ + Il2CppObject object; + Il2CppClass* klass; + FieldInfo* field; + Il2CppString* name; + Il2CppReflectionType* type; + uint32_t attrs; +} Il2CppReflectionField; +typedef struct Il2CppReflectionProperty +{ + Il2CppObject object; + Il2CppClass* klass; + const PropertyInfo* property; +} Il2CppReflectionProperty; +typedef struct Il2CppReflectionMethod +{ + Il2CppObject object; + const MethodInfo* method; + Il2CppString* name; + Il2CppReflectionType* reftype; +} Il2CppReflectionMethod; +typedef struct Il2CppReflectionGenericMethod +{ + Il2CppReflectionMethod base; +} Il2CppReflectionGenericMethod; +typedef struct Il2CppMethodInfo +{ + Il2CppReflectionType* parent; + Il2CppReflectionType* ret; + uint32_t attrs; + uint32_t implattrs; + uint32_t callconv; +} Il2CppMethodInfo; +typedef struct Il2CppPropertyInfo +{ + Il2CppReflectionType* parent; + Il2CppReflectionType* declaringType; + Il2CppString* name; + Il2CppReflectionMethod* get; + Il2CppReflectionMethod* set; + uint32_t attrs; +} Il2CppPropertyInfo; +typedef struct Il2CppReflectionParameter +{ + Il2CppObject object; + Il2CppReflectionType* ClassImpl; + Il2CppObject* DefaultValueImpl; + Il2CppObject* MemberImpl; + Il2CppString* NameImpl; + int32_t PositionImpl; + uint32_t AttrsImpl; + Il2CppObject* MarshalAsImpl; +} Il2CppReflectionParameter; +typedef struct Il2CppReflectionModule +{ + Il2CppObject obj; + const Il2CppImage* image; + Il2CppReflectionAssembly* assembly; + Il2CppString* fqname; + Il2CppString* name; + Il2CppString* scopename; + bool is_resource; + uint32_t token; +} Il2CppReflectionModule; +typedef struct Il2CppReflectionAssemblyName +{ + Il2CppObject obj; + Il2CppString* name; + Il2CppString* codebase; + int32_t major, minor, build, revision; + Il2CppObject* cultureInfo; + uint32_t flags; + uint32_t hashalg; + Il2CppObject* keypair; + Il2CppArray* publicKey; + Il2CppArray* keyToken; + uint32_t versioncompat; + Il2CppObject* version; + uint32_t processor_architecture; + uint32_t contentType; +} Il2CppReflectionAssemblyName; +typedef struct Il2CppReflectionAssembly +{ + Il2CppObject object; + const Il2CppAssembly* assembly; + Il2CppObject* resolve_event_holder; + Il2CppObject* evidence; + Il2CppObject* minimum; + Il2CppObject* optional; + Il2CppObject* refuse; + Il2CppObject* granted; + Il2CppObject* denied; + bool from_byte_array; + Il2CppString* name; +} Il2CppReflectionAssembly; +typedef struct Il2CppReflectionMarshal +{ + Il2CppObject object; + int32_t count; + int32_t type; + int32_t eltype; + Il2CppString* guid; + Il2CppString* mcookie; + Il2CppString* marshaltype; + Il2CppObject* marshaltyperef; + int32_t param_num; + bool has_size; +} Il2CppReflectionMarshal; +typedef struct Il2CppReflectionPointer +{ + Il2CppObject object; + void* data; + Il2CppReflectionType* type; +} Il2CppReflectionPointer; +typedef struct Il2CppInternalThread +{ + Il2CppObject obj; + int lock_thread_id; + Thread* handle; + void* native_handle; + Il2CppArray* cached_culture_info; + Il2CppChar* name; + int name_len; + uint32_t state; + Il2CppObject* abort_exc; + int abort_state_handle; + uint64_t tid; + void* stack_ptr; + void** static_data; + void* runtime_thread_info; + Il2CppObject* current_appcontext; + Il2CppObject* root_domain_thread; + Il2CppArray* _serialized_principal; + int _serialized_principal_version; + void* appdomain_refs; + int32_t interruption_requested; + FastMutex* synch_cs; + bool threadpool_thread; + bool thread_interrupt_requested; + int stack_size; + uint8_t apartment_state; + int critical_region_level; + int managed_id; + uint32_t small_id; + void* manage_callback; + void* interrupt_on_stop; + void* flags; + void* thread_pinning_ref; + void* abort_protected_block_count; + int32_t priority; + void* owned_mutexes; + void* suspended; + int32_t self_suspended; + size_t thread_state; + size_t unused2; + void* last; +} Il2CppInternalThread; +typedef struct Il2CppIOSelectorJob +{ + Il2CppObject object; + int32_t operation; + Il2CppObject* callback; + Il2CppObject* state; +} Il2CppIOSelectorJob; +typedef enum +{ + Il2Cpp_CallType_Sync = 0, + Il2Cpp_CallType_BeginInvoke = 1, + Il2Cpp_CallType_EndInvoke = 2, + Il2Cpp_CallType_OneWay = 3 +} Il2CppCallType; +typedef struct Il2CppMethodMessage +{ + Il2CppObject obj; + Il2CppReflectionMethod* method; + Il2CppArray* args; + Il2CppArray* names; + Il2CppArray* arg_types; + Il2CppObject* ctx; + Il2CppObject* rval; + Il2CppObject* exc; + Il2CppAsyncResult* async_result; + uint32_t call_type; +} Il2CppMethodMessage; +typedef struct Il2CppAppDomainSetup +{ + Il2CppObject object; + Il2CppString* application_base; + Il2CppString* application_name; + Il2CppString* cache_path; + Il2CppString* configuration_file; + Il2CppString* dynamic_base; + Il2CppString* license_file; + Il2CppString* private_bin_path; + Il2CppString* private_bin_path_probe; + Il2CppString* shadow_copy_directories; + Il2CppString* shadow_copy_files; + uint8_t publisher_policy; + uint8_t path_changed; + int loader_optimization; + uint8_t disallow_binding_redirects; + uint8_t disallow_code_downloads; + Il2CppObject* activation_arguments; + Il2CppObject* domain_initializer; + Il2CppObject* application_trust; + Il2CppArray* domain_initializer_args; + uint8_t disallow_appbase_probe; + Il2CppArray* configuration_bytes; + Il2CppArray* serialized_non_primitives; +} Il2CppAppDomainSetup; +typedef struct Il2CppThread +{ + Il2CppObject obj; + Il2CppInternalThread* internal_thread; + Il2CppObject* start_obj; + Il2CppException* pending_exception; + Il2CppObject* principal; + int32_t principal_version; + Il2CppDelegate* delegate; + Il2CppObject* executionContext; + bool executionContextBelongsToOuterScope; +} Il2CppThread; +typedef struct Il2CppException +{ + Il2CppObject Object; + Il2CppString* className; + Il2CppString* message; + Il2CppObject* _data; + Il2CppException* inner_ex; + Il2CppString* _helpURL; + Il2CppArray* trace_ips; + Il2CppString* stack_trace; + Il2CppString* remote_stack_trace; + int remote_stack_index; + Il2CppObject* _dynamicMethods; + il2cpp_hresult_t hresult; + Il2CppString* source; + Il2CppObject* safeSerializationManager; + Il2CppArray* captured_traces; + Il2CppArray* native_trace_ips; +} Il2CppException; +typedef struct Il2CppSystemException +{ + Il2CppException base; +} Il2CppSystemException; +typedef struct Il2CppArgumentException +{ + Il2CppException base; + Il2CppString* argName; +} Il2CppArgumentException; +typedef struct Il2CppTypedRef +{ + Il2CppType* type; + void* value; + Il2CppClass* klass; +} Il2CppTypedRef; +typedef struct Il2CppDelegate +{ + Il2CppObject object; + Il2CppMethodPointer method_ptr; + InvokerMethod invoke_impl; + Il2CppObject* target; + const MethodInfo* method; + void* delegate_trampoline; + intptr_t extraArg; + uint8_t** method_code; + Il2CppReflectionMethod* method_info; + Il2CppReflectionMethod* original_method_info; + Il2CppObject* data; + bool method_is_virtual; +} Il2CppDelegate; +typedef struct Il2CppMulticastDelegate +{ + Il2CppDelegate delegate; + Il2CppArray* delegates; +} Il2CppMulticastDelegate; +typedef struct Il2CppMarshalByRefObject +{ + Il2CppObject obj; + Il2CppObject* identity; +} Il2CppMarshalByRefObject; +typedef struct Il2CppComObject +{ + Il2CppObject Object; + Il2CppIUnknown* identity; + volatile int32_t refCount; +} Il2CppComObject; +typedef struct Il2CppAppDomain +{ + Il2CppMarshalByRefObject mbr; + Il2CppDomain* data; +} Il2CppAppDomain; +typedef struct Il2CppStackFrame +{ + Il2CppObject obj; + int32_t il_offset; + int32_t native_offset; + uint64_t methodAddress; + uint32_t methodIndex; + Il2CppReflectionMethod* method; + Il2CppString* filename; + int32_t line; + int32_t column; + Il2CppString* internal_method_name; +} Il2CppStackFrame; +typedef struct Il2CppDateTimeFormatInfo +{ + Il2CppObject obj; + Il2CppObject* CultureData; + Il2CppString* Name; + Il2CppString* LangName; + Il2CppObject* CompareInfo; + Il2CppObject* CultureInfo; + Il2CppString* AMDesignator; + Il2CppString* PMDesignator; + Il2CppString* DateSeparator; + Il2CppString* GeneralShortTimePattern; + Il2CppString* GeneralLongTimePattern; + Il2CppString* TimeSeparator; + Il2CppString* MonthDayPattern; + Il2CppString* DateTimeOffsetPattern; + Il2CppObject* Calendar; + uint32_t FirstDayOfWeek; + uint32_t CalendarWeekRule; + Il2CppString* FullDateTimePattern; + Il2CppArray* AbbreviatedDayNames; + Il2CppArray* ShortDayNames; + Il2CppArray* DayNames; + Il2CppArray* AbbreviatedMonthNames; + Il2CppArray* MonthNames; + Il2CppArray* GenitiveMonthNames; + Il2CppArray* GenitiveAbbreviatedMonthNames; + Il2CppArray* LeapYearMonthNames; + Il2CppString* LongDatePattern; + Il2CppString* ShortDatePattern; + Il2CppString* YearMonthPattern; + Il2CppString* LongTimePattern; + Il2CppString* ShortTimePattern; + Il2CppArray* YearMonthPatterns; + Il2CppArray* ShortDatePatterns; + Il2CppArray* LongDatePatterns; + Il2CppArray* ShortTimePatterns; + Il2CppArray* LongTimePatterns; + Il2CppArray* EraNames; + Il2CppArray* AbbrevEraNames; + Il2CppArray* AbbrevEnglishEraNames; + Il2CppArray* OptionalCalendars; + bool readOnly; + int32_t FormatFlags; + int32_t CultureID; + bool UseUserOverride; + bool UseCalendarInfo; + int32_t DataItem; + bool IsDefaultCalendar; + Il2CppArray* DateWords; + Il2CppString* FullTimeSpanPositivePattern; + Il2CppString* FullTimeSpanNegativePattern; + Il2CppArray* dtfiTokenHash; +} Il2CppDateTimeFormatInfo; +typedef struct Il2CppNumberFormatInfo +{ + Il2CppObject obj; + Il2CppArray* numberGroupSizes; + Il2CppArray* currencyGroupSizes; + Il2CppArray* percentGroupSizes; + Il2CppString* positiveSign; + Il2CppString* negativeSign; + Il2CppString* numberDecimalSeparator; + Il2CppString* numberGroupSeparator; + Il2CppString* currencyGroupSeparator; + Il2CppString* currencyDecimalSeparator; + Il2CppString* currencySymbol; + Il2CppString* ansiCurrencySymbol; + Il2CppString* naNSymbol; + Il2CppString* positiveInfinitySymbol; + Il2CppString* negativeInfinitySymbol; + Il2CppString* percentDecimalSeparator; + Il2CppString* percentGroupSeparator; + Il2CppString* percentSymbol; + Il2CppString* perMilleSymbol; + Il2CppArray* nativeDigits; + int dataItem; + int numberDecimalDigits; + int currencyDecimalDigits; + int currencyPositivePattern; + int currencyNegativePattern; + int numberNegativePattern; + int percentPositivePattern; + int percentNegativePattern; + int percentDecimalDigits; + int digitSubstitution; + bool readOnly; + bool useUserOverride; + bool isInvariant; + bool validForParseAsNumber; + bool validForParseAsCurrency; +} Il2CppNumberFormatInfo; +typedef struct Il2CppCultureData +{ + Il2CppObject obj; + Il2CppString* AMDesignator; + Il2CppString* PMDesignator; + Il2CppString* TimeSeparator; + Il2CppArray* LongTimePatterns; + Il2CppArray* ShortTimePatterns; + uint32_t FirstDayOfWeek; + uint32_t CalendarWeekRule; +} Il2CppCultureData; +typedef struct Il2CppCalendarData +{ + Il2CppObject obj; + Il2CppString* NativeName; + Il2CppArray* ShortDatePatterns; + Il2CppArray* YearMonthPatterns; + Il2CppArray* LongDatePatterns; + Il2CppString* MonthDayPattern; + Il2CppArray* EraNames; + Il2CppArray* AbbreviatedEraNames; + Il2CppArray* AbbreviatedEnglishEraNames; + Il2CppArray* DayNames; + Il2CppArray* AbbreviatedDayNames; + Il2CppArray* SuperShortDayNames; + Il2CppArray* MonthNames; + Il2CppArray* AbbreviatedMonthNames; + Il2CppArray* GenitiveMonthNames; + Il2CppArray* GenitiveAbbreviatedMonthNames; +} Il2CppCalendarData; +typedef struct Il2CppCultureInfo +{ + Il2CppObject obj; + bool is_read_only; + int32_t lcid; + int32_t parent_lcid; + int32_t datetime_index; + int32_t number_index; + int32_t default_calendar_type; + bool use_user_override; + Il2CppNumberFormatInfo* number_format; + Il2CppDateTimeFormatInfo* datetime_format; + Il2CppObject* textinfo; + Il2CppString* name; + Il2CppString* englishname; + Il2CppString* nativename; + Il2CppString* iso3lang; + Il2CppString* iso2lang; + Il2CppString* win3lang; + Il2CppString* territory; + Il2CppArray* native_calendar_names; + Il2CppString* compareinfo; + const void* text_info_data; + int dataItem; + Il2CppObject* calendar; + Il2CppObject* parent_culture; + bool constructed; + Il2CppArray* cached_serialized_form; + Il2CppObject* cultureData; + bool isInherited; +} Il2CppCultureInfo; +typedef struct Il2CppRegionInfo +{ + Il2CppObject obj; + int32_t geo_id; + Il2CppString* iso2name; + Il2CppString* iso3name; + Il2CppString* win3name; + Il2CppString* english_name; + Il2CppString* currency_symbol; + Il2CppString* iso_currency_symbol; + Il2CppString* currency_english_name; +} Il2CppRegionInfo; +typedef struct Il2CppSafeHandle +{ + Il2CppObject base; + void* handle; + int state; + bool owns_handle; + bool fullyInitialized; +} Il2CppSafeHandle; +typedef struct Il2CppStringBuilder +{ + Il2CppObject object; + Il2CppArray* chunkChars; + Il2CppStringBuilder* chunkPrevious; + int chunkLength; + int chunkOffset; + int maxCapacity; +} Il2CppStringBuilder; +typedef struct Il2CppSocketAddress +{ + Il2CppObject base; + int m_Size; + Il2CppArray* data; + bool m_changed; + int m_hash; +} Il2CppSocketAddress; +typedef struct Il2CppSortKey +{ + Il2CppObject base; + Il2CppString* str; + Il2CppArray* key; + int32_t options; + int32_t lcid; +} Il2CppSortKey; +typedef struct Il2CppErrorWrapper +{ + Il2CppObject base; + int32_t errorCode; +} Il2CppErrorWrapper; +typedef struct Il2CppAsyncResult +{ + Il2CppObject base; + Il2CppObject* async_state; + Il2CppWaitHandle* handle; + Il2CppDelegate* async_delegate; + void* data; + Il2CppAsyncCall* object_data; + bool sync_completed; + bool completed; + bool endinvoke_called; + Il2CppObject* async_callback; + Il2CppObject* execution_context; + Il2CppObject* original_context; +} Il2CppAsyncResult; +typedef struct Il2CppAsyncCall +{ + Il2CppObject base; + Il2CppMethodMessage* msg; + MethodInfo* cb_method; + Il2CppDelegate* cb_target; + Il2CppObject* state; + Il2CppObject* res; + Il2CppArray* out_args; +} Il2CppAsyncCall; +typedef struct Il2CppExceptionWrapper +{ + Il2CppException* ex; +} Il2CppExceptionWrapper; +typedef struct Il2CppIOAsyncResult +{ + Il2CppObject base; + Il2CppDelegate* callback; + Il2CppObject* state; + Il2CppWaitHandle* wait_handle; + bool completed_synchronously; + bool completed; +} Il2CppIOAsyncResult; +typedef struct Il2CppSocketAsyncResult +{ + Il2CppIOAsyncResult base; + Il2CppObject* socket; + int32_t operation; + Il2CppException* delayedException; + Il2CppObject* endPoint; + Il2CppArray* buffer; + int32_t offset; + int32_t size; + int32_t socket_flags; + Il2CppObject* acceptSocket; + Il2CppArray* addresses; + int32_t port; + Il2CppObject* buffers; + bool reuseSocket; + int32_t currentAddress; + Il2CppObject* acceptedSocket; + int32_t total; + int32_t error; + int32_t endCalled; +} Il2CppSocketAsyncResult; +typedef enum Il2CppResourceLocation +{ + IL2CPP_RESOURCE_LOCATION_EMBEDDED = 1, + IL2CPP_RESOURCE_LOCATION_ANOTHER_ASSEMBLY = 2, + IL2CPP_RESOURCE_LOCATION_IN_MANIFEST = 4 +} Il2CppResourceLocation; +typedef struct Il2CppManifestResourceInfo +{ + Il2CppObject object; + Il2CppReflectionAssembly* assembly; + Il2CppString* filename; + uint32_t location; +} Il2CppManifestResourceInfo; +typedef struct Il2CppAppContext +{ + Il2CppObject obj; + int32_t domain_id; + int32_t context_id; + void* static_data; +} Il2CppAppContext; +struct Il2CppDecimal +{ + uint16_t reserved; + union + { + struct + { + uint8_t scale; + uint8_t sign; + } u; + uint16_t signscale; + } u; + uint32_t Hi32; + union + { + struct + { + uint32_t Lo32; + uint32_t Mid32; + } v; + uint64_t Lo64; + } v; +}; +typedef struct Il2CppDouble +{ + uint32_t mantLo : 32; + uint32_t mantHi : 20; + uint32_t exp : 11; + uint32_t sign : 1; +} Il2CppDouble; +typedef union +{ + Il2CppDouble s; + double d; +} Il2CppDouble_double; +typedef enum +{ + IL2CPP_DECIMAL_CMP_LT = -1, + IL2CPP_DECIMAL_CMP_EQ, + IL2CPP_DECIMAL_CMP_GT +} Il2CppDecimalCompareResult; +typedef struct Il2CppSingle +{ + uint32_t mant : 23; + uint32_t exp : 8; + uint32_t sign : 1; +} Il2CppSingle; +typedef union +{ + Il2CppSingle s; + float f; +} Il2CppSingle_float; +typedef struct Il2CppGuid +{ + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} Il2CppGuid; +typedef struct Il2CppSafeArrayBound +{ + uint32_t element_count; + int32_t lower_bound; +} Il2CppSafeArrayBound; +typedef struct Il2CppSafeArray +{ + uint16_t dimension_count; + uint16_t features; + uint32_t element_size; + uint32_t lock_count; + void* data; + Il2CppSafeArrayBound bounds[1]; +} Il2CppSafeArray; +struct Il2CppWin32Decimal +{ + uint16_t reserved; + union + { + struct + { + uint8_t scale; + uint8_t sign; + } s; + uint16_t signscale; + } u; + uint32_t hi32; + union + { + struct + { + uint32_t lo32; + uint32_t mid32; + } s2; + uint64_t lo64; + } u2; +}; +typedef int16_t IL2CPP_VARIANT_BOOL; +typedef enum Il2CppVarType +{ + IL2CPP_VT_EMPTY = 0, + IL2CPP_VT_NULL = 1, + IL2CPP_VT_I2 = 2, + IL2CPP_VT_I4 = 3, + IL2CPP_VT_R4 = 4, + IL2CPP_VT_R8 = 5, + IL2CPP_VT_CY = 6, + IL2CPP_VT_DATE = 7, + IL2CPP_VT_BSTR = 8, + IL2CPP_VT_DISPATCH = 9, + IL2CPP_VT_ERROR = 10, + IL2CPP_VT_BOOL = 11, + IL2CPP_VT_VARIANT = 12, + IL2CPP_VT_UNKNOWN = 13, + IL2CPP_VT_DECIMAL = 14, + IL2CPP_VT_I1 = 16, + IL2CPP_VT_UI1 = 17, + IL2CPP_VT_UI2 = 18, + IL2CPP_VT_UI4 = 19, + IL2CPP_VT_I8 = 20, + IL2CPP_VT_UI8 = 21, + IL2CPP_VT_INT = 22, + IL2CPP_VT_UINT = 23, + IL2CPP_VT_VOID = 24, + IL2CPP_VT_HRESULT = 25, + IL2CPP_VT_PTR = 26, + IL2CPP_VT_SAFEARRAY = 27, + IL2CPP_VT_CARRAY = 28, + IL2CPP_VT_USERDEFINED = 29, + IL2CPP_VT_LPSTR = 30, + IL2CPP_VT_LPWSTR = 31, + IL2CPP_VT_RECORD = 36, + IL2CPP_VT_INT_PTR = 37, + IL2CPP_VT_UINT_PTR = 38, + IL2CPP_VT_FILETIME = 64, + IL2CPP_VT_BLOB = 65, + IL2CPP_VT_STREAM = 66, + IL2CPP_VT_STORAGE = 67, + IL2CPP_VT_STREAMED_OBJECT = 68, + IL2CPP_VT_STORED_OBJECT = 69, + IL2CPP_VT_BLOB_OBJECT = 70, + IL2CPP_VT_CF = 71, + IL2CPP_VT_CLSID = 72, + IL2CPP_VT_VERSIONED_STREAM = 73, + IL2CPP_VT_BSTR_BLOB = 0xfff, + IL2CPP_VT_VECTOR = 0x1000, + IL2CPP_VT_ARRAY = 0x2000, + IL2CPP_VT_BYREF = 0x4000, + IL2CPP_VT_RESERVED = 0x8000, + IL2CPP_VT_ILLEGAL = 0xffff, + IL2CPP_VT_ILLEGALMASKED = 0xfff, + IL2CPP_VT_TYPEMASK = 0xfff, +} Il2CppVarType; +typedef struct Il2CppVariant +{ + union + { + struct __tagVARIANT + { + uint16_t type; + uint16_t reserved1; + uint16_t reserved2; + uint16_t reserved3; + union + { + int64_t llVal; + int32_t lVal; + uint8_t bVal; + int16_t iVal; + float fltVal; + double dblVal; + IL2CPP_VARIANT_BOOL boolVal; + int32_t scode; + int64_t cyVal; + double date; + Il2CppChar* bstrVal; + Il2CppIUnknown* punkVal; + void* pdispVal; + Il2CppSafeArray* parray; + uint8_t* pbVal; + int16_t* piVal; + int32_t* plVal; + int64_t* pllVal; + float* pfltVal; + double* pdblVal; + IL2CPP_VARIANT_BOOL* pboolVal; + int32_t* pscode; + int64_t* pcyVal; + double* pdate; + Il2CppChar* pbstrVal; + Il2CppIUnknown** ppunkVal; + void** ppdispVal; + Il2CppSafeArray** pparray; + struct Il2CppVariant* pvarVal; + void* byref; + char cVal; + uint16_t uiVal; + uint32_t ulVal; + uint64_t ullVal; + int intVal; + unsigned int uintVal; + Il2CppWin32Decimal* pdecVal; + char* pcVal; + uint16_t* puiVal; + uint32_t* pulVal; + uint64_t* pullVal; + int* pintVal; + unsigned int* puintVal; + struct __tagBRECORD + { + void* pvRecord; + void* pRecInfo; + } n4; + } n3; + } n2; + Il2CppWin32Decimal decVal; + } n1; +} Il2CppVariant; +typedef struct Il2CppFileTime +{ + uint32_t low; + uint32_t high; +} Il2CppFileTime; +typedef struct Il2CppStatStg +{ + Il2CppChar* name; + uint32_t type; + uint64_t size; + Il2CppFileTime mtime; + Il2CppFileTime ctime; + Il2CppFileTime atime; + uint32_t mode; + uint32_t locks; + Il2CppGuid clsid; + uint32_t state; + uint32_t reserved; +} Il2CppStatStg; +typedef struct Il2CppHString__ +{ + int unused; +} Il2CppHString__; +typedef Il2CppHString__* Il2CppHString; +typedef struct Il2CppHStringHeader +{ + union + { + void* Reserved1; + char Reserved2[24]; + } Reserved; +} Il2CppHStringHeader; +typedef struct Il2CppIUnknown +{ + static const Il2CppGuid IID; +} Il2CppIUnknown; +typedef struct Il2CppISequentialStream +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppISequentialStream; +typedef struct Il2CppIStream +{ + Il2CppISequentialStream ISequentialStream; + static const Il2CppGuid IID; +} Il2CppIStream; +typedef struct Il2CppIMarshal +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIMarshal; +typedef struct Il2CppIManagedObject +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIManagedObject; +typedef struct Il2CppIManagedObjectHolder +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIManagedObjectHolder; +typedef struct Il2CppIInspectable +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIInspectable; +typedef struct Il2CppIActivationFactory +{ + Il2CppIInspectable IInspectable; + static const Il2CppGuid IID; +} Il2CppIActivationFactory; +typedef struct Il2CppIRestrictedErrorInfo +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIRestrictedErrorInfo; +typedef struct Il2CppILanguageExceptionErrorInfo +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppILanguageExceptionErrorInfo; +typedef struct Il2CppIAgileObject +{ + Il2CppIUnknown IUnknown; + static const Il2CppGuid IID; +} Il2CppIAgileObject; + +#pragma warning(disable : 4369) +#pragma warning(disable : 4309) +#pragma warning(disable : 4359) +#if !defined(_GHIDRA_) && !defined(_IDA_) +namespace app { +#endif + + // ****************************************************************************** + // * Application types from method calls + // ****************************************************************************** + + struct Object__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + }; + + struct Object__StaticFields { + }; + + struct Object__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Object__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Object__VTable vtable; + }; + + struct Type__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData GetCustomAttributes; + VirtualInvokeData GetCustomAttributes_1; + VirtualInvokeData IsDefined; + VirtualInvokeData get_DeclaringType; + VirtualInvokeData get_MemberType; + VirtualInvokeData __unknown; + VirtualInvokeData get_ReflectedType; + VirtualInvokeData __unknown_1; + VirtualInvokeData __unknown_2; + VirtualInvokeData __unknown_3; + VirtualInvokeData __unknown_4; + VirtualInvokeData get_MetadataToken; + VirtualInvokeData __unknown_5; + VirtualInvokeData __unknown_6; + VirtualInvokeData get_Attributes; + VirtualInvokeData __unknown_7; + VirtualInvokeData __unknown_8; + VirtualInvokeData __unknown_9; + VirtualInvokeData get_HasElementType; + VirtualInvokeData get_IsAbstract; + VirtualInvokeData get_IsArray; + VirtualInvokeData get_IsByRef; + VirtualInvokeData get_IsClass; + VirtualInvokeData get_IsContextful; + VirtualInvokeData get_IsEnum; + VirtualInvokeData get_IsExplicitLayout; + VirtualInvokeData get_IsInterface; + VirtualInvokeData get_IsMarshalByRef; + VirtualInvokeData get_IsNestedPublic; + VirtualInvokeData get_IsPointer; + VirtualInvokeData get_IsPrimitive; + VirtualInvokeData get_IsPublic; + VirtualInvokeData get_IsSealed; + VirtualInvokeData get_IsSerializable; + VirtualInvokeData get_IsValueType; + VirtualInvokeData __unknown_10; + VirtualInvokeData get_TypeHandle; + VirtualInvokeData __unknown_11; + VirtualInvokeData Equals_1; + VirtualInvokeData GetType; + VirtualInvokeData IsSubclassOf; + VirtualInvokeData GetInterfaceMap; + VirtualInvokeData __unknown_12; + VirtualInvokeData IsAssignableFrom; + VirtualInvokeData IsInstanceOfType; + VirtualInvokeData GetArrayRank; + VirtualInvokeData __unknown_13; + VirtualInvokeData GetEvent; + VirtualInvokeData __unknown_14; + VirtualInvokeData __unknown_15; + VirtualInvokeData GetField; + VirtualInvokeData __unknown_16; + VirtualInvokeData GetFields; + VirtualInvokeData __unknown_17; + VirtualInvokeData GetMember; + VirtualInvokeData GetMember_1; + VirtualInvokeData GetMember_2; + VirtualInvokeData __unknown_18; + VirtualInvokeData GetMethod; + VirtualInvokeData GetMethod_1; + VirtualInvokeData GetMethod_2; + VirtualInvokeData GetMethod_3; + VirtualInvokeData GetMethod_4; + VirtualInvokeData __unknown_19; + VirtualInvokeData GetMethods; + VirtualInvokeData __unknown_20; + VirtualInvokeData __unknown_21; + VirtualInvokeData GetProperties; + VirtualInvokeData __unknown_22; + VirtualInvokeData GetProperty; + VirtualInvokeData GetProperty_1; + VirtualInvokeData GetProperty_2; + VirtualInvokeData GetProperty_3; + VirtualInvokeData GetProperty_4; + VirtualInvokeData __unknown_23; + VirtualInvokeData __unknown_24; + VirtualInvokeData __unknown_25; + VirtualInvokeData __unknown_26; + VirtualInvokeData __unknown_27; + VirtualInvokeData __unknown_28; + VirtualInvokeData __unknown_29; + VirtualInvokeData __unknown_30; + VirtualInvokeData IsValueTypeImpl; + VirtualInvokeData IsContextfulImpl; + VirtualInvokeData IsMarshalByRefImpl; + VirtualInvokeData GetConstructor; + VirtualInvokeData GetConstructor_1; + VirtualInvokeData GetConstructor_2; + VirtualInvokeData GetConstructors; + VirtualInvokeData __unknown_31; + VirtualInvokeData FindMembers; + VirtualInvokeData InvokeMember; + VirtualInvokeData __unknown_32; + VirtualInvokeData GetGenericArguments; + VirtualInvokeData get_ContainsGenericParameters; + VirtualInvokeData get_IsGenericTypeDefinition; + VirtualInvokeData GetGenericTypeDefinition; + VirtualInvokeData get_IsGenericType; + VirtualInvokeData MakeGenericType; + VirtualInvokeData get_IsGenericParameter; + VirtualInvokeData GetGenericParameterConstraints; + VirtualInvokeData MakeByRefType; + }; + + struct Type__StaticFields { + uint16_t Delimiter; + struct Type__Array* EmptyTypes; + struct MemberFilter* FilterAttribute; + struct MemberFilter* FilterName; + struct MemberFilter* FilterNameIgnoreCase; + struct Object* Missing; + }; + + struct Type__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Type__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Type__VTable vtable; + }; + + struct Object { + struct Object__Class* klass; + MonitorData* monitor; + }; + + struct RuntimeTypeHandle__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData GetObjectData; + }; + + struct RuntimeTypeHandle__StaticFields { + }; + + struct RuntimeTypeHandle__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct RuntimeTypeHandle__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct RuntimeTypeHandle__VTable vtable; + }; + + struct Char__Array__VTable { + }; + + struct Char__Array__StaticFields { + }; + + struct Char__Array__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Char__Array__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Char__Array__VTable vtable; + }; + + struct __declspec(align(8)) Encoding__Fields { + int32_t codePage; + int32_t windows_code_page; + bool is_readonly; + struct DecoderFallback* decoder_fallback; + struct EncoderFallback* encoder_fallback; + struct String* body_name; + struct String* encoding_name; + struct String* header_name; + bool is_mail_news_display; + bool is_mail_news_save; + bool is_browser_save; + bool is_browser_display; + struct String* web_name; + }; + + struct Encoding__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData Clone; + VirtualInvokeData __unknown; + VirtualInvokeData GetByteCount; + VirtualInvokeData GetByteCount_1; + VirtualInvokeData __unknown_1; + VirtualInvokeData GetBytes; + VirtualInvokeData GetBytes_1; + VirtualInvokeData GetBytes_2; + VirtualInvokeData GetBytes_3; + VirtualInvokeData __unknown_2; + VirtualInvokeData __unknown_3; + VirtualInvokeData GetChars; + VirtualInvokeData GetChars_1; + VirtualInvokeData GetDecoder; + VirtualInvokeData Clone_1; + VirtualInvokeData __unknown_4; + VirtualInvokeData __unknown_5; + VirtualInvokeData GetPreamble; + VirtualInvokeData GetString; + VirtualInvokeData GetString_1; + VirtualInvokeData get_HeaderName; + VirtualInvokeData get_WebName; + VirtualInvokeData GetByteCount_2; + VirtualInvokeData GetBytes_4; + }; + + struct Encoding__StaticFields { + struct Assembly* i18nAssembly; + bool i18nDisabled; + struct EncodingInfo__Array* encoding_infos; + struct Object__Array* encodings; + struct Encoding* asciiEncoding; + struct Encoding* bigEndianEncoding; + struct Encoding* defaultEncoding; + struct Encoding* utf7Encoding; + struct Encoding* utf8EncodingWithMarkers; + struct Encoding* utf8EncodingWithoutMarkers; + struct Encoding* unicodeEncoding; + struct Encoding* isoLatin1Encoding; + struct Encoding* utf8EncodingUnsafe; + struct Encoding* utf32Encoding; + struct Encoding* bigEndianUTF32Encoding; + struct Object* lockobj; + }; + + struct Encoding { + struct Encoding__Class* klass; + MonitorData* monitor; + struct Encoding__Fields fields; + }; + + struct Encoding__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Encoding__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Encoding__VTable vtable; + }; + + struct Char__Array { + struct Char__Array__Class* klass; + MonitorData* monitor; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; + uint16_t vector[32]; + }; + + struct RuntimeTypeHandle { + void* value; + }; + + struct RuntimeTypeHandle__Boxed { + struct RuntimeTypeHandle__Class* klass; + MonitorData* monitor; + struct RuntimeTypeHandle fields; + }; + + + + struct __declspec(align(8)) Type__Fields { + struct RuntimeTypeHandle _impl; + }; + + struct Type { + struct Type__Class* klass; + MonitorData* monitor; + struct Type__Fields fields; + }; + + struct String__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData GetTypeCode; + VirtualInvokeData System_IConvertible_ToBoolean; + VirtualInvokeData System_IConvertible_ToByte; + VirtualInvokeData System_IConvertible_ToChar; + VirtualInvokeData System_IConvertible_ToDateTime; + VirtualInvokeData System_IConvertible_ToDecimal; + VirtualInvokeData System_IConvertible_ToDouble; + VirtualInvokeData System_IConvertible_ToInt16; + VirtualInvokeData System_IConvertible_ToInt32; + VirtualInvokeData System_IConvertible_ToInt64; + VirtualInvokeData System_IConvertible_ToSByte; + VirtualInvokeData System_IConvertible_ToSingle; + VirtualInvokeData ToString_1; + VirtualInvokeData System_IConvertible_ToType; + VirtualInvokeData System_IConvertible_ToUInt16; + VirtualInvokeData System_IConvertible_ToUInt32; + VirtualInvokeData System_IConvertible_ToUInt64; + VirtualInvokeData CompareTo; + VirtualInvokeData System_Collections_IEnumerable_GetEnumerator; + VirtualInvokeData Clone; + VirtualInvokeData CompareTo_1; + VirtualInvokeData Equals_1; + VirtualInvokeData System_Collections_Generic_IEnumerable_char__GetEnumerator; + }; + + struct String__StaticFields { + struct String* Empty; + struct Char__Array* WhiteChars; + }; + + struct String__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct String__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct String__VTable vtable; + }; + + struct __declspec(align(8)) String__Fields { + int32_t length; + uint16_t start_char; + }; + + struct String { + struct String__Class* klass; + MonitorData* monitor; + struct String__Fields fields; + }; + + struct IFormatProvider { + struct IFormatProvider__Class* klass; + MonitorData* monitor; + }; + + struct IFormatProvider__VTable { + VirtualInvokeData GetFormat; + }; + + struct IFormatProvider__StaticFields { + }; + + struct IFormatProvider__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct IFormatProvider__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct IFormatProvider__VTable vtable; + }; + + struct Byte__Array__VTable { + }; + + struct Byte__Array__StaticFields { + }; + + struct Byte__Array__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Byte__Array__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Byte__Array__VTable vtable; + }; + + struct Byte__Array { + struct Byte__Array__Class* klass; + MonitorData* monitor; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; + uint8_t vector[32]; + }; + + struct __declspec(align(8)) LuaBaseManager__Fields { + struct LuaEnv* _luaenv; + }; + + struct LuaManager_ILuaReload__VTable { + VirtualInvokeData Reload; + VirtualInvokeData GetHotfixFuncs; + }; + + struct LuaManager_ILuaReload__StaticFields { + }; + + struct LuaManager_ILuaReload__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct LuaManager_ILuaReload__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct LuaManager_ILuaReload__VTable vtable; + }; + + struct LuaBaseManager__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData Init; + VirtualInvokeData Tick; + VirtualInvokeData PostTick; + VirtualInvokeData LateTick; + VirtualInvokeData LatePreTick; + VirtualInvokeData LatePreTickEnd; + VirtualInvokeData LatePostTick; + VirtualInvokeData LatePostTickEnd; + VirtualInvokeData Dump; + VirtualInvokeData Destroy; + VirtualInvokeData ClearOnLevelDestroy; + VirtualInvokeData InitOnConnect; + VirtualInvokeData ClearOnDisconnect; + VirtualInvokeData ClearOnBackHome; + VirtualInvokeData ReloadRes; + VirtualInvokeData InitByLocalData; + VirtualInvokeData InitLua; + VirtualInvokeData Require; + VirtualInvokeData OnLoadLuaFinish; + }; + + struct LuaBaseManager__StaticFields { + struct DelegateBridge* _c__Hotfix0_ctor; + struct DelegateBridge* __Hotfix0_Init; + struct DelegateBridge* __Hotfix0_InitLua; + struct DelegateBridge* __Hotfix0_DoLua; + struct DelegateBridge* __Hotfix0_Require; + struct DelegateBridge* __Hotfix0_OnLoadLuaFinish; + struct DelegateBridge* __Hotfix0_ReloadRes; + struct DelegateBridge* __Hotfix0_Tick; + struct DelegateBridge* __Hotfix0_Destroy; + struct DelegateBridge* __Hotfix0_ClearOnLevelDestroy; + struct DelegateBridge* __Hotfix0_WaitForSeconds; + struct DelegateBridge* __Hotfix0_WaitForSecondsImp; + struct DelegateBridge* __Hotfix0_WaitForSeveralFrames; + struct DelegateBridge* __Hotfix0_WaitForSeveralFramesImp; + struct DelegateBridge* __Hotfix0_WaitForEndOfFrame; + struct DelegateBridge* __Hotfix0_WaitForEndOfFrameImp; + struct DelegateBridge* __Hotfix0_WaitForFixedUpdate; + struct DelegateBridge* __Hotfix0_WaitForFixedUpdateImp; + struct DelegateBridge* __Hotfix0_IsIOS; + struct DelegateBridge* __Hotfix0_IsAndroid; + struct DelegateBridge* __Hotfix0_ModifySafeFloat; + struct DelegateBridge* __Hotfix0_ModifySafeInt; + struct DelegateBridge* __Hotfix0_ModifySafeBool; + struct DelegateBridge* __Hotfix0_GetActorPlugin; + struct DelegateBridge* __Hotfix0_GetNetPacketV1Data; + struct DelegateBridge* __Hotfix0_CreateLuaTable; + struct DelegateBridge* __Hotfix0_ConvertDictionaryToLuaTable; + struct DelegateBridge* __Hotfix0_ConvertDictionaryKeysToList; + struct DelegateBridge* __Hotfix0_CreateLuaDelegate; + struct DelegateBridge* __Hotfix0_CreateLuaAction; + struct DelegateBridge* __Hotfix0_CreateLuaActionWithOneArg; + struct DelegateBridge* __Hotfix0_CreateLuaActionWithTwoArgs; + struct DelegateBridge* __Hotfix0_CreateLuaActionWithThreeArgs; + struct DelegateBridge* __Hotfix0_CreateLuaActionWithFourArgs; + struct DelegateBridge* __Hotfix0_CreateDelegate; + struct DelegateBridge* __Hotfix0_CreateAction; + struct DelegateBridge* __Hotfix0_CreateActionWithOneArg; + struct DelegateBridge* __Hotfix0_CreateActionWithTwoArgs; + struct DelegateBridge* __Hotfix0_CreateActionWithMultiArgs; + struct DelegateBridge* __Hotfix0_CreateStaticClassDelegate; + struct DelegateBridge* __Hotfix0_CreateStaticClassAction; + struct DelegateBridge* __Hotfix0_CreateStaticClassActionWithOneArg; + struct DelegateBridge* __Hotfix0_CreateStaticClassActionWithTwoArgs; + struct DelegateBridge* __Hotfix0_CreateStaticClassActionWithMultiArgs; + struct DelegateBridge* __Hotfix0_CreateInstance; + struct DelegateBridge* __Hotfix0_CreateGenericInstance; + struct DelegateBridge* __Hotfix0_CreateGenericInstanceWithTwoArgs; + struct DelegateBridge* __Hotfix0_CreateGenericInstanceWithMultiArgs; + struct DelegateBridge* __Hotfix0_GetObjectField; + struct DelegateBridge* __Hotfix0_GetObjectFieldValue; + struct DelegateBridge* __Hotfix0_SetObjectFieldValue; + struct DelegateBridge* __Hotfix0_GetStaticClassField; + struct DelegateBridge* __Hotfix0_GetStaticClassFieldValue; + struct DelegateBridge* __Hotfix0_SetStaticClassFieldValue; + struct DelegateBridge* __Hotfix0_InvokeObjectMethod; + struct DelegateBridge* __Hotfix0_InvokeObjectMethodWithMultiArgs; + struct DelegateBridge* __Hotfix0_InvokeStaticClassMethod; + struct DelegateBridge* __Hotfix0_InvokeStaticClassMethodWithMultiArgs; + struct DelegateBridge* __Hotfix0_ConvertLuaArgToCSharpArg; + struct DelegateBridge* __Hotfix0_ChangeType; + struct DelegateBridge* __Hotfix1_ChangeType; + struct DelegateBridge* __Hotfix0_GetClassType; + struct DelegateBridge* __Hotfix1_GetClassType; + struct DelegateBridge* __Hotfix0_GetTypeArray; + struct DelegateBridge* __Hotfix1_GetTypeArray; + struct DelegateBridge* __Hotfix2_GetTypeArray; + struct DelegateBridge* __Hotfix3_GetTypeArray; + struct DelegateBridge* __Hotfix0_InvokeMethodImp; + struct DelegateBridge* __Hotfix1_InvokeMethodImp; + }; + + struct LuaBaseManager__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct LuaBaseManager__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct LuaBaseManager__VTable vtable; + }; + + struct LuaBaseManager { + struct LuaBaseManager__Class* klass; + MonitorData* monitor; + struct LuaBaseManager__Fields fields; + }; + + struct LuaManager_ILuaReload { + struct LuaManager_ILuaReload__Class* klass; + MonitorData* monitor; + }; + + struct LuaManager_ILuaHotFix { + struct LuaManager_ILuaHotFix__Class* klass; + MonitorData* monitor; + }; + + struct LuaManager_ILuaMain { + struct LuaManager_ILuaMain__Class* klass; + MonitorData* monitor; + }; + + struct LuaManager__Fields { + struct LuaBaseManager__Fields _; + struct LuaManager_ILuaReload* _luaReload; + struct LuaManager_ILuaHotFix* _luaHotfix; + struct LuaManager_ILuaMain* _luaMain; + struct ActorManager_ILuaActorManager* _luaActorMgr; + struct Action* reloadCallback; + struct LuaEnv_CustomLoader* _customLoader; + uint32_t _gcCnt; + bool gcEnabled; + bool _isStarted; + bool _hotfixInited; + struct LuaTable* _patchTable; + }; + + struct LuaManager { + struct LuaManager__Class* klass; + MonitorData* monitor; + struct LuaManager__Fields fields; + }; + + + enum class DateTimeKind__Enum : int32_t { + Unspecified = 0x00000000, + Utc = 0x00000001, + Local = 0x00000002, + }; + + struct TimeSpan { + int64_t _ticks; + }; + + struct DateTime { + struct TimeSpan ticks; + DateTimeKind__Enum kind; + }; + + struct DateTime__Boxed { + struct DateTime__Class* klass; + MonitorData* monitor; + struct DateTime fields; + }; + + struct __declspec(align(8)) LuaBase__Fields { + bool disposed; + int32_t luaReference; + void* luaEnv; + }; + + struct DelegateBridgeBase__Fields { + struct LuaBase__Fields _; + void* firstKey; + void* firstValue; + void* bindTo; + int32_t errorFuncRef; + }; + + + struct DelegateBridge__Fields { + struct DelegateBridgeBase__Fields _; + int32_t _oldTop; + void* _stack; + }; + + struct DelegateBridge { + void* klass; + MonitorData* monitor; + struct DelegateBridge__Fields fields; + }; + + struct MMLHJDIKHGO__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + }; + + struct MMLHJDIKHGO__StaticFields { + struct DelegateBridge* FBPNECEFLOE; + struct DelegateBridge* PHCOGNGOLIB; + struct DelegateBridge* OMMFGIEPLNB; + struct DelegateBridge* DNGLBOAIJHH; + struct DelegateBridge* NCLIEEPFHDL; + struct DelegateBridge* KKOMKIEGPDO; + struct DelegateBridge* FKBGMOOHCEA; + struct DelegateBridge* DLBNKFCNNPF; + struct DelegateBridge* ENEPELNLPFO; + struct DelegateBridge* MPAKCCMDCIJ; + struct DelegateBridge* OPGPJFEHPHA; + struct DelegateBridge* KJEDMNINANM; + struct DelegateBridge* EKCDCMOHEII; + struct DelegateBridge* DGOPGFKLHCK; + struct DelegateBridge* GNFJCLOPBJA; + struct DelegateBridge* ECOIAFKEILB; + struct DelegateBridge* BMONDEPLGNK; + struct DelegateBridge* EODKGEBKPEI; + struct DelegateBridge* IGGNFLOEKIA; + struct DelegateBridge* FGKFHJNKCKN; + struct DelegateBridge* JCAEBEECFNM; + struct DelegateBridge* NDEKDPHIEMI; + struct DelegateBridge* DMGCMECPIAF; + struct DelegateBridge* FMLKIDOAAGM; + }; + + struct MMLHJDIKHGO__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct MMLHJDIKHGO__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct MMLHJDIKHGO__VTable vtable; + }; + + enum class MMLHJDIKHGO_PJOIODIAPNK__Enum : int32_t { + UDP = 0x00000000, + TCP = 0x00000001, + }; + + struct MMLHJDIKHGO_PJOIODIAPNK__Enum__Boxed { + struct MMLHJDIKHGO_PJOIODIAPNK__Enum__Class* klass; + MonitorData* monitor; + MMLHJDIKHGO_PJOIODIAPNK__Enum value; + }; + + struct __declspec(align(8)) MMLHJDIKHGO__Fields { + void* MEOGCAMBLHJ; + MMLHJDIKHGO_PJOIODIAPNK__Enum JAAAEGMMPIF; + }; + + struct MMLHJDIKHGO { + struct MMLHJDIKHGO__Class* klass; + MonitorData* monitor; + struct MMLHJDIKHGO__Fields fields; + }; + + struct ConfigChannel__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + }; + + struct ConfigChannel__StaticFields { + struct DelegateBridge* _c__Hotfix0_ctor; + struct DelegateBridge* __Hotfix0_IsOversea; + struct DelegateBridge* __Hotfix0_IsPreGMPackage; + struct DelegateBridge* __Hotfix0_IsRelPackage; + }; + + struct ConfigChannel__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct ConfigChannel__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct ConfigChannel__VTable vtable; + }; + + enum class AccountBranches__Enum : int32_t { + Original = 0x00000000, + UC = 0x00000001, + QIHOO = 0x00000002, + OPPO = 0x00000003, + VIVO = 0x00000004, + HUAWEI = 0x00000005, + XIAOMI = 0x00000006, + TENCENT = 0x00000007, + GIONEE = 0x00000008, + LENOVO = 0x00000009, + BAIDU = 0x0000000a, + COOLPAD = 0x0000000b, + WANDOUJIA = 0x0000000c, + MEIZU = 0x0000000d, + BILIBILI = 0x0000000e, + LESHI = 0x0000000f, + JAPAN = 0x00000010, + TAIWAN = 0x00000011, + KOREA = 0x00000012, + OVERSEAS = 0x00000013, + GLOBAL = 0x00000014, + }; + + enum class PaymentBranches__Enum : int32_t { + DEFAULT = 0x00000000, + APPSTORE_CN = 0x00000001, + ORIGINAL_ANDROID_PAY = 0x00000002, + GOOGLE_ANDROID_PAY = 0x00000003, + }; + + struct __declspec(align(8)) ConfigChannel__Fields { + struct String* ChannelName; + struct String* BundleIdentifier; + struct String* PS4ClientID; + struct String* PS5ClientID; + struct String* ProductName; + struct String* PreDefines; + struct String* TimeZones; + void* DispatchConfigs; + int32_t VersionCode; + bool Obb; + bool DataUseAssetBundle; + bool EventUseAssetBundle; + bool BetaMark; + struct String* CVDefault; + struct String* FAQUrl; + struct String* ExceptionReportUrl; + struct String* NetworkErrReportUrl; + struct String* MediumReportUrl; + struct String* CrashReportUrl; + struct String* LogRecorderUrl; + AccountBranches__Enum AccountBranch; + PaymentBranches__Enum PaymentBranch; + struct String* GVoiceAppID; + struct String* GVoiceAppKey; + struct String* GVoiceServerInfo; + struct String* BaseTextLang; + struct String* BaseAudioLang; + }; + + struct ConfigChannel { + struct ConfigChannel__Class* klass; + MonitorData* monitor; + struct ConfigChannel__Fields fields; + }; + + struct UInt16__Array { + void* klass; + MonitorData* monitor; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; + uint16_t vector[32]; + }; + + struct IPAddress__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + }; + + struct IPAddress__StaticFields { + struct IPAddress* Any; + struct IPAddress* Broadcast; + struct IPAddress* Loopback; + struct IPAddress* None; + struct IPAddress* IPv6Any; + struct IPAddress* IPv6Loopback; + struct IPAddress* IPv6None; + }; + + struct IPAddress__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct IPAddress__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct IPAddress__VTable vtable; + }; + + enum class AddressFamily__Enum : int32_t { + Unknown = -1, + Unspecified = 0x00000000, + Unix = 0x00000001, + InterNetwork = 0x00000002, + ImpLink = 0x00000003, + Pup = 0x00000004, + Chaos = 0x00000005, + NS = 0x00000006, + Ipx = 0x00000006, + Iso = 0x00000007, + Osi = 0x00000007, + Ecma = 0x00000008, + DataKit = 0x00000009, + Ccitt = 0x0000000a, + Sna = 0x0000000b, + DecNet = 0x0000000c, + DataLink = 0x0000000d, + Lat = 0x0000000e, + HyperChannel = 0x0000000f, + AppleTalk = 0x00000010, + NetBios = 0x00000011, + VoiceView = 0x00000012, + FireFox = 0x00000013, + Banyan = 0x00000015, + Atm = 0x00000016, + InterNetworkV6 = 0x00000017, + Cluster = 0x00000018, + Ieee12844 = 0x00000019, + Irda = 0x0000001a, + NetworkDesigners = 0x0000001c, + Max = 0x0000001d, + }; + + struct __declspec(align(8)) IPAddress__Fields { + int64_t m_Address; + AddressFamily__Enum m_Family; + struct UInt16__Array* m_Numbers; + int64_t m_ScopeId; + int32_t m_HashCode; + }; + + struct IPAddress { + struct IPAddress__Class* klass; + MonitorData* monitor; + struct IPAddress__Fields fields; + }; + + struct GameLogin__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData Init; + VirtualInvokeData Tick; + VirtualInvokeData PostTick; + VirtualInvokeData LateTick; + VirtualInvokeData LatePreTick; + VirtualInvokeData LatePreTickEnd; + VirtualInvokeData LatePostTick; + VirtualInvokeData LatePostTickEnd; + VirtualInvokeData Dump; + VirtualInvokeData Destroy; + VirtualInvokeData ClearOnLevelDestroy; + VirtualInvokeData InitOnConnect; + VirtualInvokeData ClearOnDisconnect; + VirtualInvokeData ClearOnBackHome; + VirtualInvokeData ReloadRes; + VirtualInvokeData InitByLocalData; + VirtualInvokeData OnNotify; + }; + + struct GameLogin__StaticFields { + float MLDLNMIPKPC; + struct Action_1_Boolean_* CILACBNHEJJ; + struct Action_1_Boolean_* CMLLGAMAOGJ; + struct Action_1_Boolean_* KLCMHGNLIDA; + struct Action_1_Boolean_* KHCJGGHLPJB; + struct DelegateBridge* FBPNECEFLOE; + struct DelegateBridge* DJGJOAIGMLD; + struct DelegateBridge* GHBMOCNLBEP; + struct DelegateBridge* HAOJOAIJDLC; + struct DelegateBridge* BNPHMIAKMLH; + struct DelegateBridge* POHLKBNMAKN; + struct DelegateBridge* ACKIAAPPOCM; + struct DelegateBridge* NGBIKKCFAMM; + struct DelegateBridge* INCKMHOGFFM; + struct DelegateBridge* NCKBEMGGAFG; + struct DelegateBridge* LBBMGIBJGKK; + struct DelegateBridge* BGCCHJCOMCA; + struct DelegateBridge* IGGNFLOEKIA; + struct DelegateBridge* FGKFHJNKCKN; + struct DelegateBridge* NDEKDPHIEMI; + struct DelegateBridge* DMGCMECPIAF; + struct DelegateBridge* OPIAFCKIIMH; + struct DelegateBridge* MCMBGKDLJDP; + struct DelegateBridge* PKKEJMCEFMN; + struct DelegateBridge* CKFHNMFEGDH; + struct DelegateBridge* ENDBLDDKOJM; + struct DelegateBridge* AJIAHCGPFAM; + struct DelegateBridge* MJFEOEEDIOM; + struct DelegateBridge* ADLFHGAEGGP; + struct DelegateBridge* BDDLFNOHNPL; + struct DelegateBridge* DHPBOABCJCA; + struct DelegateBridge* FGLFGLOCDAI; + struct DelegateBridge* EBCBEEKJDAG; + struct DelegateBridge* PGDPLBMLIOB; + struct DelegateBridge* BIDFGAAMEIF; + struct DelegateBridge* OJKLMMNGCCE; + struct DelegateBridge* JLEKLKBLABP; + struct DelegateBridge* AGGGLDBEDFC; + struct DelegateBridge* DNGLBOAIJHH; + struct DelegateBridge* GNFJCLOPBJA; + struct DelegateBridge* DPBNGBNHHKM; + struct DelegateBridge* FOLCPIBPFHC; + struct DelegateBridge* IIFHAOOAAAN; + struct DelegateBridge* FNODFDBIEGF; + struct DelegateBridge* BMLDOAJDEJN; + struct DelegateBridge* PAIMJJBFPOE; + struct DelegateBridge* EEFPHGIJLFA; + struct DelegateBridge* ENJJEODKEDM; + struct DelegateBridge* NCLIEEPFHDL; + struct DelegateBridge* ICIBJOEFHIB; + struct DelegateBridge* PGELDOHIPEO; + struct DelegateBridge* LNKHMBAGMPM; + struct DelegateBridge* BMOFMEKMKKB; + struct DelegateBridge* FMBPAMABPAN; + struct DelegateBridge* JOIDODGIKPF; + struct DelegateBridge* HKCBNNKMBLK; + struct DelegateBridge* AJKLPKIBLFO; + struct DelegateBridge* IEHIFOMCEMC; + struct DelegateBridge* MNFIFFECNIB; + struct DelegateBridge* PDACKOLBBAD; + struct DelegateBridge* NOOBGJMNHHK; + struct DelegateBridge* NNNBPLNLFJA; + struct DelegateBridge* CNIBMCFKIGE; + struct DelegateBridge* MOKNHGMODIF; + struct DelegateBridge* DJGADCOHAHL; + struct DelegateBridge* ANBGMAFNKBM; + struct DelegateBridge* KLEBJFCFALN; + struct DelegateBridge* FACBONJJDGK; + struct DelegateBridge* GCAOJPKPHBI; + struct DelegateBridge* LNJDKPPGIHI; + struct DelegateBridge* LHJKPKHDFBJ; + struct DelegateBridge* ONLNGOLFEGA; + struct DelegateBridge* MPEPFPBGPED; + struct DelegateBridge* EOLNJIBIOOI; + struct DelegateBridge* HIKIICODOHG; + struct DelegateBridge* HFNFADFGFNL; + struct DelegateBridge* BEDLIIGCPPB; + struct DelegateBridge* BOGFANIJHNG; + struct DelegateBridge* JCMMIJINFHM; + struct DelegateBridge* PIBDEAPDMCN; + struct DelegateBridge* HHOHNDMOIDG; + struct DelegateBridge* OJPHGKMIPFO; + struct DelegateBridge* LCCJIFBKFGP; + struct DelegateBridge* KLCMEPIDAFN; + struct DelegateBridge* EPICONADDGN; + struct DelegateBridge* FIADEEKPMIN; + struct DelegateBridge* AMLNCFFHMMH; + struct DelegateBridge* BGBACPBFBJA; + struct DelegateBridge* FPFJEGLIGKF; + struct DelegateBridge* NEBMEFPPFHM; + struct DelegateBridge* CDCALMACEIP; + struct DelegateBridge* IGNFNPLNEBA; + struct DelegateBridge* OJBBNCGKILF; + struct DelegateBridge* FLNMAACDBHM; + struct DelegateBridge* HMNCCPODJGF; + struct DelegateBridge* CGGCJLLEENH; + struct DelegateBridge* LHJKHFBCIDE; + struct DelegateBridge* PDMFMEFDHMP; + struct DelegateBridge* MBMHIBGNIKC; + struct DelegateBridge* KFNKKPLIIKF; + struct DelegateBridge* EPLNCJFPCNG; + struct DelegateBridge* CKDMDIFBFMO; + struct DelegateBridge* APKIONCDHNO; + struct DelegateBridge* GLBKPNPOPLF; + struct DelegateBridge* JNOMMDNINDF; + struct DelegateBridge* JNBKEEAIEGD; + struct DelegateBridge* PJGIPHAPLHJ; + struct DelegateBridge* EFCAJLBLGHG; + struct DelegateBridge* IMDDIJKJBFJ; + struct DelegateBridge* IDLKNOKFEEG; + struct DelegateBridge* CIPKGBECGCO; + struct DelegateBridge* GLOOBCCHAAO; + struct DelegateBridge* KMNLELOIKCA; + struct DelegateBridge* GDHONGOIBHA; + struct DelegateBridge* FKIGDKPILPF; + struct DelegateBridge* EDOBLDBKOBI; + struct DelegateBridge* NGEPNKNJCON; + struct DelegateBridge* CCAAIBGMMJJ; + struct DelegateBridge* FMFMJABGOPO; + struct DelegateBridge* MANGFJHPNFG; + struct DelegateBridge* BHHNILKLEOB; + struct DelegateBridge* JACGFJLFOPN; + struct DelegateBridge* OLDOMPNPJKD; + struct DelegateBridge* OAOLKAIKNEO; + struct DelegateBridge* IFLMKHFDPEN; + struct DelegateBridge* DEJIGJPCNJL; + struct DelegateBridge* BDEDCJFGFMB; + struct DelegateBridge* AKGNLGBKMJH; + struct DelegateBridge* LIDLNAGEELP; + struct DelegateBridge* HDMNGHAJLKO; + struct DelegateBridge* OHPMGIJHACJ; + struct DelegateBridge* JLJJNOEPOOP; + struct DelegateBridge* HDDALELIOOB; + struct DelegateBridge* HFNDDDAPAHM; + struct DelegateBridge* OLFOHKMOMLE; + struct DelegateBridge* FPNDMIOONDK; + struct DelegateBridge* KBCBMIBDPCE; + struct DelegateBridge* DJOJBKNPCNM; + struct DelegateBridge* NIJAAMDNELA; + struct DelegateBridge* NINDPFAFIDN; + struct DelegateBridge* NEKKIGGEEEE; + struct DelegateBridge* EAMDPBHJOOH; + struct DelegateBridge* LHMKOMMHCNJ; + struct DelegateBridge* NBOOIECOMOL; + struct DelegateBridge* BJHLCNJMGCO; + struct DelegateBridge* PIOBJAHPLBJ; + struct DelegateBridge* DKPBBLPHGKA; + struct DelegateBridge* HKCIKDAPFDF; + struct DelegateBridge* GAJAKCFJFFG; + struct DelegateBridge* CFJMPGGFPFO; + }; + + struct GameLogin__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct GameLogin__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct GameLogin__VTable vtable; + }; + + struct __declspec(align(8)) GameLogin__Fields { + struct MMLHJDIKHGO* SocketInfo; + bool FHAFGBAEEOH; + struct ConfigChannel* configChannel; + void* _KLFJDIDIFDO_k__BackingField; + void* CHJMOFIOEEN; + void* MLOFGBOKJHB; + bool _PMMICLMAANC_k__BackingField; + bool HGPFHBDKCPL; + bool PIGHNIAKIMF; + struct IPAddress* ip_backing; + struct IPAddress* ip; + struct String* someString; + uint16_t MIJHJILHMCD; + bool PKGHNCCBAGD; + bool CEOEBONMNKB; + struct DateTime datetime_1; + struct DateTime datetime_2; + int32_t EDHEJDIHOEC; + uint32_t AIOJOKHHMDH; + void* JLFPPAAJBJH; + void* LAMGEEIPKJN; + void* KELHMKAPLCF; + bool NKKGJMMCINF; + uint32_t IOIAKODGJAL; + uint32_t GOGAODGGJJB; + void* IACEIKHNJAN; + struct DateTime datetime_3; + void* OKGJIGGJNOH; + float FNOLDKFPBLL; + float PJHHBBICHPD; + void* coroutine; + void* coroutines; + bool NLMICBAEFBO; + int32_t HBDAKIADBDH; + bool DPMDLKFJNGJ; + uint32_t FGKMCOPPLAK; + int32_t MDIMAAHFFHF; + void* coroutine_1; + void* GANBFGNLLDD; + void* DFFDCKODHEN; + }; + + struct GameLogin { + struct GameLogin__Class* klass; + MonitorData* monitor; + struct GameLogin__Fields fields; + }; + + struct __declspec(align(8)) MAKEGCIBGMD__Fields { + int32_t OHALFFMCMLN; + uint8_t CEOMEKMKCDG; + int32_t JABMLLBAOLE; + }; + + struct GKOJAICIOPA__Fields { + struct MAKEGCIBGMD__Fields _; + struct String* string_1; + struct String* string_2; + struct String* string_3; + struct String* string_4; + struct String* string_5; + uint32_t DCDMCEEGPHO; + uint64_t HNNPGFOOOGF; + bool GJEGPDCKHKC; + uint32_t OHILLNPMGOG; + uint32_t PJCAONOLKME; + struct String* string_6; + struct String* string_7; + struct String* string_8; + uint32_t GLALNAFJNPI; + bool GFDJDACPNEF; + uint32_t HGMCFPBHFIP; + uint32_t MHOMEBNKBMB; + struct String* string_16; + struct String* string_9; + uint32_t IJKANMFMBID; + void* CJDKDCIPBPF; + void* EOIAHBHLOOP; + struct String* string_10; + uint32_t LIDAFJHHONJ; + uint32_t PMGDOOKBJND; + struct String* string_11; + uint32_t NFNAILJKHNB; + void* HBMOHKNKCDH; + struct String* string_12; + uint32_t BEAOKGHFDLP; + struct NHHMPCAAKGF* COALKJGFLEJ; + uint32_t NDJHCJFIKGH; + struct String* string_13; + struct String* string_14; + bool OKOOABLDFNB; + uint32_t FCOKNAHMKMD; + uint32_t KOHNHBDBAGH; + void* HAJNHPHHBJH; + struct String* string_15; + }; + + struct GKOJAICIOPA { + void* klass; + MonitorData* monitor; + struct GKOJAICIOPA__Fields fields; + }; + + struct Array__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData GetEnumerator; + VirtualInvokeData Clone; + VirtualInvokeData System_Collections_ICollection_get_Count; + VirtualInvokeData get_IsSynchronized; + VirtualInvokeData get_SyncRoot; + VirtualInvokeData CopyTo; + VirtualInvokeData get_IsFixedSize; + VirtualInvokeData get_IsReadOnly; + VirtualInvokeData System_Collections_IList_get_Item; + VirtualInvokeData System_Collections_IList_set_Item; + VirtualInvokeData System_Collections_IList_Add; + VirtualInvokeData System_Collections_IList_Clear; + VirtualInvokeData System_Collections_IList_Contains; + VirtualInvokeData System_Collections_IList_IndexOf; + VirtualInvokeData System_Collections_IList_Insert; + VirtualInvokeData System_Collections_IList_Remove; + VirtualInvokeData System_Collections_IList_RemoveAt; + }; + + struct Array__StaticFields { + }; + + struct Array__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Array__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Array__VTable vtable; + }; + + struct Array { + struct Array__Class* klass; + MonitorData* monitor; + }; + + struct Byte__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData ToString_1; + VirtualInvokeData GetTypeCode; + VirtualInvokeData System_IConvertible_ToBoolean; + VirtualInvokeData System_IConvertible_ToByte; + VirtualInvokeData System_IConvertible_ToChar; + VirtualInvokeData System_IConvertible_ToDateTime; + VirtualInvokeData System_IConvertible_ToDecimal; + VirtualInvokeData System_IConvertible_ToDouble; + VirtualInvokeData System_IConvertible_ToInt16; + VirtualInvokeData System_IConvertible_ToInt32; + VirtualInvokeData System_IConvertible_ToInt64; + VirtualInvokeData System_IConvertible_ToSByte; + VirtualInvokeData System_IConvertible_ToSingle; + VirtualInvokeData ToString_2; + VirtualInvokeData System_IConvertible_ToType; + VirtualInvokeData System_IConvertible_ToUInt16; + VirtualInvokeData System_IConvertible_ToUInt32; + VirtualInvokeData System_IConvertible_ToUInt64; + VirtualInvokeData CompareTo; + VirtualInvokeData CompareTo_1; + VirtualInvokeData Equals_1; + }; + + struct Byte__StaticFields { + }; + + struct Byte__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct Byte__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct Byte__VTable vtable; + }; +#if !defined(_GHIDRA_) && !defined(_IDA_) +} +#endif diff --git a/cheat-library/src/appdata/il2cpp-unityplayer-functions.h b/cheat-library/src/appdata/il2cpp-unityplayer-functions.h new file mode 100644 index 0000000..cdd481d --- /dev/null +++ b/cheat-library/src/appdata/il2cpp-unityplayer-functions.h @@ -0,0 +1,4 @@ +using namespace app; + +DO_APP_FUNC(0xD50040, app::Byte__Array*, Unity_RecordUserData, (int32_t nType)); +DO_APP_FUNC(0xCF5570, Il2CppClass**, GetIl2Classes, ()); \ No newline at end of file diff --git a/cheat-library/src/framework/dllmain.cpp b/cheat-library/src/framework/dllmain.cpp new file mode 100644 index 0000000..8c51317 --- /dev/null +++ b/cheat-library/src/framework/dllmain.cpp @@ -0,0 +1,26 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// DLL entry point + +#define WIN32_LEAN_AND_MEAN +#include +#include "il2cpp-init.h" +#include "main.h" + +// DLL entry point +BOOL WINAPI DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Run, nullptr, 0, NULL); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} \ No newline at end of file diff --git a/cheat-library/src/framework/helpers.cpp b/cheat-library/src/framework/helpers.cpp new file mode 100644 index 0000000..db296b5 --- /dev/null +++ b/cheat-library/src/framework/helpers.cpp @@ -0,0 +1,38 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Helper functions + +#include "pch-il2cpp.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include "helpers.h" + +// Helper function to get the module base address +uintptr_t il2cppi_get_base_address() { + return (uintptr_t) GetModuleHandleW(L"UserAssembly.dll"); +} + +uintptr_t il2cppi_get_unity_address() { + return (uintptr_t)GetModuleHandleW(L"UnityPlayer.dll"); +} + +// Helper function to open a new console window and redirect stdout there +void il2cppi_new_console() { + AllocConsole(); + freopen_s((FILE**) stdout, "CONOUT$", "w", stdout); +} + +#if _MSC_VER >= 1920 +// Helper function to convert Il2CppString to std::string +std::string il2cppi_to_string(Il2CppString* str) { + std::u16string u16(reinterpret_cast(str->chars), str->length); + return std::wstring_convert, char16_t>{}.to_bytes(u16); +} + +// Helper function to convert System.String to std::string +std::string il2cppi_to_string(app::String* str) { + return il2cppi_to_string(reinterpret_cast(str)); +} +#endif \ No newline at end of file diff --git a/cheat-library/src/framework/helpers.h b/cheat-library/src/framework/helpers.h new file mode 100644 index 0000000..5fd8846 --- /dev/null +++ b/cheat-library/src/framework/helpers.h @@ -0,0 +1,44 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Helper functions + +#pragma once + +#include +#include +#include + +#include "il2cpp-metadata-version.h" + +// Helper function to get the module base address +uintptr_t il2cppi_get_base_address(); + +// Helpre function to get the UnityPlayer.dll base address +uintptr_t il2cppi_get_unity_address(); + +// Helper function to open a new console window and redirect stdout there +void il2cppi_new_console(); + +#if _MSC_VER >= 1920 +// Helper function to convert Il2CppString to std::string +std::string il2cppi_to_string(Il2CppString* str); + +// Helper function to convert System.String to std::string +std::string il2cppi_to_string(app::String* str); +#endif + +// Helper function to check if a metadata usage pointer is initialized +template bool il2cppi_is_initialized(T* metadataItem) { +#if __IL2CPP_METADATA_VERISON < 270 + return *metadataItem != 0; +#else + // Metadata >=27 (Unity 2020.2) + return !((uintptr_t) *metadataItem & 1); +#endif +} + +// Helper function to convert a pointer to hex +template std::string to_hex_string(T i) { + std::stringstream stream; + stream << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; + return stream.str(); +} \ No newline at end of file diff --git a/cheat-library/src/framework/il2cpp-appdata.h b/cheat-library/src/framework/il2cpp-appdata.h new file mode 100644 index 0000000..02d7dbb --- /dev/null +++ b/cheat-library/src/framework/il2cpp-appdata.h @@ -0,0 +1,34 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// IL2CPP application data + +#pragma once + +#include + +// Application-specific types +#include "il2cpp-types.h" + +// IL2CPP API function pointers +#include "il2cpp-api-functions-ptr.h" + +// IL2CPP APIs +#define DO_API(r, n, p) extern r (*n) p +#include "il2cpp-api-functions.h" +#undef DO_API + +// Application-specific functions +#define DO_APP_FUNC(a, r, n, p) extern r (*n) p +#define DO_APP_FUNC_METHODINFO(a, n) extern struct MethodInfo ** n +namespace app { + #include "il2cpp-functions.h" + #include "il2cpp-unityplayer-functions.h" +} +#undef DO_APP_FUNC +#undef DO_APP_FUNC_METHODINFO + +// TypeInfo pointers +#define DO_TYPEDEF(a, n) extern n ## __Class** n ## __TypeInfo +namespace app { + #include "il2cpp-types-ptr.h" +} +#undef DO_TYPEDEF \ No newline at end of file diff --git a/cheat-library/src/framework/il2cpp-init.cpp b/cheat-library/src/framework/il2cpp-init.cpp new file mode 100644 index 0000000..ec2f1ca --- /dev/null +++ b/cheat-library/src/framework/il2cpp-init.cpp @@ -0,0 +1,63 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// IL2CPP application initializer + +#include "pch-il2cpp.h" + +#include "il2cpp-init.h" +#include "helpers.h" + +// IL2CPP APIs +#define DO_API(r, n, p) r (*n) p +#include "il2cpp-api-functions.h" +#undef DO_API + +// Application-specific functions +#define DO_APP_FUNC(a, r, n, p) r (*n) p +#define DO_APP_FUNC_METHODINFO(a, n) struct MethodInfo ** n +namespace app { +#include "il2cpp-functions.h" +#include "il2cpp-unityplayer-functions.h" +} +#undef DO_APP_FUNC +#undef DO_APP_FUNC_METHODINFO + +// TypeInfo pointers +#define DO_TYPEDEF(a, n) n ## __Class** n ## __TypeInfo +namespace app { +#include "il2cpp-types-ptr.h" +} +#undef DO_TYPEDEF + +// IL2CPP application initializer +void init_il2cpp() +{ + // Get base address of IL2CPP module + uintptr_t baseAddress = il2cppi_get_base_address(); + + using namespace app; + + // Define IL2CPP API function addresses + #define DO_API(r, n, p) n = (r (*) p)(baseAddress + n ## _ptr) + #include "il2cpp-api-functions.h" + #undef DO_API + + // Define function addresses + #define DO_APP_FUNC(a, r, n, p) n = (r (*) p)(baseAddress + a) + #define DO_APP_FUNC_METHODINFO(a, n) n = (struct MethodInfo **)(baseAddress + a) + #include "il2cpp-functions.h" + #undef DO_APP_FUNC + #undef DO_APP_FUNC_METHODINFO + + // Define TypeInfo variables + #define DO_TYPEDEF(a, n) n ## __TypeInfo = (n ## __Class**) (baseAddress + a); + #include "il2cpp-types-ptr.h" + #undef DO_TYPEDEF + + uintptr_t unityPlayerAddress = il2cppi_get_unity_address(); + // Define UnityPlayer functions + #define DO_APP_FUNC(a, r, n, p) n = (r (*) p)(unityPlayerAddress + a) + #define DO_APP_FUNC_METHODINFO(a, n) n = (struct MethodInfo **)(unityPlayerAddress + a) + #include "il2cpp-unityplayer-functions.h" + #undef DO_APP_FUNC + #undef DO_APP_FUNC_METHODINFO +} \ No newline at end of file diff --git a/cheat-library/src/framework/il2cpp-init.h b/cheat-library/src/framework/il2cpp-init.h new file mode 100644 index 0000000..a2c675c --- /dev/null +++ b/cheat-library/src/framework/il2cpp-init.h @@ -0,0 +1,7 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// IL2CPP application initializer + +#pragma once + +// IL2CPP application initializer +void init_il2cpp(); \ No newline at end of file diff --git a/cheat-library/src/framework/pch-il2cpp.cpp b/cheat-library/src/framework/pch-il2cpp.cpp new file mode 100644 index 0000000..ec2d7b9 --- /dev/null +++ b/cheat-library/src/framework/pch-il2cpp.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch-il2cpp.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. \ No newline at end of file diff --git a/cheat-library/src/framework/pch-il2cpp.h b/cheat-library/src/framework/pch-il2cpp.h new file mode 100644 index 0000000..2859c8d --- /dev/null +++ b/cheat-library/src/framework/pch-il2cpp.h @@ -0,0 +1,13 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_IL2CPP_H +#define PCH_IL2CPP_H + +// add headers that you want to pre-compile here +#include "il2cpp-appdata.h" + +#endif //PCH_IL2CPP_H \ No newline at end of file diff --git a/cheat-library/src/user/debug-hooks.cpp b/cheat-library/src/user/debug-hooks.cpp new file mode 100644 index 0000000..c8054b7 --- /dev/null +++ b/cheat-library/src/user/debug-hooks.cpp @@ -0,0 +1,50 @@ +#include "pch-il2cpp.h" + +#include "debug-hooks.h" + +#include "util/HookManager.h" +#include "helpers.h" +#include + +app::Byte__Array* LoadCustomLuaFile_Hook(app::LuaManager* __this, app::String** filePath, bool* recycleBytes, MethodInfo* method) { + std::cout << "Load library: " << il2cppi_to_string(*filePath) << ".lua" << std::endl; + return callOrigin(LoadCustomLuaFile_Hook, __this, filePath, recycleBytes, method); +} + +void __stdcall SendInfo_Hook(app::GameLogin* __this, app::GKOJAICIOPA* info, MethodInfo* method) { + std::cout << "Game sending game info to server." << std::endl; + std::cout << "Content: " << std::endl; + +#define printString(i) if (info->fields.string_ ## i > (void *)1 && info->fields.string_ ## i ##->fields.length > 0)\ + std::cout << "\tfield#" << i << ": " << il2cppi_to_string(info->fields.string_ ## i) << std::endl; + + printString(1); + printString(2); + printString(3); + printString(4); + printString(5); + printString(6); + printString(7); + printString(8); + printString(9); + printString(10); + printString(11); + printString(12); + printString(13); + printString(14); + printString(15); + printString(16); + +#undef printString + + callOrigin(SendInfo_Hook, __this, info, method); +} + + +void InitDebugHooks() { + HookManager::set(app::LuaManager_LoadCustomLuaFile, LoadCustomLuaFile_Hook); + std::cout << "Hooked LoadCustomLuaFile. Origin at 0x" << (void*)HookManager::getOrigin(LoadCustomLuaFile_Hook) << std::endl; + + HookManager::set(app::GameLogin_SendInfo_2, SendInfo_Hook); + std::cout << "Hooked GameLogin::SendGameInfo. Origin at 0x" << (void*)HookManager::getOrigin(SendInfo_Hook) << std::endl; +} \ No newline at end of file diff --git a/cheat-library/src/user/debug-hooks.h b/cheat-library/src/user/debug-hooks.h new file mode 100644 index 0000000..3b6b102 --- /dev/null +++ b/cheat-library/src/user/debug-hooks.h @@ -0,0 +1,3 @@ +#pragma once + +void InitDebugHooks(); \ No newline at end of file diff --git a/cheat-library/src/user/main.cpp b/cheat-library/src/user/main.cpp new file mode 100644 index 0000000..10cd662 --- /dev/null +++ b/cheat-library/src/user/main.cpp @@ -0,0 +1,40 @@ +#include "pch-il2cpp.h" +#include "main.h" + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include + +#include "il2cpp-init.h" +#include "helpers.h" +#include "util/Config.h" +#include "debug-hooks.h" +#include "protection-bypass.h" + +const char* INIFileName = "config.ini"; + +void Run() +{ + Sleep(2000); // Waiting for il2cpp initialize + + init_il2cpp(); + + il2cpp_thread_attach(il2cpp_domain_get()); + + std::string configPath = (std::filesystem::current_path() / INIFileName).string(); + Config::Init(configPath); + if (Config::consoleLogging) + il2cppi_new_console(); + + std::cout << "Config path is " << (std::filesystem::current_path() / INIFileName).string() << std::endl; + std::cout << "UserAssembly.dll at 0x" << il2cppi_get_base_address() << std::endl; + std::cout << "UnityPlayer.dll at 0x" << il2cppi_get_unity_address() << std::endl; + + InitProtectionBypass(); + + InitDebugHooks(); +} \ No newline at end of file diff --git a/cheat-library/src/user/main.h b/cheat-library/src/user/main.h new file mode 100644 index 0000000..a1cbaa9 --- /dev/null +++ b/cheat-library/src/user/main.h @@ -0,0 +1,7 @@ +// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty +// Custom injected code entry point + +#pragma once + +// Custom injected code entry point +void Run(); \ No newline at end of file diff --git a/cheat-library/src/user/protection-bypass.cpp b/cheat-library/src/user/protection-bypass.cpp new file mode 100644 index 0000000..4d56b77 --- /dev/null +++ b/cheat-library/src/user/protection-bypass.cpp @@ -0,0 +1,60 @@ +#include "pch-il2cpp.h" + +#include "protection-bypass.h" + +#include "util/HookManager.h" +#include "util/Config.h" + +#include +#include +#include + +static std::map correctSignatures; + +app::Byte__Array* RecordUserData_Hook(int32_t nType) { + + if (correctSignatures.count(nType)) + { + auto byteClass = app::GetIl2Classes()[0x25]; + + auto content = correctSignatures[nType]; + auto newArray = (app::Byte__Array*)il2cpp_array_new(byteClass, content.size()); + memmove_s(newArray->vector, content.size(), content.data(), content.size()); + + return newArray; + } + + app::Byte__Array* result = callOrigin(RecordUserData_Hook, nType); + auto length = app::Array_get_Length(reinterpret_cast(result), nullptr); + + if (length == 0) + return result; + + + auto stringValue = std::string((char*)result->vector, length); + correctSignatures[nType] = stringValue; + + std::cout << "Sniffed correct signature for type " << nType << " value " << stringValue << std::endl; + + return result; +} + + +void InitProtectionBypass() { + HookManager::set(app::Unity_RecordUserData, RecordUserData_Hook); + std::cout << "RecordUserData function address is 0x" << (void*)app::Unity_RecordUserData << std::endl; + + for (int i = 0; i < 4; i++) { + std::cout << "Emulating call of RecordUserData with type " << i << std::endl; + app::Application_RecordUserData(nullptr, i, nullptr); + } + + if (Config::disableMhyProt) { + std::cout << "Trying to close mhyprot handle." << std::endl; + if (CloseHandleByName(L"\\Device\\mhyprot2")) + std::cout << "Mhyprot2 handle successfuly closed. Happy hacking ^)" << std::endl; + else + std::cout << "Failed closing mhyprot2 handle. Maybe dev updated driver." << std::endl; + } + +} \ No newline at end of file diff --git a/cheat-library/src/user/protection-bypass.h b/cheat-library/src/user/protection-bypass.h new file mode 100644 index 0000000..c5021a7 --- /dev/null +++ b/cheat-library/src/user/protection-bypass.h @@ -0,0 +1,3 @@ +#pragma once + +void InitProtectionBypass(); \ No newline at end of file diff --git a/cheat-library/src/user/util/Config.cpp b/cheat-library/src/user/util/Config.cpp new file mode 100644 index 0000000..ad3adf8 --- /dev/null +++ b/cheat-library/src/user/util/Config.cpp @@ -0,0 +1,29 @@ +#include "pch-il2cpp.h" + +#include "Config.h" + +#include "simple-ini.hpp" + +bool Config::disableMhyProt = false; +bool Config::consoleLogging = false; +bool Config::fileLogging = false; + +static CSimpleIni ini; +static bool changed = false; + +bool LoadBool(const char* section, const char* key, bool defaultValue = false) { + auto result = ini.GetBoolValue(section, key, defaultValue); + ini.SetBoolValue(section, key, result); + return result; +} + +void Config::Init(const std::string& configFile) +{ + ini.LoadFile(configFile.c_str()); + + disableMhyProt = LoadBool("DLLUtil", "DisableMhyprot", true); + consoleLogging = LoadBool("DLLUtil", "ConsoleLogging", true); + fileLogging = LoadBool("DLLUtil", "FileLogging", true); + + ini.SaveFile(configFile.c_str()); +} diff --git a/cheat-library/src/user/util/Config.h b/cheat-library/src/user/util/Config.h new file mode 100644 index 0000000..3f7e059 --- /dev/null +++ b/cheat-library/src/user/util/Config.h @@ -0,0 +1,11 @@ +#pragma once +#include + +class Config { +public: + static bool disableMhyProt; + static bool fileLogging; + static bool consoleLogging; + + static void Init(const std::string& configFile); +}; \ No newline at end of file diff --git a/cheat-library/src/user/util/HookManager.cpp b/cheat-library/src/user/util/HookManager.cpp new file mode 100644 index 0000000..ab55132 --- /dev/null +++ b/cheat-library/src/user/util/HookManager.cpp @@ -0,0 +1,40 @@ +#include "pch-il2cpp.h" +#include "HookManager.h" + +#include + +std::map HookManager::holderMap; + +//template +//static void HookManager::set(Fn func, Fn handler) noexcept +//{ +// auto existHolder = get(handler); +// if (existHolder != nullptr) +// existHolder->disable(); +// +// auto holder = HookFactory::install(func, handler); +// holderMap[handler] = holder; +//} + +//template +//static HookHolder* HookManager::get(Fn handler) noexcept +//{ +// if (holderMap.count(handler) == 0) +// return nullptr; +// return (HookHolder)* holderMap[handler]; +//} + +//template +//static Fn* HookManager::getOrigin(Fn handler) noexcept +//{ +// auto holder = get(handler); +// if (holder == nullptr) +// return nullptr; +// return &holder->origin(); +//} +// +//template +//static void HookManager::remove(Fn func) noexcept +//{ +// holderMap.erase(func); +//} diff --git a/cheat-library/src/user/util/HookManager.h b/cheat-library/src/user/util/HookManager.h new file mode 100644 index 0000000..90ef971 --- /dev/null +++ b/cheat-library/src/user/util/HookManager.h @@ -0,0 +1,46 @@ +#pragma once + +#include "HookLib.h" +#include + +#define callOrigin(function, ...) \ + HookManager::getOrigin(function)(__VA_ARGS__); + +class HookManager +{ +public: + template + static void set(Fn func, Fn handler) { + auto existHolder = get(handler); + if (existHolder != nullptr) + existHolder->disable(); + + auto holder = new HookHolder(func, handler); + holder->enable(); + + holderMap[reinterpret_cast(handler)] = reinterpret_cast(holder); + } + + template + [[nodiscard]] static HookHolder* get(Fn handler) noexcept { + if (holderMap.count(reinterpret_cast(handler)) == 0) + return nullptr; + return reinterpret_cast*>(holderMap[reinterpret_cast(handler)]); + } + + template + [[nodiscard]] static Fn getOrigin(Fn handler) noexcept { + auto holder = get(handler); + return holder->original(); + } + + template + [[nodiscard]] static void remove(Fn handler) noexcept { + holderMap.erase(reinterpret_cast(handler)); + } + +private: + static std::map holderMap; +}; + + diff --git a/cheat-library/src/user/util/util.cpp b/cheat-library/src/user/util/util.cpp new file mode 100644 index 0000000..2839b23 --- /dev/null +++ b/cheat-library/src/user/util/util.cpp @@ -0,0 +1,228 @@ +#include +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include +#include +#include + +#pragma comment(lib,"ntdll.lib") + +#define NT_SUCCESS(x) ((x) >= 0) +#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 + +#define SystemHandleInformation 16 +#define ObjectBasicInformation 0 +#define ObjectNameInformation 1 +#define ObjectTypeInformation 2 + +static int num = 0; + + +typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)( + ULONG SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength + ); +typedef NTSTATUS(NTAPI* _NtDuplicateObject)( + HANDLE SourceProcessHandle, + HANDLE SourceHandle, + HANDLE TargetProcessHandle, + PHANDLE TargetHandle, + ACCESS_MASK DesiredAccess, + ULONG Attributes, + ULONG Options + ); +typedef NTSTATUS(NTAPI* _NtQueryObject)( + HANDLE ObjectHandle, + ULONG ObjectInformationClass, + PVOID ObjectInformation, + ULONG ObjectInformationLength, + PULONG ReturnLength + ); + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, * PUNICODE_STRING; + +typedef struct _SYSTEM_HANDLE +{ + ULONG ProcessId; + BYTE ObjectTypeNumber; + BYTE Flags; + USHORT Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; +} SYSTEM_HANDLE, * PSYSTEM_HANDLE; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG HandleCount; + SYSTEM_HANDLE Handles[1]; +} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; + +typedef enum _POOL_TYPE +{ + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS +} POOL_TYPE, * PPOOL_TYPE; + +typedef struct _OBJECT_TYPE_INFORMATION +{ + UNICODE_STRING Name; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccess; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + USHORT MaintainTypeList; + POOL_TYPE PoolType; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; +} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; + +typedef struct _SYSTEM_PROCESS_INFO +{ + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER Reserved[3]; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + ULONG BasePriority; + HANDLE ProcessId; + HANDLE InheritedFromProcessId; +}SYSTEM_PROCESS_INFO, * PSYSTEM_PROCESS_INFO; + +PVOID GetLibraryProcAddress(LPCSTR LibraryName, LPCSTR ProcName) +{ + return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); +} + +bool CloseHandleByName(const wchar_t* name) +{ + _NtQuerySystemInformation NtQuerySystemInformation = + (_NtQuerySystemInformation)GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); + _NtDuplicateObject NtDuplicateObject = + (_NtDuplicateObject)GetLibraryProcAddress("ntdll.dll", "NtDuplicateObject"); + _NtQueryObject NtQueryObject = + (_NtQueryObject)GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); + NTSTATUS status; + + ULONG handleInfoSize = 0x10000; + PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); + + ULONG pid; + HANDLE processHandle = GetCurrentProcess(); + ULONG i; + + /* NtQuerySystemInformation won't give us the correct buffer size, + so we guess by doubling the buffer size. */ + while ((status = NtQuerySystemInformation( + SystemHandleInformation, + handleInfo, + handleInfoSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2); + + /* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */ + if (!NT_SUCCESS(status)) + { + std::cout << "NtQuerySystemInformation failed!" << std::endl; + return false; + } + + bool closed = false; + for (i = 0; i < handleInfo->HandleCount; i++) + { + if (closed) + break; + + SYSTEM_HANDLE handle = handleInfo->Handles[i]; + HANDLE dupHandle = NULL; + POBJECT_TYPE_INFORMATION objectTypeInfo; + PVOID objectNameInfo; + UNICODE_STRING objectName; + ULONG returnLength; + + /* Duplicate the handle so we can query it. */ + if (!NT_SUCCESS(NtDuplicateObject(processHandle, (HANDLE)handle.Handle, GetCurrentProcess(), &dupHandle, 0, 0, 0))) + continue; + + /* Query the object type. */ + objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); + if (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL))) + { + CloseHandle(dupHandle); + continue; + } + + /* Query the object name (unless it has an access of + 0x0012019f, on which NtQueryObject could hang. */ + if (handle.GrantedAccess == 0x0012019f) + { + free(objectTypeInfo); + CloseHandle(dupHandle); + continue; + } + + objectNameInfo = malloc(0x1000); + if (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength))) + { + /* Reallocate the buffer and try again. */ + objectNameInfo = realloc(objectNameInfo, returnLength); + if (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectNameInformation, objectNameInfo, returnLength, NULL))) + { + free(objectTypeInfo); + free(objectNameInfo); + CloseHandle(dupHandle); + continue; + } + } + + /* Cast our buffer into an UNICODE_STRING. */ + objectName = *(PUNICODE_STRING)objectNameInfo; + + /* Print the information! */ + if (objectName.Length && lstrcmpiW(objectName.Buffer, name) == 0) + { + CloseHandle((HANDLE)handle.Handle); + closed = true; + } + + free(objectTypeInfo); + free(objectNameInfo); + CloseHandle(dupHandle); + + } + + free(handleInfo); + CloseHandle(processHandle); + return closed; +} \ No newline at end of file diff --git a/cheat-library/src/user/util/util.h b/cheat-library/src/user/util/util.h new file mode 100644 index 0000000..87a11e3 --- /dev/null +++ b/cheat-library/src/user/util/util.h @@ -0,0 +1,3 @@ +#pragma once + +bool CloseHandleByName(const wchar_t* name); \ No newline at end of file diff --git a/cheat-library/vendor/include/HookLib.h b/cheat-library/vendor/include/HookLib.h new file mode 100644 index 0000000..fb23bc8 --- /dev/null +++ b/cheat-library/vendor/include/HookLib.h @@ -0,0 +1,212 @@ +#pragma once + +#ifdef __cplusplus + #include + #define hooklib_export extern "C" +#else + #include + #define hooklib_export +#endif + +typedef struct +{ + void* fn; + const void* handler; + void* original; // hook() makes it valid callable pointer after successful hook and sets as nullptr otherwise +} Hook; + +typedef struct +{ + void* original; // unhook() makes it nullptr after successful unhook and keeps unchanged otherwise +} Unhook; + +hooklib_export void* hook(void* fn, const void* handler); +hooklib_export size_t multihook(Hook* hooks, size_t count); + +hooklib_export size_t multiunhook(Unhook* originals, size_t count); +hooklib_export size_t unhook(void* original); + +#ifndef _KERNEL_MODE +hooklib_export void* lookupModule(const wchar_t* modName); // LdrGetDllHandle +hooklib_export void* lookupFunction(const void* hModule, const char* funcName); // LdrGetProcedureAddress +#endif + +#ifdef __cplusplus +template +class HookHolder +{ +private: + struct tr + { + template + static constexpr Type exchange(Type& val, Other&& newVal) + { + const Type oldVal = static_cast(val); + val = static_cast(newVal); + return oldVal; + } + }; + +protected: + Fn m_orig; + Fn m_fn; + Fn m_handler; + +public: + HookHolder() = default; + + HookHolder(Fn fn, Fn handler) noexcept : m_orig(nullptr), m_fn(fn), m_handler(handler) + { + } + + HookHolder(const HookHolder&) = delete; + + HookHolder(HookHolder&& holder) noexcept + : m_orig(tr::exchange(holder.m_orig, nullptr)) + , m_fn(tr::exchange(holder.m_fn, nullptr)) + , m_handler(tr::exchange(holder.m_handler, nullptr)) + { + } + + HookHolder& operator = (const HookHolder&) = delete; + + HookHolder& operator = (HookHolder&& holder) noexcept + { + if (&holder == this) + { + return *this; + } + + disable(); + + m_orig = tr::exchange(holder.m_orig, nullptr); + m_fn = tr::exchange(holder.m_fn, nullptr); + m_handler = tr::exchange(holder.m_handler, nullptr); + + return *this; + } + + ~HookHolder() noexcept + { + if (active()) + { + disable(); + } + } + + bool valid() const noexcept + { + return m_fn && m_handler; + } + + bool active() const noexcept + { + return m_orig != nullptr; + } + + bool enable() noexcept + { + if (!valid()) + { + return false; + } + + if (active()) + { + return true; + } + + m_orig = static_cast(hook(m_fn, m_handler)); + + return m_orig != nullptr; + } + + bool disable() noexcept + { + if (!valid()) + { + return false; + } + + if (!active()) + { + return true; + } + + const bool unhookStatus = (unhook(m_orig) == 1); + if (unhookStatus) + { + m_orig = nullptr; + } + + return unhookStatus; + } + + Fn detach() noexcept + { + return tr::exchange(m_orig, nullptr); + } + + Fn original() const noexcept + { + return m_orig; + } + + Fn fn() const noexcept + { + return m_fn; + } + + Fn handler() const noexcept + { + return m_handler; + } + +#ifdef _MSC_VER + __declspec(property(get = original)) Fn call; +#endif +}; + +struct HookFactory +{ + template + [[nodiscard]] static HookHolder install(Fn fn, Fn handler) noexcept + { + HookHolder hook(fn, handler); + hook.enable(); + return hook; + } + + template + [[nodiscard]] static HookHolder install(void* fn, Fn handler) noexcept + { + return install(static_cast(fn), handler); + } + +#ifndef _KERNEL_MODE + template + [[nodiscard]] static HookHolder install(void* mod, const char* const funcName, Fn handler) noexcept + { + if (!mod) + { + return HookHolder(nullptr, handler); + } + + void* const fn = lookupFunction(mod, funcName); + if (!fn) + { + return HookHolder(nullptr, handler); + } + + return install(static_cast(fn), handler); + } + + template + [[nodiscard]] static HookHolder install(const wchar_t* const modName, const char* const funcName, Fn handler) noexcept + { + const void* const mod = lookupModule(modName); + return install(mod, funcName, handler); + } +#endif +}; +#endif \ No newline at end of file diff --git a/cheat-library/vendor/include/simple-ini.hpp b/cheat-library/vendor/include/simple-ini.hpp new file mode 100644 index 0000000..54de89d --- /dev/null +++ b/cheat-library/vendor/include/simple-ini.hpp @@ -0,0 +1,3487 @@ +/** @mainpage + + +
Library SimpleIni +
File SimpleIni.h +
Author Brodie Thiesfield [brofield at gmail dot com] +
Source https://github.com/brofield/simpleini +
Version 4.17 +
+ + Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation. + + @section intro INTRODUCTION + + This component allows an INI-style configuration file to be used on both + Windows and Linux/Unix. It is fast, simple and source code using this + component will compile unchanged on either OS. + + + @section features FEATURES + + - MIT Licence allows free use in all software (including GPL and commercial) + - multi-platform (Windows CE/9x/NT..10/etc, Linux, MacOSX, Unix) + - loading and saving of INI-style configuration files + - configuration files can have any newline format on all platforms + - liberal acceptance of file format + - key/values with no section + - removal of whitespace around sections, keys and values + - support for multi-line values (values with embedded newline characters) + - optional support for multiple keys with the same name + - optional case-insensitive sections and keys (for ASCII characters only) + - saves files with sections and keys in the same order as they were loaded + - preserves comments on the file, section and keys where possible. + - supports both char or wchar_t programming interfaces + - supports both MBCS (system locale) and UTF-8 file encodings + - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file + - support for non-ASCII characters in section, keys, values and comments + - support for non-standard character types or file encodings + via user-written converter classes + - support for adding/modifying values programmatically + - compiles cleanly in the following compilers: + - Windows/VC6 (warning level 3) + - Windows/VC.NET 2003 (warning level 4) + - Windows/VC 2005 (warning level 4) + - Linux/gcc (-Wall) + + + @section usage USAGE SUMMARY + + -# Define the appropriate symbol for the converter you wish to use and + include the SimpleIni.h header file. If no specific converter is defined + then the default converter is used. The default conversion mode uses + SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other + platforms. If you are using ICU then SI_CONVERT_ICU is supported on all + platforms. + -# Declare an instance the appropriate class. Note that the following + definitions are just shortcuts for commonly used types. Other types + (PRUnichar, unsigned short, unsigned char) are also possible. + +
Interface Case-sensitive Load UTF-8 Load MBCS Typedef +
SI_CONVERT_GENERIC +
char No Yes Yes #1 CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_WIN32 +
char No No #2 Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_ICU +
char No Yes Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
UChar No Yes Yes CSimpleIniW +
UChar Yes Yes Yes CSimpleIniCaseW +
+ #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.
+ #2 Only affects Windows. On Windows this uses MBCS functions and + so may fold case incorrectly leading to uncertain results. + -# Call LoadData() or LoadFile() to load and parse the INI configuration file + -# Access and modify the data of the file using the following functions + +
GetAllSections Return all section names +
GetAllKeys Return all key names within a section +
GetAllValues Return all values within a section & key +
GetSection Return all key names and values in a section +
GetSectionSize Return the number of keys in a section +
GetValue Return a value for a section & key +
SetValue Add or update a value for a section & key +
Delete Remove a section, or a key from a section +
+ -# Call Save() or SaveFile() to save the INI configuration data + + @section iostreams IO STREAMS + + SimpleIni supports reading from and writing to STL IO streams. Enable this + by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header + file. Ensure that if the streams are backed by a file (e.g. ifstream or + ofstream) then the flag ios_base::binary has been used when the file was + opened. + + @section multiline MULTI-LINE VALUES + + Values that span multiple lines are created using the following format. + +
+        key = <<
+
+    Note the following:
+    - The text used for ENDTAG can be anything and is used to find
+      where the multi-line text ends.
+    - The newline after ENDTAG in the start tag, and the newline
+      before ENDTAG in the end tag is not included in the data value.
+    - The ending tag must be on it's own line with no whitespace before
+      or after it.
+    - The multi-line value is modified at load so that each line in the value
+      is delimited by a single '\\n' character on all platforms. At save time
+      it will be converted into the newline format used by the current
+      platform.
+
+    @section comments COMMENTS
+
+    Comments are preserved in the file within the following restrictions:
+    - Every file may have a single "file comment". It must start with the
+      first character in the file, and will end with the first non-comment
+      line in the file.
+    - Every section may have a single "section comment". It will start
+      with the first comment line following the file comment, or the last
+      data entry. It ends at the beginning of the section.
+    - Every key may have a single "key comment". This comment will start
+      with the first comment line following the section start, or the file
+      comment if there is no section name.
+    - Comments are set at the time that the file, section or key is first
+      created. The only way to modify a comment on a section or a key is to
+      delete that entry and recreate it with the new comment. There is no
+      way to change the file comment.
+
+    @section save SAVE ORDER
+
+    The sections and keys are written out in the same order as they were
+    read in from the file. Sections and keys added to the data after the
+    file has been loaded will be added to the end of the file when it is
+    written. There is no way to specify the location of a section or key
+    other than in first-created, first-saved order.
+
+    @section notes NOTES
+
+    - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
+      Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
+    - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
+    - When using SI_CONVERT_ICU, ICU header files must be on the include
+      path and icuuc.lib must be linked in.
+    - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
+      you should use SI_CONVERT_GENERIC.
+    - The collation (sorting) order used for sections and keys returned from
+      iterators is NOT DEFINED. If collation order of the text is important
+      then it should be done yourself by either supplying a replacement
+      SI_STRLESS class, or by sorting the strings external to this library.
+    - Usage of the  header on Windows can be disabled by defining
+      SI_NO_MBCS. This is defined automatically on Windows CE platforms.
+    - Not thread-safe so manage your own locking
+
+    @section contrib CONTRIBUTIONS
+    
+    - 2010/05/03: Tobias Gehrig: added GetDoubleValue()
+
+    @section licence MIT LICENCE
+
+    The licence text below is the boilerplate "MIT Licence" used from:
+    http://www.opensource.org/licenses/mit-license.php
+
+    Copyright (c) 2006-2012, Brodie Thiesfield
+
+    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.
+*/
+
+#ifndef INCLUDED_SimpleIni_h
+#define INCLUDED_SimpleIni_h
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Disable these warnings in MSVC:
+//  4127 "conditional expression is constant" as the conversion classes trigger
+//  it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
+//  be optimized away in a release build.
+//  4503 'insert' : decorated name length exceeded, name was truncated
+//  4702 "unreachable code" as the MS STL header causes it in release mode.
+//  Again, the code causing the warning will be cleaned up by the compiler.
+//  4786 "identifier truncated to 256 characters" as this is thrown hundreds
+//  of times VC6 as soon as STL is used.
+#ifdef _MSC_VER
+# pragma warning (push)
+# pragma warning (disable: 4127 4503 4702 4786)
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef SI_SUPPORT_IOSTREAMS
+# include 
+#endif // SI_SUPPORT_IOSTREAMS
+
+#ifdef _DEBUG
+# ifndef assert
+#  include 
+# endif
+# define SI_ASSERT(x)   assert(x)
+#else
+# define SI_ASSERT(x)
+#endif
+
+enum SI_Error {
+    SI_OK       =  0,   //!< No error
+    SI_UPDATED  =  1,   //!< An existing value was updated
+    SI_INSERTED =  2,   //!< A new value was inserted
+
+    // note: test for any error with (retval < 0)
+    SI_FAIL     = -1,   //!< Generic failure
+    SI_NOMEM    = -2,   //!< Out of memory error
+    SI_FILE     = -3    //!< File error (see errno for detail error)
+};
+
+#define SI_UTF8_SIGNATURE     "\xEF\xBB\xBF"
+
+#ifdef _WIN32
+# define SI_NEWLINE_A   "\r\n"
+# define SI_NEWLINE_W   L"\r\n"
+#else // !_WIN32
+# define SI_NEWLINE_A   "\n"
+# define SI_NEWLINE_W   L"\n"
+#endif // _WIN32
+
+#if defined(SI_CONVERT_ICU)
+# include 
+#endif
+
+#if defined(_WIN32)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     wchar_t
+#elif defined(SI_CONVERT_ICU)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     UChar
+#endif
+
+
+// ---------------------------------------------------------------------------
+//                              MAIN TEMPLATE CLASS
+// ---------------------------------------------------------------------------
+
+/** Simple INI file reader.
+
+    This can be instantiated with the choice of unicode or native characterset,
+    and case sensitive or insensitive comparisons of section and key names.
+    The supported combinations are pre-defined with the following typedefs:
+
+    
+        
Interface Case-sensitive Typedef +
char No CSimpleIniA +
char Yes CSimpleIniCaseA +
wchar_t No CSimpleIniW +
wchar_t Yes CSimpleIniCaseW +
+ + Note that using other types for the SI_CHAR is supported. For instance, + unsigned char, unsigned short, etc. Note that where the alternative type + is a different size to char/wchar_t you may need to supply new helper + classes for SI_STRLESS and SI_CONVERTER. + */ +template +class CSimpleIniTempl +{ +public: + typedef SI_CHAR SI_CHAR_T; + + /** key entry */ + struct Entry { + const SI_CHAR * pItem; + const SI_CHAR * pComment; + int nOrder; + + Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) + : pItem(a_pszItem) + , pComment(NULL) + , nOrder(a_nOrder) + { } + Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) + : pItem(a_pszItem) + , pComment(a_pszComment) + , nOrder(a_nOrder) + { } + Entry(const Entry & rhs) { operator=(rhs); } + Entry & operator=(const Entry & rhs) { + pItem = rhs.pItem; + pComment = rhs.pComment; + nOrder = rhs.nOrder; + return *this; + } + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } + bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } +#endif + + /** Strict less ordering by name of key only */ + struct KeyOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(lhs.pItem, rhs.pItem); + } + }; + + /** Strict less ordering by order, and then name of key */ + struct LoadOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + if (lhs.nOrder != rhs.nOrder) { + return lhs.nOrder < rhs.nOrder; + } + return KeyOrder()(lhs.pItem, rhs.pItem); + } + }; + }; + + /** map keys to values */ + typedef std::multimap TKeyVal; + + /** map sections to key/value map */ + typedef std::map TSection; + + /** set of dependent string pointers. Note that these pointers are + dependent on memory owned by CSimpleIni. + */ + typedef std::list TNamesDepend; + + /** interface definition for the OutputWriter object to pass to Save() + in order to output the INI file data. + */ + class OutputWriter { + public: + OutputWriter() { } + virtual ~OutputWriter() { } + virtual void Write(const char * a_pBuf) = 0; + private: + OutputWriter(const OutputWriter &); // disable + OutputWriter & operator=(const OutputWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a file */ + class FileWriter : public OutputWriter { + FILE * m_file; + public: + FileWriter(FILE * a_file) : m_file(a_file) { } + void Write(const char * a_pBuf) { + fputs(a_pBuf, m_file); + } + private: + FileWriter(const FileWriter &); // disable + FileWriter & operator=(const FileWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a string */ + class StringWriter : public OutputWriter { + std::string & m_string; + public: + StringWriter(std::string & a_string) : m_string(a_string) { } + void Write(const char * a_pBuf) { + m_string.append(a_pBuf); + } + private: + StringWriter(const StringWriter &); // disable + StringWriter & operator=(const StringWriter &); // disable + }; + +#ifdef SI_SUPPORT_IOSTREAMS + /** OutputWriter class to write the INI data to an ostream */ + class StreamWriter : public OutputWriter { + std::ostream & m_ostream; + public: + StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } + void Write(const char * a_pBuf) { + m_ostream << a_pBuf; + } + private: + StreamWriter(const StreamWriter &); // disable + StreamWriter & operator=(const StreamWriter &); // disable + }; +#endif // SI_SUPPORT_IOSTREAMS + + /** Characterset conversion utility class to convert strings to the + same format as is used for the storage. + */ + class Converter : private SI_CONVERTER { + public: + Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { + m_scratch.resize(1024); + } + Converter(const Converter & rhs) { operator=(rhs); } + Converter & operator=(const Converter & rhs) { + m_scratch = rhs.m_scratch; + return *this; + } + bool ConvertToStore(const SI_CHAR * a_pszString) { + size_t uLen = SI_CONVERTER::SizeToStore(a_pszString); + if (uLen == (size_t)(-1)) { + return false; + } + while (uLen > m_scratch.size()) { + m_scratch.resize(m_scratch.size() * 2); + } + return SI_CONVERTER::ConvertToStore( + a_pszString, + const_cast(m_scratch.data()), + m_scratch.size()); + } + const char * Data() { return m_scratch.data(); } + private: + std::string m_scratch; + }; + +public: + /*-----------------------------------------------------------------------*/ + + /** Default constructor. + + @param a_bIsUtf8 See the method SetUnicode() for details. + @param a_bMultiKey See the method SetMultiKey() for details. + @param a_bMultiLine See the method SetMultiLine() for details. + */ + CSimpleIniTempl( + bool a_bIsUtf8 = false, + bool a_bMultiKey = false, + bool a_bMultiLine = false + ); + + /** Destructor */ + ~CSimpleIniTempl(); + + /** Deallocate all memory stored by this object */ + void Reset(); + + /** Has any data been loaded */ + bool IsEmpty() const { return m_data.empty(); } + + /*-----------------------------------------------------------------------*/ + /** @{ @name Settings */ + + /** Set the storage format of the INI data. This affects both the loading + and saving of the INI data using all of the Load/Save API functions. + This value cannot be changed after any INI data has been loaded. + + If the file is not set to Unicode (UTF-8), then the data encoding is + assumed to be the OS native encoding. This encoding is the system + locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP. + If the storage format is set to Unicode then the file will be loaded + as UTF-8 encoded data regardless of the native file encoding. If + SI_CHAR == char then all of the char* parameters take and return UTF-8 + encoded data regardless of the system locale. + + \param a_bIsUtf8 Assume UTF-8 encoding for the source? + */ + void SetUnicode(bool a_bIsUtf8 = true) { + if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; + } + + /** Get the storage format of the INI data. */ + bool IsUnicode() const { return m_bStoreIsUtf8; } + + /** Should multiple identical keys be permitted in the file. If set to false + then the last value encountered will be used as the value of the key. + If set to true, then all values will be available to be queried. For + example, with the following input: + +
+        [section]
+        test=value1
+        test=value2
+        
+ + Then with SetMultiKey(true), both of the values "value1" and "value2" + will be returned for the key test. If SetMultiKey(false) is used, then + the value for "test" will only be "value2". This value may be changed + at any time. + + \param a_bAllowMultiKey Allow multi-keys in the source? + */ + void SetMultiKey(bool a_bAllowMultiKey = true) { + m_bAllowMultiKey = a_bAllowMultiKey; + } + + /** Get the storage format of the INI data. */ + bool IsMultiKey() const { return m_bAllowMultiKey; } + + /** Should data values be permitted to span multiple lines in the file. If + set to false then the multi-line construct << + SI_CHAR FORMAT + char same format as when loaded (MBCS or UTF-8) + wchar_t UTF-8 + other UTF-8 + + + Note that comments from the original data is preserved as per the + documentation on comments. The order of the sections and values + from the original file will be preserved. + + Any data prepended or appended to the output device must use the the + same format (MBCS or UTF-8). You may use the GetConverter() method to + convert text to the correct format regardless of the output format + being used by SimpleIni. + + To add a BOM to UTF-8 data, write it out manually at the very beginning + like is done in SaveFile when a_bUseBOM is true. + + @param a_oOutput Output writer to write the data to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the OutputWriter. + + @return SI_Error See error definitions + */ + SI_Error Save( + OutputWriter & a_oOutput, + bool a_bAddSignature = false + ) const; + +#ifdef SI_SUPPORT_IOSTREAMS + /** Save the INI data to an ostream. See Save() for details. + + @param a_ostream String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the stream. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::ostream & a_ostream, + bool a_bAddSignature = false + ) const + { + StreamWriter writer(a_ostream); + return Save(writer, a_bAddSignature); + } +#endif // SI_SUPPORT_IOSTREAMS + + /** Append the INI data to a string. See Save() for details. + + @param a_sBuffer String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the string. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::string & a_sBuffer, + bool a_bAddSignature = false + ) const + { + StringWriter writer(a_sBuffer); + return Save(writer, a_bAddSignature); + } + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Accessing INI Data */ + + /** Retrieve all section names. The list is returned as an STL vector of + names and can be iterated or searched as necessary. Note that the + sort order of the returned strings is NOT DEFINED. You can sort + the names into the load order if desired. Search this file for ".sort" + for an example. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these pointers + are in use! + + @param a_names Vector that will receive all of the section + names. See note above! + */ + void GetAllSections( + TNamesDepend & a_names + ) const; + + /** Retrieve all unique key names in a section. The sort order of the + returned strings is NOT DEFINED. You can sort the names into the load + order if desired. Search this file for ".sort" for an example. Only + unique key names are returned. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Section to request data for + @param a_names List that will receive all of the key + names. See note above! + + @return true Section was found. + @return false Matching section was not found. + */ + bool GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const; + + /** Retrieve all values for a specific key. This method can be used when + multiple keys are both enabled and disabled. Note that the sort order + of the returned strings is NOT DEFINED. You can sort the names into + the load order if desired. Search this file for ".sort" for an example. + + NOTE! The returned values are pointers to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_values List to return if the key is not found + + @return true Key was found. + @return false Matching section/key was not found. + */ + bool GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const; + + /** Query the number of keys in a specific section. Note that if multiple + keys are enabled, then this value may be different to the number of + keys returned by GetAllKeys. + + @param a_pSection Section to request data for + + @return -1 Section does not exist in the file + @return >=0 Number of keys in the section + */ + int GetSectionSize( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve all key and value pairs for a section. The data is returned + as a pointer to an STL map and can be iterated or searched as + desired. Note that multiple entries for the same key may exist when + multiple keys have been enabled. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Name of the section to return + @return boolean Was a section matching the supplied + name found. + */ + const TKeyVal * GetSection( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve the value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + NOTE! The returned value is a pointer to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_pDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_pDefault Key was not found in the section + @return other Value of the key + */ + const SI_CHAR * GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault = NULL, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + long GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + double GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a boolean value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + Strings starting with "t", "y", "on" or "1" are returned as logically true. + Strings starting with "f", "n", "of" or "0" are returned as logically false. + For all other values the default is returned. Character comparisons are + case-insensitive. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_bDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + bool GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault = false, + bool * a_pHasMultiple = NULL + ) const; + + /** Add or update a section or value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. Set to NULL to + create an empty section. + @param a_pValue Value to set. Set to NULL to create an + empty section. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. Note that a + comment may be set ONLY when the section or key is + first created (i.e. when this function returns the + value SI_INSERTED). If you wish to create a section + with a comment then you need to create the section + separately to the key. The comment string must be + in full comment form already (have a comment + character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetValue and SetValue + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ) + { + return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); + } + + /** Add or update a numeric value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bUseHex By default the value will be written to the file + in decimal format. Set this to true to write it + as hexadecimal. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetLongValue and + SetLongValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bUseHex = false, + bool a_bForceReplace = false + ); + + /** Add or update a double value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetDoubleValue and + SetDoubleValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Add or update a boolean value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_bValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetBoolValue and + SetBoolValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Delete an entire section, or a key from a section. Note that the + data returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, this will delete all keys with + that name; to selectively delete individual key/values, use + DeleteValue. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key or section was deleted. + @return false Key or section was not found. + */ + bool Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty = false + ); + + /** Delete an entire section, or a key from a section. If value is + provided, only remove keys with the value. Note that the data + returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, all keys with the value will + be deleted. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_pValue Value of key to remove from the section. + Set to NULL to remove all keys. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key/value or section was deleted. + @return false Key/value or section was not found. + */ + bool DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty = false + ); + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Converter */ + + /** Return a conversion object to convert text to the same encoding + as is used by the Save(), SaveFile() and SaveString() functions. + Use this to prepare the strings that you wish to append or prepend + to the output INI data. + */ + Converter GetConverter() const { + return Converter(m_bStoreIsUtf8); + } + + /*-----------------------------------------------------------------------*/ + /** @} */ + +private: + // copying is not permitted + CSimpleIniTempl(const CSimpleIniTempl &); // disabled + CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled + + /** Parse the data looking for a file comment and store it if found. + */ + SI_Error FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ); + + /** Parse the data looking for the next valid entry. The memory pointed to + by a_pData is modified by inserting NULL characters. The pointer is + updated to the current location in the block of text. + */ + bool FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const; + + /** Add the section/key/value to our data. + + @param a_pSection Section name. Sections will be created if they + don't already exist. + @param a_pKey Key name. May be NULL to create an empty section. + Existing entries will be updated. New entries will + be created. + @param a_pValue Value for the key. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. This must be + a string in full comment form already (have a + comment character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/AddEntry and AddEntry + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + @param a_bCopyStrings Should copies of the strings be made or not. + If false then the pointers will be used as is. + */ + SI_Error AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ); + + /** Is the supplied character a whitespace character? */ + inline bool IsSpace(SI_CHAR ch) const { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + } + + /** Does the supplied character start a comment line? */ + inline bool IsComment(SI_CHAR ch) const { + return (ch == ';' || ch == '#'); + } + + + /** Skip over a newline character (or characters) for either DOS or UNIX */ + inline void SkipNewLine(SI_CHAR *& a_pData) const { + a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; + } + + /** Make a copy of the supplied string, replacing the original pointer */ + SI_Error CopyString(const SI_CHAR *& a_pString); + + /** Delete a string from the copied strings buffer if necessary */ + void DeleteString(const SI_CHAR * a_pString); + + /** Internal use of our string comparison function */ + bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(a_pLeft, a_pRight); + } + + bool IsMultiLineTag(const SI_CHAR * a_pData) const; + bool IsMultiLineData(const SI_CHAR * a_pData) const; + bool LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment = false + ) const; + bool IsNewLineChar(SI_CHAR a_c) const; + + bool OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const; + +private: + /** Copy of the INI file data in our character format. This will be + modified when parsed to have NULL characters added after all + interesting string entries. All of the string pointers to sections, + keys and values point into this block of memory. + */ + SI_CHAR * m_pData; + + /** Length of the data that we have stored. Used when deleting strings + to determine if the string is stored here or in the allocated string + buffer. + */ + size_t m_uDataLen; + + /** File comment for this data, if one exists. */ + const SI_CHAR * m_pFileComment; + + /** Parsed INI data. Section -> (Key -> Value). */ + TSection m_data; + + /** This vector stores allocated memory for copies of strings that have + been supplied after the file load. It will be empty unless SetValue() + has been called. + */ + TNamesDepend m_strings; + + /** Is the format of our datafile UTF-8 or MBCS? */ + bool m_bStoreIsUtf8; + + /** Are multiple values permitted for the same key? */ + bool m_bAllowMultiKey; + + /** Are data values permitted to span multiple lines? */ + bool m_bAllowMultiLine; + + /** Should spaces be written out surrounding the equals sign? */ + bool m_bSpaces; + + /** Next order value, used to ensure sections and keys are output in the + same order that they are loaded/added. + */ + int m_nOrder; +}; + +// --------------------------------------------------------------------------- +// IMPLEMENTATION +// --------------------------------------------------------------------------- + +template +CSimpleIniTempl::CSimpleIniTempl( + bool a_bIsUtf8, + bool a_bAllowMultiKey, + bool a_bAllowMultiLine + ) + : m_pData(0) + , m_uDataLen(0) + , m_pFileComment(NULL) + , m_bStoreIsUtf8(a_bIsUtf8) + , m_bAllowMultiKey(a_bAllowMultiKey) + , m_bAllowMultiLine(a_bAllowMultiLine) + , m_bSpaces(true) + , m_nOrder(0) +{ } + +template +CSimpleIniTempl::~CSimpleIniTempl() +{ + Reset(); +} + +template +void +CSimpleIniTempl::Reset() +{ + // remove all data + delete[] m_pData; + m_pData = NULL; + m_uDataLen = 0; + m_pFileComment = NULL; + if (!m_data.empty()) { + m_data.erase(m_data.begin(), m_data.end()); + } + + // remove all strings + if (!m_strings.empty()) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) { + delete[] const_cast(i->pItem); + } + m_strings.erase(m_strings.begin(), m_strings.end()); + } +} + +template +SI_Error +CSimpleIniTempl::LoadFile( + const char * a_pszFile + ) +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) { + return SI_FILE; + } + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::LoadFile( + const SI_WCHAR_T * a_pwszFile + ) +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return LoadFile(szFile); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::LoadFile( + FILE * a_fpFile + ) +{ + // load the raw file data + int retval = fseek(a_fpFile, 0, SEEK_END); + if (retval != 0) { + return SI_FILE; + } + long lSize = ftell(a_fpFile); + if (lSize < 0) { + return SI_FILE; + } + if (lSize == 0) { + return SI_OK; + } + + // allocate and ensure NULL terminated + char * pData = new(std::nothrow) char[lSize+1]; + if (!pData) { + return SI_NOMEM; + } + pData[lSize] = 0; + + // load data into buffer + fseek(a_fpFile, 0, SEEK_SET); + size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); + if (uRead != (size_t) lSize) { + delete[] pData; + return SI_FILE; + } + + // convert the raw data to unicode + SI_Error rc = LoadData(pData, uRead); + delete[] pData; + return rc; +} + +template +SI_Error +CSimpleIniTempl::LoadData( + const char * a_pData, + size_t a_uDataLen + ) +{ + if (!a_pData) { + return SI_OK; + } + + // if the UTF-8 BOM exists, consume it and set mode to unicode, if we have + // already loaded data and try to change mode half-way through then this will + // be ignored and we will assert in debug versions + if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { + a_pData += 3; + a_uDataLen -= 3; + SI_ASSERT(m_bStoreIsUtf8 || !m_pData); // we don't expect mixed mode data + SetUnicode(); + } + + if (a_uDataLen == 0) { + return SI_OK; + } + + // determine the length of the converted data + SI_CONVERTER converter(m_bStoreIsUtf8); + size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); + if (uLen == (size_t)(-1)) { + return SI_FAIL; + } + + // allocate memory for the data, ensure that there is a NULL + // terminator wherever the converted data ends + SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen+1]; + if (!pData) { + return SI_NOMEM; + } + memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); + + // convert the data + if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { + delete[] pData; + return SI_FAIL; + } + + // parse it + const static SI_CHAR empty = 0; + SI_CHAR * pWork = pData; + const SI_CHAR * pSection = ∅ + const SI_CHAR * pItem = NULL; + const SI_CHAR * pVal = NULL; + const SI_CHAR * pComment = NULL; + + // We copy the strings if we are loading data into this class when we + // already have stored some. + bool bCopyStrings = (m_pData != NULL); + + // find a file comment if it exists, this is a comment that starts at the + // beginning of the file and continues until the first blank line. + SI_Error rc = FindFileComment(pWork, bCopyStrings); + if (rc < 0) return rc; + + // add every entry in the file to the data table + while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { + rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); + if (rc < 0) return rc; + } + + // store these strings if we didn't copy them + if (bCopyStrings) { + delete[] pData; + } + else { + m_pData = pData; + m_uDataLen = uLen+1; + } + + return SI_OK; +} + +#ifdef SI_SUPPORT_IOSTREAMS +template +SI_Error +CSimpleIniTempl::LoadData( + std::istream & a_istream + ) +{ + std::string strData; + char szBuf[512]; + do { + a_istream.get(szBuf, sizeof(szBuf), '\0'); + strData.append(szBuf); + } + while (a_istream.good()); + return LoadData(strData); +} +#endif // SI_SUPPORT_IOSTREAMS + +template +SI_Error +CSimpleIniTempl::FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ) +{ + // there can only be a single file comment + if (m_pFileComment) { + return SI_OK; + } + + // Load the file comment as multi-line text, this will modify all of + // the newline characters to be single \n chars + if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { + return SI_OK; + } + + // copy the string if necessary + if (a_bCopyStrings) { + SI_Error rc = CopyString(m_pFileComment); + if (rc < 0) return rc; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const +{ + a_pComment = NULL; + + SI_CHAR * pTrail = NULL; + while (*a_pData) { + // skip spaces and empty lines + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + if (!*a_pData) { + break; + } + + // skip processing of comment lines but keep a pointer to + // the start of the comment. + if (IsComment(*a_pData)) { + LoadMultiLineText(a_pData, a_pComment, NULL, true); + continue; + } + + // process section names + if (*a_pData == '[') { + // skip leading spaces + ++a_pData; + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the section name (it may contain spaces) + // and convert it to lowercase as necessary + a_pSection = a_pData; + while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != ']') { + continue; + } + + // remove trailing spaces from the section + pTrail = a_pData - 1; + while (pTrail >= a_pSection && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip to the end of the line + ++a_pData; // safe as checked that it == ']' above + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + a_pKey = NULL; + a_pVal = NULL; + return true; + } + + // find the end of the key name (it may contain spaces) + // and convert it to lowercase as necessary + a_pKey = a_pData; + while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != '=') { + continue; + } + + // empty keys are invalid + if (a_pKey == a_pData) { + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + continue; + } + + // remove trailing spaces from the key + pTrail = a_pData - 1; + while (pTrail >= a_pKey && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip leading whitespace on the value + ++a_pData; // safe as checked that it == '=' above + while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the value which is the end of this line + a_pVal = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // remove trailing spaces from the value + pTrail = a_pData - 1; + if (*a_pData) { // prepare for the next round + SkipNewLine(a_pData); + } + while (pTrail >= a_pVal && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // check for multi-line entries + if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { + // skip the "<<<" to get the tag that will end the multiline + const SI_CHAR * pTagName = a_pVal + 3; + return LoadMultiLineText(a_pData, a_pVal, pTagName); + } + + // return the standard entry + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsMultiLineTag( + const SI_CHAR * a_pVal + ) const +{ + // check for the "<<<" prefix for a multi-line entry + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + return true; +} + +template +bool +CSimpleIniTempl::IsMultiLineData( + const SI_CHAR * a_pData + ) const +{ + // data is multi-line if it has any of the following features: + // * whitespace prefix + // * embedded newlines + // * whitespace suffix + + // empty string + if (!*a_pData) { + return false; + } + + // check for prefix + if (IsSpace(*a_pData)) { + return true; + } + + // embedded newlines + while (*a_pData) { + if (IsNewLineChar(*a_pData)) { + return true; + } + ++a_pData; + } + + // check for suffix + if (IsSpace(*--a_pData)) { + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsNewLineChar( + SI_CHAR a_c + ) const +{ + return (a_c == '\n' || a_c == '\r'); +} + +template +bool +CSimpleIniTempl::LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment + ) const +{ + // we modify this data to strip all newlines down to a single '\n' + // character. This means that on Windows we need to strip out some + // characters which will make the data shorter. + // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become + // LINE1-LINE1\nLINE2-LINE2\0 + // The pDataLine entry is the pointer to the location in memory that + // the current line needs to start to run following the existing one. + // This may be the same as pCurrLine in which case no move is needed. + SI_CHAR * pDataLine = a_pData; + SI_CHAR * pCurrLine; + + // value starts at the current line + a_pVal = a_pData; + + // find the end tag. This tag must start in column 1 and be + // followed by a newline. We ignore any whitespace after the end + // tag but not whitespace before it. + SI_CHAR cEndOfLineChar = *a_pData; + for(;;) { + // if we are loading comments then we need a comment character as + // the first character on every line + if (!a_pTagName && !IsComment(*a_pData)) { + // if we aren't allowing blank lines then we're done + if (!a_bAllowBlankLinesInComment) { + break; + } + + // if we are allowing blank lines then we only include them + // in this comment if another comment follows, so read ahead + // to find out. + SI_CHAR * pCurr = a_pData; + int nNewLines = 0; + while (IsSpace(*pCurr)) { + if (IsNewLineChar(*pCurr)) { + ++nNewLines; + SkipNewLine(pCurr); + } + else { + ++pCurr; + } + } + + // we have a comment, add the blank lines to the output + // and continue processing from here + if (IsComment(*pCurr)) { + for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; + a_pData = pCurr; + continue; + } + + // the comment ends here + break; + } + + // find the end of this line + pCurrLine = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; + + // move this line down to the location that it should be if necessary + if (pDataLine < pCurrLine) { + size_t nLen = (size_t) (a_pData - pCurrLine); + memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); + pDataLine[nLen] = '\0'; + } + + // end the line with a NULL + cEndOfLineChar = *a_pData; + *a_pData = 0; + + // if are looking for a tag then do the check now. This is done before + // checking for end of the data, so that if we have the tag at the end + // of the data then the tag is removed correctly. + if (a_pTagName) { + // strip whitespace from the end of this tag + SI_CHAR* pc = a_pData - 1; + while (pc > pDataLine && IsSpace(*pc)) --pc; + SI_CHAR ch = *++pc; + *pc = 0; + + if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) { + break; + } + + *pc = ch; + } + + // if we are at the end of the data then we just automatically end + // this entry and return the current data. + if (!cEndOfLineChar) { + return true; + } + + // otherwise we need to process this newline to ensure that it consists + // of just a single \n character. + pDataLine += (a_pData - pCurrLine); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + *pDataLine++ = '\n'; + } + + // if we didn't find a comment at all then return false + if (a_pVal == a_pData) { + a_pVal = NULL; + return false; + } + + // the data (which ends at the end of the last line) needs to be + // null-terminated BEFORE before the newline character(s). If the + // user wants a new line in the multi-line data then they need to + // add an empty line before the tag. + *--pDataLine = '\0'; + + // if looking for a tag and if we aren't at the end of the data, + // then move a_pData to the start of the next line. + if (a_pTagName && cEndOfLineChar) { + SI_ASSERT(IsNewLineChar(cEndOfLineChar)); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::CopyString( + const SI_CHAR *& a_pString + ) +{ + size_t uLen = 0; + if (sizeof(SI_CHAR) == sizeof(char)) { + uLen = strlen((const char *)a_pString); + } + else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + uLen = wcslen((const wchar_t *)a_pString); + } + else { + for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; + } + ++uLen; // NULL character + SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen]; + if (!pCopy) { + return SI_NOMEM; + } + memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); + m_strings.push_back(pCopy); + a_pString = pCopy; + return SI_OK; +} + +template +SI_Error +CSimpleIniTempl::AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ) +{ + SI_Error rc; + bool bInserted = false; + + SI_ASSERT(!a_pComment || IsComment(*a_pComment)); + + // if we are copying strings then make a copy of the comment now + // because we will need it when we add the entry. + if (a_bCopyStrings && a_pComment) { + rc = CopyString(a_pComment); + if (rc < 0) return rc; + } + + // create the section entry if necessary + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + // if the section doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + if (a_bCopyStrings) { + rc = CopyString(a_pSection); + if (rc < 0) return rc; + } + + // only set the comment if this is a section only entry + Entry oSection(a_pSection, ++m_nOrder); + if (a_pComment && (!a_pKey || !a_pValue)) { + oSection.pComment = a_pComment; + } + + typename TSection::value_type oEntry(oSection, TKeyVal()); + typedef typename TSection::iterator SectionIterator; + std::pair i = m_data.insert(oEntry); + iSection = i.first; + bInserted = true; + } + if (!a_pKey || !a_pValue) { + // section only entries are specified with pItem and pVal as NULL + return bInserted ? SI_INSERTED : SI_UPDATED; + } + + // check for existence of the key + TKeyVal & keyval = iSection->second; + typename TKeyVal::iterator iKey = keyval.find(a_pKey); + bInserted = iKey == keyval.end(); + + // remove all existing entries but save the load order and + // comment of the first entry + int nLoadOrder = ++m_nOrder; + if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { + const SI_CHAR * pComment = NULL; + while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { + if (iKey->first.nOrder < nLoadOrder) { + nLoadOrder = iKey->first.nOrder; + pComment = iKey->first.pComment; + } + ++iKey; + } + if (pComment) { + DeleteString(a_pComment); + a_pComment = pComment; + CopyString(a_pComment); + } + Delete(a_pSection, a_pKey); + iKey = keyval.end(); + } + + // make string copies if necessary + bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; + if (a_bCopyStrings) { + if (bForceCreateNewKey || iKey == keyval.end()) { + // if the key doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + // because we will be inserting the key next + rc = CopyString(a_pKey); + if (rc < 0) return rc; + } + + // we always need a copy of the value + rc = CopyString(a_pValue); + if (rc < 0) return rc; + } + + // create the key entry + if (iKey == keyval.end() || bForceCreateNewKey) { + Entry oKey(a_pKey, nLoadOrder); + if (a_pComment) { + oKey.pComment = a_pComment; + } + typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); + iKey = keyval.insert(oEntry); + } + + iKey->second = a_pValue; + return bInserted ? SI_INSERTED : SI_UPDATED; +} + +template +const SI_CHAR * +CSimpleIniTempl::GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault, + bool * a_pHasMultiple + ) const +{ + if (a_pHasMultiple) { + *a_pHasMultiple = false; + } + if (!a_pSection || !a_pKey) { + return a_pDefault; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return a_pDefault; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return a_pDefault; + } + + // check for multiple entries with the same key + if (m_bAllowMultiKey && a_pHasMultiple) { + typename TKeyVal::const_iterator iTemp = iKeyVal; + if (++iTemp != iSection->second.end()) { + if (!IsLess(a_pKey, iTemp->first.pItem)) { + *a_pHasMultiple = true; + } + } + } + + return iKeyVal->second; +} + +template +long +CSimpleIniTempl::GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + // handle the value as hex if prefaced with "0x" + long nValue = a_nDefault; + char * pszSuffix = szValue; + if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { + if (!szValue[2]) return a_nDefault; + nValue = strtol(&szValue[2], &pszSuffix, 16); + } + else { + nValue = strtol(szValue, &pszSuffix, 10); + } + + // any invalid strings will return the default value + if (*pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment, + bool a_bUseHex, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +double +CSimpleIniTempl::GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + char * pszSuffix = NULL; + double nValue = strtod(szValue, &pszSuffix); + + // any invalid strings will return the default value + if (!pszSuffix || *pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, "%f", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, "%f", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_bDefault; + + // we only look at the minimum number of characters + switch (pszValue[0]) { + case 't': case 'T': // true + case 'y': case 'Y': // yes + case '1': // 1 (one) + return true; + + case 'f': case 'F': // false + case 'n': case 'N': // no + case '0': // 0 (zero) + return false; + + case 'o': case 'O': + if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on + if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off + break; + } + + // no recognized value, return the default + return a_bDefault; +} + +template +SI_Error +CSimpleIniTempl::SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + const char * pszInput = a_bValue ? "true" : "false"; + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const +{ + a_values.clear(); + + if (!a_pSection || !a_pKey) { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + // insert all values for this key + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + if (m_bAllowMultiKey) { + ++iKeyVal; + while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + ++iKeyVal; + } + } + + return true; +} + +template +int +CSimpleIniTempl::GetSectionSize( + const SI_CHAR * a_pSection + ) const +{ + if (!a_pSection) { + return -1; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return -1; + } + const TKeyVal & section = iSection->second; + + // if multi-key isn't permitted then the section size is + // the number of keys that we have. + if (!m_bAllowMultiKey || section.empty()) { + return (int) section.size(); + } + + // otherwise we need to count them + int nCount = 0; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + ++nCount; + pLastKey = iKeyVal->first.pItem; + } + } + return nCount; +} + +template +const typename CSimpleIniTempl::TKeyVal * +CSimpleIniTempl::GetSection( + const SI_CHAR * a_pSection + ) const +{ + if (a_pSection) { + typename TSection::const_iterator i = m_data.find(a_pSection); + if (i != m_data.end()) { + return &(i->second); + } + } + return 0; +} + +template +void +CSimpleIniTempl::GetAllSections( + TNamesDepend & a_names + ) const +{ + a_names.clear(); + typename TSection::const_iterator i = m_data.begin(); + for (int n = 0; i != m_data.end(); ++i, ++n ) { + a_names.push_back(i->first); + } +} + +template +bool +CSimpleIniTempl::GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const +{ + a_names.clear(); + + if (!a_pSection) { + return false; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + const TKeyVal & section = iSection->second; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + a_names.push_back(iKeyVal->first); + pLastKey = iKeyVal->first.pItem; + } + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::SaveFile( + const char * a_pszFile, + bool a_bAddSignature + ) const +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::SaveFile( + const SI_WCHAR_T * a_pwszFile, + bool a_bAddSignature + ) const +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return SaveFile(szFile, a_bAddSignature); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::SaveFile( + FILE * a_pFile, + bool a_bAddSignature + ) const +{ + FileWriter writer(a_pFile); + return Save(writer, a_bAddSignature); +} + +template +SI_Error +CSimpleIniTempl::Save( + OutputWriter & a_oOutput, + bool a_bAddSignature + ) const +{ + Converter convert(m_bStoreIsUtf8); + + // add the UTF-8 signature if it is desired + if (m_bStoreIsUtf8 && a_bAddSignature) { + a_oOutput.Write(SI_UTF8_SIGNATURE); + } + + // get all of the sections sorted in load order + TNamesDepend oSections; + GetAllSections(oSections); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oSections.sort(); +#elif defined(__BORLANDC__) + oSections.sort(Entry::LoadOrder()); +#else + oSections.sort(typename Entry::LoadOrder()); +#endif + + // if there is an empty section name, then it must be written out first + // regardless of the load order + typename TNamesDepend::iterator is = oSections.begin(); + for (; is != oSections.end(); ++is) { + if (!*is->pItem) { + // move the empty section name to the front of the section list + if (is != oSections.begin()) { + oSections.splice(oSections.begin(), oSections, is, std::next(is)); + } + break; + } + } + + // write the file comment if we have one + bool bNeedNewLine = false; + if (m_pFileComment) { + if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { + return SI_FAIL; + } + bNeedNewLine = true; + } + + // iterate through our sections and output the data + typename TNamesDepend::const_iterator iSection = oSections.begin(); + for ( ; iSection != oSections.end(); ++iSection ) { + // write out the comment if there is one + if (iSection->pComment) { + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + } + if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { + return SI_FAIL; + } + bNeedNewLine = false; + } + + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + bNeedNewLine = false; + } + + // write the section (unless there is no section name) + if (*iSection->pItem) { + if (!convert.ConvertToStore(iSection->pItem)) { + return SI_FAIL; + } + a_oOutput.Write("["); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("]"); + a_oOutput.Write(SI_NEWLINE_A); + } + + // get all of the keys sorted in load order + TNamesDepend oKeys; + GetAllKeys(iSection->pItem, oKeys); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oKeys.sort(); +#elif defined(__BORLANDC__) + oKeys.sort(Entry::LoadOrder()); +#else + oKeys.sort(typename Entry::LoadOrder()); +#endif + + // write all keys and values + typename TNamesDepend::const_iterator iKey = oKeys.begin(); + for ( ; iKey != oKeys.end(); ++iKey) { + // get all values for this key + TNamesDepend oValues; + GetAllValues(iSection->pItem, iKey->pItem, oValues); + + typename TNamesDepend::const_iterator iValue = oValues.begin(); + for ( ; iValue != oValues.end(); ++iValue) { + // write out the comment if there is one + if (iValue->pComment) { + a_oOutput.Write(SI_NEWLINE_A); + if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { + return SI_FAIL; + } + } + + // write the key + if (!convert.ConvertToStore(iKey->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(convert.Data()); + + // write the value + if (!convert.ConvertToStore(iValue->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(m_bSpaces ? " = " : "="); + if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { + // multi-line data needs to be processed specially to ensure + // that we use the correct newline format for the current system + a_oOutput.Write("<<pItem)) { + return SI_FAIL; + } + a_oOutput.Write("END_OF_TEXT"); + } + else { + a_oOutput.Write(convert.Data()); + } + a_oOutput.Write(SI_NEWLINE_A); + } + } + + bNeedNewLine = true; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const +{ + const SI_CHAR * pEndOfLine; + SI_CHAR cEndOfLineChar = *a_pText; + while (cEndOfLineChar) { + // find the end of this line + pEndOfLine = a_pText; + for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; + cEndOfLineChar = *pEndOfLine; + + // temporarily null terminate, convert and output the line + *const_cast(pEndOfLine) = 0; + if (!a_oConverter.ConvertToStore(a_pText)) { + return false; + } + *const_cast(pEndOfLine) = cEndOfLineChar; + a_pText += (pEndOfLine - a_pText) + 1; + a_oOutput.Write(a_oConverter.Data()); + a_oOutput.Write(SI_NEWLINE_A); + } + return true; +} + +template +bool +CSimpleIniTempl::Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty + ) +{ + return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty); +} + +template +bool +CSimpleIniTempl::DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty + ) +{ + if (!a_pSection) { + return false; + } + + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + // remove a single key if we have a keyname + if (a_pKey) { + typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + const static SI_STRLESS isLess = SI_STRLESS(); + + // remove any copied strings and then the key + typename TKeyVal::iterator iDelete; + bool bDeleted = false; + do { + iDelete = iKeyVal++; + + if(a_pValue == NULL || + (isLess(a_pValue, iDelete->second) == false && + isLess(iDelete->second, a_pValue) == false)) { + DeleteString(iDelete->first.pItem); + DeleteString(iDelete->second); + iSection->second.erase(iDelete); + bDeleted = true; + } + } + while (iKeyVal != iSection->second.end() + && !IsLess(a_pKey, iKeyVal->first.pItem)); + + if(!bDeleted) { + return false; + } + + // done now if the section is not empty or we are not pruning away + // the empty sections. Otherwise let it fall through into the section + // deletion code + if (!a_bRemoveEmpty || !iSection->second.empty()) { + return true; + } + } + else { + // delete all copied strings from this section. The actual + // entries will be removed when the section is removed. + typename TKeyVal::iterator iKeyVal = iSection->second.begin(); + for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { + DeleteString(iKeyVal->first.pItem); + DeleteString(iKeyVal->second); + } + } + + // delete the section itself + DeleteString(iSection->first.pItem); + m_data.erase(iSection); + + return true; +} + +template +void +CSimpleIniTempl::DeleteString( + const SI_CHAR * a_pString + ) +{ + // strings may exist either inside the data block, or they will be + // individually allocated and stored in m_strings. We only physically + // delete those stored in m_strings. + if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (;i != m_strings.end(); ++i) { + if (a_pString == i->pItem) { + delete[] const_cast(i->pItem); + m_strings.erase(i); + break; + } + } + } +} + +// --------------------------------------------------------------------------- +// CONVERSION FUNCTIONS +// --------------------------------------------------------------------------- + +// Defines the conversion classes for different libraries. Before including +// SimpleIni.h, set the converter that you wish you use by defining one of the +// following symbols. +// +// SI_NO_CONVERSION Do not make the "W" wide character version of the +// library available. Only CSimpleIniA etc is defined. +// SI_CONVERT_GENERIC Use the Unicode reference conversion library in +// the accompanying files ConvertUTF.h/c +// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires +// ICU headers on include path and icuuc.lib +// SI_CONVERT_WIN32 Use the Win32 API functions for conversion. + +#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) +# ifdef _WIN32 +# define SI_CONVERT_WIN32 +# else +# define SI_CONVERT_GENERIC +# endif +#endif + +/** + * Generic case-sensitive less than comparison. This class returns numerically + * ordered ASCII case-sensitive text for all possible sizes and types of + * SI_CHAR. + */ +template +struct SI_GenericCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) *pLeft - (long) *pRight; + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Generic ASCII case-insensitive less than comparison. This class returns + * numerically ordered ASCII case-insensitive text for all possible sizes + * and types of SI_CHAR. It is not safe for MBCS text comparison where + * ASCII A-Z characters are used in the encoding of multi-byte characters. + */ +template +struct SI_GenericNoCase { + inline SI_CHAR locase(SI_CHAR ch) const { + return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); + } + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) locase(*pLeft) - (long) locase(*pRight); + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Null conversion class for MBCS/UTF-8 to char (or equivalent). + */ +template +class SI_ConvertA { + bool m_bStoreIsUtf8; +protected: + SI_ConvertA() { } +public: + SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } + SI_ConvertA & operator=(const SI_ConvertA & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + // ASCII/MBCS/UTF-8 needs no conversion + return a_uInputDataLen; + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + // ASCII/MBCS/UTF-8 needs no conversion + if (a_uInputDataLen > a_uOutputDataSize) { + return false; + } + memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + // ASCII/MBCS/UTF-8 needs no conversion + return strlen((const char *)a_pInputData) + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = strlen((const char *)a_pInputData) + 1; + if (uInputLen > a_uOutputDataSize) { + return false; + } + + // ascii/UTF-8 needs no conversion + memcpy(a_pOutputData, a_pInputData, uInputLen); + return true; + } +}; + + +// --------------------------------------------------------------------------- +// SI_CONVERT_GENERIC +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_GENERIC + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include +#include "ConvertUTF.h" + +/** + * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference + * library functions. This can be used on all platforms. + */ +template +class SI_ConvertW { + bool m_bStoreIsUtf8; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + if (m_bStoreIsUtf8) { + // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t + // so we just return the same number of characters required as for + // the source text. + return a_uInputDataLen; + } + +#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) + // fall back processing for platforms that don't support a NULL dest to mbstowcs + // worst case scenario is 1:1, this will be a sufficient buffer size + (void)a_pInputData; + return a_uInputDataLen; +#else + // get the actual required buffer size + return mbstowcs(NULL, a_pInputData, a_uInputDataLen); +#endif + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + if (m_bStoreIsUtf8) { + // This uses the Unicode reference implementation to do the + // conversion from UTF-8 to wchar_t. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + UTF32 * pUtf32 = (UTF32 *) a_pOutputData; + retval = ConvertUTF8toUTF32( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf32, pUtf32 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + UTF16 * pUtf16 = (UTF16 *) a_pOutputData; + retval = ConvertUTF8toUTF16( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf16, pUtf16 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + + // convert to wchar_t + size_t retval = mbstowcs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t)(-1); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + if (m_bStoreIsUtf8) { + // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char + size_t uLen = 0; + while (a_pInputData[uLen]) { + ++uLen; + } + return (6 * uLen) + 1; + } + else { + size_t uLen = wcstombs(NULL, a_pInputData, 0); + if (uLen == (size_t)(-1)) { + return uLen; + } + return uLen + 1; // include NULL terminator + } + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize + ) + { + if (m_bStoreIsUtf8) { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = 0; + while (a_pInputData[uInputLen]) { + ++uInputLen; + } + ++uInputLen; // include the NULL char + + // This uses the Unicode reference implementation to do the + // conversion from wchar_t to UTF-8. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + UTF8 * pUtf8 = (UTF8 *) a_pOutputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; + retval = ConvertUTF32toUTF8( + &pUtf32, pUtf32 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; + retval = ConvertUTF16toUTF8( + &pUtf16, pUtf16 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + else { + size_t retval = wcstombs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t) -1; + } + } +}; + +#endif // SI_CONVERT_GENERIC + + +// --------------------------------------------------------------------------- +// SI_CONVERT_ICU +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_ICU + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include + +/** + * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. + */ +template +class SI_ConvertW { + const char * m_pEncoding; + UConverter * m_pConverter; +protected: + SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { + m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_pEncoding = rhs.m_pEncoding; + m_pConverter = NULL; + return *this; + } + ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } + + /** Calculate the number of UChar required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of UChar required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen; + } + + /** Convert the input string from the storage format to UChar. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in UChar. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + UChar * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_toUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const UChar * a_pInputData) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, + a_pInputData, -1, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const UChar * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_fromUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, -1, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } +}; + +#endif // SI_CONVERT_ICU + + +// --------------------------------------------------------------------------- +// SI_CONVERT_WIN32 +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_WIN32 + +#define SI_Case SI_GenericCase + +// Windows CE doesn't have errno or MBCS libraries +#ifdef _WIN32_WCE +# ifndef SI_NO_MBCS +# define SI_NO_MBCS +# endif +#endif + +#include +#ifdef SI_NO_MBCS +# define SI_NoCase SI_GenericNoCase +#else // !SI_NO_MBCS +/** + * Case-insensitive comparison class using Win32 MBCS functions. This class + * returns a case-insensitive semi-collation order for MBCS text. It may not + * be safe for UTF-8 text returned in char format as we don't know what + * characters will be folded by the function! Therefore, if you are using + * SI_CHAR == char and SetUnicode(true), then you need to use the generic + * SI_NoCase class instead. + */ +#include +template +struct SI_NoCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + if (sizeof(SI_CHAR) == sizeof(char)) { + return _mbsicmp((const unsigned char *)pLeft, + (const unsigned char *)pRight) < 0; + } + if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + return _wcsicmp((const wchar_t *)pLeft, + (const wchar_t *)pRight) < 0; + } + return SI_GenericNoCase()(pLeft, pRight); + } +}; +#endif // SI_NO_MBCS + +/** + * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses + * only the Win32 functions and doesn't require the external Unicode UTF-8 + * conversion library. It will not work on Windows 95 without using Microsoft + * Layer for Unicode in your application. + */ +template +class SI_ConvertW { + UINT m_uCodePage; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) { + m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_uCodePage = rhs.m_uCodePage; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + int retval = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + 0, 0); + return (size_t)(retval > 0 ? retval : -1); + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + int nSize = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); + return (nSize > 0); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + 0, 0, 0, 0); + return (size_t) (retval > 0 ? retval : -1); + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + a_pOutputData, (int) a_uOutputDataSize, 0, 0); + return retval > 0; + } +}; + +#endif // SI_CONVERT_WIN32 + + + +// --------------------------------------------------------------------------- +// SI_NO_CONVERSION +// --------------------------------------------------------------------------- +#ifdef SI_NO_CONVERSION + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#endif // SI_NO_CONVERSION + + + +// --------------------------------------------------------------------------- +// TYPE DEFINITIONS +// --------------------------------------------------------------------------- + +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; + +#if defined(SI_NO_CONVERSION) +// if there is no wide char conversion then we don't need to define the +// widechar "W" versions of CSimpleIni +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +#else +# if defined(SI_CONVERT_ICU) +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# else +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# endif + +# ifdef _UNICODE +# define CSimpleIni CSimpleIniW +# define CSimpleIniCase CSimpleIniCaseW +# define SI_NEWLINE SI_NEWLINE_W +# else // !_UNICODE +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +# endif // _UNICODE +#endif + +#ifdef _MSC_VER +# pragma warning (pop) +#endif + +#endif // INCLUDED_SimpleIni_h + diff --git a/cheat-library/vendor/libraries/HookLib/HookLib-x64-Debug.lib b/cheat-library/vendor/libraries/HookLib/HookLib-x64-Debug.lib new file mode 100644 index 0000000..a605ffa Binary files /dev/null and b/cheat-library/vendor/libraries/HookLib/HookLib-x64-Debug.lib differ diff --git a/cheat-library/vendor/libraries/HookLib/HookLib-x64-Release.lib b/cheat-library/vendor/libraries/HookLib/HookLib-x64-Release.lib new file mode 100644 index 0000000..b48c178 Binary files /dev/null and b/cheat-library/vendor/libraries/HookLib/HookLib-x64-Release.lib differ diff --git a/cheat-library/vendor/libraries/HookLib/HookLib-x86-Debug.lib b/cheat-library/vendor/libraries/HookLib/HookLib-x86-Debug.lib new file mode 100644 index 0000000..99450f9 Binary files /dev/null and b/cheat-library/vendor/libraries/HookLib/HookLib-x86-Debug.lib differ diff --git a/cheat-library/vendor/libraries/HookLib/HookLib-x86-Release.lib b/cheat-library/vendor/libraries/HookLib/HookLib-x86-Release.lib new file mode 100644 index 0000000..edda3e9 Binary files /dev/null and b/cheat-library/vendor/libraries/HookLib/HookLib-x86-Release.lib differ diff --git a/genshincheat.sln b/genshincheat.sln new file mode 100644 index 0000000..bbbd315 --- /dev/null +++ b/genshincheat.sln @@ -0,0 +1,141 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "injector", "injector\injector.vcxproj", "{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cheat-library", "cheat-library\cheat-library.vcxproj", "{704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Kernel|x64 = Debug Kernel|x64 + Debug Kernel|x86 = Debug Kernel|x86 + Debug MD DLL|x64 = Debug MD DLL|x64 + Debug MD DLL|x86 = Debug MD DLL|x86 + Debug MD|x64 = Debug MD|x64 + Debug MD|x86 = Debug MD|x86 + Debug MT DLL|x64 = Debug MT DLL|x64 + Debug MT DLL|x86 = Debug MT DLL|x86 + Debug MT|x64 = Debug MT|x64 + Debug MT|x86 = Debug MT|x86 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release Kernel|x64 = Release Kernel|x64 + Release Kernel|x86 = Release Kernel|x86 + Release MD DLL|x64 = Release MD DLL|x64 + Release MD DLL|x86 = Release MD DLL|x86 + Release MD|x64 = Release MD|x64 + Release MD|x86 = Release MD|x86 + Release MT DLL|x64 = Release MT DLL|x64 + Release MT DLL|x86 = Release MT DLL|x86 + Release MT|x64 = Release MT|x64 + Release MT|x86 = Release MT|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug Kernel|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug Kernel|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug Kernel|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug Kernel|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD DLL|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD DLL|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD DLL|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD DLL|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MD|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT DLL|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT DLL|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT DLL|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT DLL|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug MT|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x64.ActiveCfg = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x64.Build.0 = Debug|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x86.ActiveCfg = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x86.Build.0 = Debug|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release Kernel|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release Kernel|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release Kernel|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release Kernel|x86.Build.0 = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD DLL|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD DLL|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD DLL|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD DLL|x86.Build.0 = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MD|x86.Build.0 = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT DLL|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT DLL|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT DLL|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT DLL|x86.Build.0 = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release MT|x86.Build.0 = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x64.ActiveCfg = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x64.Build.0 = Release|x64 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x86.ActiveCfg = Release|Win32 + {F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug Kernel|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug Kernel|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug Kernel|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug Kernel|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD DLL|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD DLL|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD DLL|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD DLL|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MD|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT DLL|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT DLL|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT DLL|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT DLL|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug MT|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug|x64.ActiveCfg = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug|x64.Build.0 = Debug|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug|x86.ActiveCfg = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Debug|x86.Build.0 = Debug|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release Kernel|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release Kernel|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release Kernel|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release Kernel|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD DLL|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD DLL|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD DLL|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD DLL|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MD|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT DLL|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT DLL|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT DLL|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT DLL|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release MT|x86.Build.0 = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release|x64.ActiveCfg = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release|x64.Build.0 = Release|x64 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release|x86.ActiveCfg = Release|Win32 + {704C8746-1BD9-4BC8-9EBE-8187F1A1AD72}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0F485A89-A340-4742-97E7-923E14A929A1} + EndGlobalSection +EndGlobal diff --git a/injector/include/simple-ini.hpp b/injector/include/simple-ini.hpp new file mode 100644 index 0000000..54de89d --- /dev/null +++ b/injector/include/simple-ini.hpp @@ -0,0 +1,3487 @@ +/** @mainpage + + +
Library SimpleIni +
File SimpleIni.h +
Author Brodie Thiesfield [brofield at gmail dot com] +
Source https://github.com/brofield/simpleini +
Version 4.17 +
+ + Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation. + + @section intro INTRODUCTION + + This component allows an INI-style configuration file to be used on both + Windows and Linux/Unix. It is fast, simple and source code using this + component will compile unchanged on either OS. + + + @section features FEATURES + + - MIT Licence allows free use in all software (including GPL and commercial) + - multi-platform (Windows CE/9x/NT..10/etc, Linux, MacOSX, Unix) + - loading and saving of INI-style configuration files + - configuration files can have any newline format on all platforms + - liberal acceptance of file format + - key/values with no section + - removal of whitespace around sections, keys and values + - support for multi-line values (values with embedded newline characters) + - optional support for multiple keys with the same name + - optional case-insensitive sections and keys (for ASCII characters only) + - saves files with sections and keys in the same order as they were loaded + - preserves comments on the file, section and keys where possible. + - supports both char or wchar_t programming interfaces + - supports both MBCS (system locale) and UTF-8 file encodings + - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file + - support for non-ASCII characters in section, keys, values and comments + - support for non-standard character types or file encodings + via user-written converter classes + - support for adding/modifying values programmatically + - compiles cleanly in the following compilers: + - Windows/VC6 (warning level 3) + - Windows/VC.NET 2003 (warning level 4) + - Windows/VC 2005 (warning level 4) + - Linux/gcc (-Wall) + + + @section usage USAGE SUMMARY + + -# Define the appropriate symbol for the converter you wish to use and + include the SimpleIni.h header file. If no specific converter is defined + then the default converter is used. The default conversion mode uses + SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other + platforms. If you are using ICU then SI_CONVERT_ICU is supported on all + platforms. + -# Declare an instance the appropriate class. Note that the following + definitions are just shortcuts for commonly used types. Other types + (PRUnichar, unsigned short, unsigned char) are also possible. + +
Interface Case-sensitive Load UTF-8 Load MBCS Typedef +
SI_CONVERT_GENERIC +
char No Yes Yes #1 CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_WIN32 +
char No No #2 Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_ICU +
char No Yes Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
UChar No Yes Yes CSimpleIniW +
UChar Yes Yes Yes CSimpleIniCaseW +
+ #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.
+ #2 Only affects Windows. On Windows this uses MBCS functions and + so may fold case incorrectly leading to uncertain results. + -# Call LoadData() or LoadFile() to load and parse the INI configuration file + -# Access and modify the data of the file using the following functions + +
GetAllSections Return all section names +
GetAllKeys Return all key names within a section +
GetAllValues Return all values within a section & key +
GetSection Return all key names and values in a section +
GetSectionSize Return the number of keys in a section +
GetValue Return a value for a section & key +
SetValue Add or update a value for a section & key +
Delete Remove a section, or a key from a section +
+ -# Call Save() or SaveFile() to save the INI configuration data + + @section iostreams IO STREAMS + + SimpleIni supports reading from and writing to STL IO streams. Enable this + by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header + file. Ensure that if the streams are backed by a file (e.g. ifstream or + ofstream) then the flag ios_base::binary has been used when the file was + opened. + + @section multiline MULTI-LINE VALUES + + Values that span multiple lines are created using the following format. + +
+        key = <<
+
+    Note the following:
+    - The text used for ENDTAG can be anything and is used to find
+      where the multi-line text ends.
+    - The newline after ENDTAG in the start tag, and the newline
+      before ENDTAG in the end tag is not included in the data value.
+    - The ending tag must be on it's own line with no whitespace before
+      or after it.
+    - The multi-line value is modified at load so that each line in the value
+      is delimited by a single '\\n' character on all platforms. At save time
+      it will be converted into the newline format used by the current
+      platform.
+
+    @section comments COMMENTS
+
+    Comments are preserved in the file within the following restrictions:
+    - Every file may have a single "file comment". It must start with the
+      first character in the file, and will end with the first non-comment
+      line in the file.
+    - Every section may have a single "section comment". It will start
+      with the first comment line following the file comment, or the last
+      data entry. It ends at the beginning of the section.
+    - Every key may have a single "key comment". This comment will start
+      with the first comment line following the section start, or the file
+      comment if there is no section name.
+    - Comments are set at the time that the file, section or key is first
+      created. The only way to modify a comment on a section or a key is to
+      delete that entry and recreate it with the new comment. There is no
+      way to change the file comment.
+
+    @section save SAVE ORDER
+
+    The sections and keys are written out in the same order as they were
+    read in from the file. Sections and keys added to the data after the
+    file has been loaded will be added to the end of the file when it is
+    written. There is no way to specify the location of a section or key
+    other than in first-created, first-saved order.
+
+    @section notes NOTES
+
+    - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
+      Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
+    - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
+    - When using SI_CONVERT_ICU, ICU header files must be on the include
+      path and icuuc.lib must be linked in.
+    - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
+      you should use SI_CONVERT_GENERIC.
+    - The collation (sorting) order used for sections and keys returned from
+      iterators is NOT DEFINED. If collation order of the text is important
+      then it should be done yourself by either supplying a replacement
+      SI_STRLESS class, or by sorting the strings external to this library.
+    - Usage of the  header on Windows can be disabled by defining
+      SI_NO_MBCS. This is defined automatically on Windows CE platforms.
+    - Not thread-safe so manage your own locking
+
+    @section contrib CONTRIBUTIONS
+    
+    - 2010/05/03: Tobias Gehrig: added GetDoubleValue()
+
+    @section licence MIT LICENCE
+
+    The licence text below is the boilerplate "MIT Licence" used from:
+    http://www.opensource.org/licenses/mit-license.php
+
+    Copyright (c) 2006-2012, Brodie Thiesfield
+
+    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.
+*/
+
+#ifndef INCLUDED_SimpleIni_h
+#define INCLUDED_SimpleIni_h
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Disable these warnings in MSVC:
+//  4127 "conditional expression is constant" as the conversion classes trigger
+//  it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
+//  be optimized away in a release build.
+//  4503 'insert' : decorated name length exceeded, name was truncated
+//  4702 "unreachable code" as the MS STL header causes it in release mode.
+//  Again, the code causing the warning will be cleaned up by the compiler.
+//  4786 "identifier truncated to 256 characters" as this is thrown hundreds
+//  of times VC6 as soon as STL is used.
+#ifdef _MSC_VER
+# pragma warning (push)
+# pragma warning (disable: 4127 4503 4702 4786)
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef SI_SUPPORT_IOSTREAMS
+# include 
+#endif // SI_SUPPORT_IOSTREAMS
+
+#ifdef _DEBUG
+# ifndef assert
+#  include 
+# endif
+# define SI_ASSERT(x)   assert(x)
+#else
+# define SI_ASSERT(x)
+#endif
+
+enum SI_Error {
+    SI_OK       =  0,   //!< No error
+    SI_UPDATED  =  1,   //!< An existing value was updated
+    SI_INSERTED =  2,   //!< A new value was inserted
+
+    // note: test for any error with (retval < 0)
+    SI_FAIL     = -1,   //!< Generic failure
+    SI_NOMEM    = -2,   //!< Out of memory error
+    SI_FILE     = -3    //!< File error (see errno for detail error)
+};
+
+#define SI_UTF8_SIGNATURE     "\xEF\xBB\xBF"
+
+#ifdef _WIN32
+# define SI_NEWLINE_A   "\r\n"
+# define SI_NEWLINE_W   L"\r\n"
+#else // !_WIN32
+# define SI_NEWLINE_A   "\n"
+# define SI_NEWLINE_W   L"\n"
+#endif // _WIN32
+
+#if defined(SI_CONVERT_ICU)
+# include 
+#endif
+
+#if defined(_WIN32)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     wchar_t
+#elif defined(SI_CONVERT_ICU)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     UChar
+#endif
+
+
+// ---------------------------------------------------------------------------
+//                              MAIN TEMPLATE CLASS
+// ---------------------------------------------------------------------------
+
+/** Simple INI file reader.
+
+    This can be instantiated with the choice of unicode or native characterset,
+    and case sensitive or insensitive comparisons of section and key names.
+    The supported combinations are pre-defined with the following typedefs:
+
+    
+        
Interface Case-sensitive Typedef +
char No CSimpleIniA +
char Yes CSimpleIniCaseA +
wchar_t No CSimpleIniW +
wchar_t Yes CSimpleIniCaseW +
+ + Note that using other types for the SI_CHAR is supported. For instance, + unsigned char, unsigned short, etc. Note that where the alternative type + is a different size to char/wchar_t you may need to supply new helper + classes for SI_STRLESS and SI_CONVERTER. + */ +template +class CSimpleIniTempl +{ +public: + typedef SI_CHAR SI_CHAR_T; + + /** key entry */ + struct Entry { + const SI_CHAR * pItem; + const SI_CHAR * pComment; + int nOrder; + + Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) + : pItem(a_pszItem) + , pComment(NULL) + , nOrder(a_nOrder) + { } + Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) + : pItem(a_pszItem) + , pComment(a_pszComment) + , nOrder(a_nOrder) + { } + Entry(const Entry & rhs) { operator=(rhs); } + Entry & operator=(const Entry & rhs) { + pItem = rhs.pItem; + pComment = rhs.pComment; + nOrder = rhs.nOrder; + return *this; + } + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } + bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } +#endif + + /** Strict less ordering by name of key only */ + struct KeyOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(lhs.pItem, rhs.pItem); + } + }; + + /** Strict less ordering by order, and then name of key */ + struct LoadOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + if (lhs.nOrder != rhs.nOrder) { + return lhs.nOrder < rhs.nOrder; + } + return KeyOrder()(lhs.pItem, rhs.pItem); + } + }; + }; + + /** map keys to values */ + typedef std::multimap TKeyVal; + + /** map sections to key/value map */ + typedef std::map TSection; + + /** set of dependent string pointers. Note that these pointers are + dependent on memory owned by CSimpleIni. + */ + typedef std::list TNamesDepend; + + /** interface definition for the OutputWriter object to pass to Save() + in order to output the INI file data. + */ + class OutputWriter { + public: + OutputWriter() { } + virtual ~OutputWriter() { } + virtual void Write(const char * a_pBuf) = 0; + private: + OutputWriter(const OutputWriter &); // disable + OutputWriter & operator=(const OutputWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a file */ + class FileWriter : public OutputWriter { + FILE * m_file; + public: + FileWriter(FILE * a_file) : m_file(a_file) { } + void Write(const char * a_pBuf) { + fputs(a_pBuf, m_file); + } + private: + FileWriter(const FileWriter &); // disable + FileWriter & operator=(const FileWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a string */ + class StringWriter : public OutputWriter { + std::string & m_string; + public: + StringWriter(std::string & a_string) : m_string(a_string) { } + void Write(const char * a_pBuf) { + m_string.append(a_pBuf); + } + private: + StringWriter(const StringWriter &); // disable + StringWriter & operator=(const StringWriter &); // disable + }; + +#ifdef SI_SUPPORT_IOSTREAMS + /** OutputWriter class to write the INI data to an ostream */ + class StreamWriter : public OutputWriter { + std::ostream & m_ostream; + public: + StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } + void Write(const char * a_pBuf) { + m_ostream << a_pBuf; + } + private: + StreamWriter(const StreamWriter &); // disable + StreamWriter & operator=(const StreamWriter &); // disable + }; +#endif // SI_SUPPORT_IOSTREAMS + + /** Characterset conversion utility class to convert strings to the + same format as is used for the storage. + */ + class Converter : private SI_CONVERTER { + public: + Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { + m_scratch.resize(1024); + } + Converter(const Converter & rhs) { operator=(rhs); } + Converter & operator=(const Converter & rhs) { + m_scratch = rhs.m_scratch; + return *this; + } + bool ConvertToStore(const SI_CHAR * a_pszString) { + size_t uLen = SI_CONVERTER::SizeToStore(a_pszString); + if (uLen == (size_t)(-1)) { + return false; + } + while (uLen > m_scratch.size()) { + m_scratch.resize(m_scratch.size() * 2); + } + return SI_CONVERTER::ConvertToStore( + a_pszString, + const_cast(m_scratch.data()), + m_scratch.size()); + } + const char * Data() { return m_scratch.data(); } + private: + std::string m_scratch; + }; + +public: + /*-----------------------------------------------------------------------*/ + + /** Default constructor. + + @param a_bIsUtf8 See the method SetUnicode() for details. + @param a_bMultiKey See the method SetMultiKey() for details. + @param a_bMultiLine See the method SetMultiLine() for details. + */ + CSimpleIniTempl( + bool a_bIsUtf8 = false, + bool a_bMultiKey = false, + bool a_bMultiLine = false + ); + + /** Destructor */ + ~CSimpleIniTempl(); + + /** Deallocate all memory stored by this object */ + void Reset(); + + /** Has any data been loaded */ + bool IsEmpty() const { return m_data.empty(); } + + /*-----------------------------------------------------------------------*/ + /** @{ @name Settings */ + + /** Set the storage format of the INI data. This affects both the loading + and saving of the INI data using all of the Load/Save API functions. + This value cannot be changed after any INI data has been loaded. + + If the file is not set to Unicode (UTF-8), then the data encoding is + assumed to be the OS native encoding. This encoding is the system + locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP. + If the storage format is set to Unicode then the file will be loaded + as UTF-8 encoded data regardless of the native file encoding. If + SI_CHAR == char then all of the char* parameters take and return UTF-8 + encoded data regardless of the system locale. + + \param a_bIsUtf8 Assume UTF-8 encoding for the source? + */ + void SetUnicode(bool a_bIsUtf8 = true) { + if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; + } + + /** Get the storage format of the INI data. */ + bool IsUnicode() const { return m_bStoreIsUtf8; } + + /** Should multiple identical keys be permitted in the file. If set to false + then the last value encountered will be used as the value of the key. + If set to true, then all values will be available to be queried. For + example, with the following input: + +
+        [section]
+        test=value1
+        test=value2
+        
+ + Then with SetMultiKey(true), both of the values "value1" and "value2" + will be returned for the key test. If SetMultiKey(false) is used, then + the value for "test" will only be "value2". This value may be changed + at any time. + + \param a_bAllowMultiKey Allow multi-keys in the source? + */ + void SetMultiKey(bool a_bAllowMultiKey = true) { + m_bAllowMultiKey = a_bAllowMultiKey; + } + + /** Get the storage format of the INI data. */ + bool IsMultiKey() const { return m_bAllowMultiKey; } + + /** Should data values be permitted to span multiple lines in the file. If + set to false then the multi-line construct << + SI_CHAR FORMAT + char same format as when loaded (MBCS or UTF-8) + wchar_t UTF-8 + other UTF-8 + + + Note that comments from the original data is preserved as per the + documentation on comments. The order of the sections and values + from the original file will be preserved. + + Any data prepended or appended to the output device must use the the + same format (MBCS or UTF-8). You may use the GetConverter() method to + convert text to the correct format regardless of the output format + being used by SimpleIni. + + To add a BOM to UTF-8 data, write it out manually at the very beginning + like is done in SaveFile when a_bUseBOM is true. + + @param a_oOutput Output writer to write the data to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the OutputWriter. + + @return SI_Error See error definitions + */ + SI_Error Save( + OutputWriter & a_oOutput, + bool a_bAddSignature = false + ) const; + +#ifdef SI_SUPPORT_IOSTREAMS + /** Save the INI data to an ostream. See Save() for details. + + @param a_ostream String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the stream. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::ostream & a_ostream, + bool a_bAddSignature = false + ) const + { + StreamWriter writer(a_ostream); + return Save(writer, a_bAddSignature); + } +#endif // SI_SUPPORT_IOSTREAMS + + /** Append the INI data to a string. See Save() for details. + + @param a_sBuffer String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the string. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::string & a_sBuffer, + bool a_bAddSignature = false + ) const + { + StringWriter writer(a_sBuffer); + return Save(writer, a_bAddSignature); + } + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Accessing INI Data */ + + /** Retrieve all section names. The list is returned as an STL vector of + names and can be iterated or searched as necessary. Note that the + sort order of the returned strings is NOT DEFINED. You can sort + the names into the load order if desired. Search this file for ".sort" + for an example. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these pointers + are in use! + + @param a_names Vector that will receive all of the section + names. See note above! + */ + void GetAllSections( + TNamesDepend & a_names + ) const; + + /** Retrieve all unique key names in a section. The sort order of the + returned strings is NOT DEFINED. You can sort the names into the load + order if desired. Search this file for ".sort" for an example. Only + unique key names are returned. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Section to request data for + @param a_names List that will receive all of the key + names. See note above! + + @return true Section was found. + @return false Matching section was not found. + */ + bool GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const; + + /** Retrieve all values for a specific key. This method can be used when + multiple keys are both enabled and disabled. Note that the sort order + of the returned strings is NOT DEFINED. You can sort the names into + the load order if desired. Search this file for ".sort" for an example. + + NOTE! The returned values are pointers to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_values List to return if the key is not found + + @return true Key was found. + @return false Matching section/key was not found. + */ + bool GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const; + + /** Query the number of keys in a specific section. Note that if multiple + keys are enabled, then this value may be different to the number of + keys returned by GetAllKeys. + + @param a_pSection Section to request data for + + @return -1 Section does not exist in the file + @return >=0 Number of keys in the section + */ + int GetSectionSize( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve all key and value pairs for a section. The data is returned + as a pointer to an STL map and can be iterated or searched as + desired. Note that multiple entries for the same key may exist when + multiple keys have been enabled. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Name of the section to return + @return boolean Was a section matching the supplied + name found. + */ + const TKeyVal * GetSection( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve the value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + NOTE! The returned value is a pointer to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_pDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_pDefault Key was not found in the section + @return other Value of the key + */ + const SI_CHAR * GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault = NULL, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + long GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + double GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a boolean value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + Strings starting with "t", "y", "on" or "1" are returned as logically true. + Strings starting with "f", "n", "of" or "0" are returned as logically false. + For all other values the default is returned. Character comparisons are + case-insensitive. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_bDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + bool GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault = false, + bool * a_pHasMultiple = NULL + ) const; + + /** Add or update a section or value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. Set to NULL to + create an empty section. + @param a_pValue Value to set. Set to NULL to create an + empty section. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. Note that a + comment may be set ONLY when the section or key is + first created (i.e. when this function returns the + value SI_INSERTED). If you wish to create a section + with a comment then you need to create the section + separately to the key. The comment string must be + in full comment form already (have a comment + character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetValue and SetValue + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ) + { + return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); + } + + /** Add or update a numeric value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bUseHex By default the value will be written to the file + in decimal format. Set this to true to write it + as hexadecimal. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetLongValue and + SetLongValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bUseHex = false, + bool a_bForceReplace = false + ); + + /** Add or update a double value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetDoubleValue and + SetDoubleValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Add or update a boolean value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_bValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetBoolValue and + SetBoolValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Delete an entire section, or a key from a section. Note that the + data returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, this will delete all keys with + that name; to selectively delete individual key/values, use + DeleteValue. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key or section was deleted. + @return false Key or section was not found. + */ + bool Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty = false + ); + + /** Delete an entire section, or a key from a section. If value is + provided, only remove keys with the value. Note that the data + returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, all keys with the value will + be deleted. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_pValue Value of key to remove from the section. + Set to NULL to remove all keys. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key/value or section was deleted. + @return false Key/value or section was not found. + */ + bool DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty = false + ); + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Converter */ + + /** Return a conversion object to convert text to the same encoding + as is used by the Save(), SaveFile() and SaveString() functions. + Use this to prepare the strings that you wish to append or prepend + to the output INI data. + */ + Converter GetConverter() const { + return Converter(m_bStoreIsUtf8); + } + + /*-----------------------------------------------------------------------*/ + /** @} */ + +private: + // copying is not permitted + CSimpleIniTempl(const CSimpleIniTempl &); // disabled + CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled + + /** Parse the data looking for a file comment and store it if found. + */ + SI_Error FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ); + + /** Parse the data looking for the next valid entry. The memory pointed to + by a_pData is modified by inserting NULL characters. The pointer is + updated to the current location in the block of text. + */ + bool FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const; + + /** Add the section/key/value to our data. + + @param a_pSection Section name. Sections will be created if they + don't already exist. + @param a_pKey Key name. May be NULL to create an empty section. + Existing entries will be updated. New entries will + be created. + @param a_pValue Value for the key. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. This must be + a string in full comment form already (have a + comment character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/AddEntry and AddEntry + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + @param a_bCopyStrings Should copies of the strings be made or not. + If false then the pointers will be used as is. + */ + SI_Error AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ); + + /** Is the supplied character a whitespace character? */ + inline bool IsSpace(SI_CHAR ch) const { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + } + + /** Does the supplied character start a comment line? */ + inline bool IsComment(SI_CHAR ch) const { + return (ch == ';' || ch == '#'); + } + + + /** Skip over a newline character (or characters) for either DOS or UNIX */ + inline void SkipNewLine(SI_CHAR *& a_pData) const { + a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; + } + + /** Make a copy of the supplied string, replacing the original pointer */ + SI_Error CopyString(const SI_CHAR *& a_pString); + + /** Delete a string from the copied strings buffer if necessary */ + void DeleteString(const SI_CHAR * a_pString); + + /** Internal use of our string comparison function */ + bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(a_pLeft, a_pRight); + } + + bool IsMultiLineTag(const SI_CHAR * a_pData) const; + bool IsMultiLineData(const SI_CHAR * a_pData) const; + bool LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment = false + ) const; + bool IsNewLineChar(SI_CHAR a_c) const; + + bool OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const; + +private: + /** Copy of the INI file data in our character format. This will be + modified when parsed to have NULL characters added after all + interesting string entries. All of the string pointers to sections, + keys and values point into this block of memory. + */ + SI_CHAR * m_pData; + + /** Length of the data that we have stored. Used when deleting strings + to determine if the string is stored here or in the allocated string + buffer. + */ + size_t m_uDataLen; + + /** File comment for this data, if one exists. */ + const SI_CHAR * m_pFileComment; + + /** Parsed INI data. Section -> (Key -> Value). */ + TSection m_data; + + /** This vector stores allocated memory for copies of strings that have + been supplied after the file load. It will be empty unless SetValue() + has been called. + */ + TNamesDepend m_strings; + + /** Is the format of our datafile UTF-8 or MBCS? */ + bool m_bStoreIsUtf8; + + /** Are multiple values permitted for the same key? */ + bool m_bAllowMultiKey; + + /** Are data values permitted to span multiple lines? */ + bool m_bAllowMultiLine; + + /** Should spaces be written out surrounding the equals sign? */ + bool m_bSpaces; + + /** Next order value, used to ensure sections and keys are output in the + same order that they are loaded/added. + */ + int m_nOrder; +}; + +// --------------------------------------------------------------------------- +// IMPLEMENTATION +// --------------------------------------------------------------------------- + +template +CSimpleIniTempl::CSimpleIniTempl( + bool a_bIsUtf8, + bool a_bAllowMultiKey, + bool a_bAllowMultiLine + ) + : m_pData(0) + , m_uDataLen(0) + , m_pFileComment(NULL) + , m_bStoreIsUtf8(a_bIsUtf8) + , m_bAllowMultiKey(a_bAllowMultiKey) + , m_bAllowMultiLine(a_bAllowMultiLine) + , m_bSpaces(true) + , m_nOrder(0) +{ } + +template +CSimpleIniTempl::~CSimpleIniTempl() +{ + Reset(); +} + +template +void +CSimpleIniTempl::Reset() +{ + // remove all data + delete[] m_pData; + m_pData = NULL; + m_uDataLen = 0; + m_pFileComment = NULL; + if (!m_data.empty()) { + m_data.erase(m_data.begin(), m_data.end()); + } + + // remove all strings + if (!m_strings.empty()) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) { + delete[] const_cast(i->pItem); + } + m_strings.erase(m_strings.begin(), m_strings.end()); + } +} + +template +SI_Error +CSimpleIniTempl::LoadFile( + const char * a_pszFile + ) +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) { + return SI_FILE; + } + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::LoadFile( + const SI_WCHAR_T * a_pwszFile + ) +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return LoadFile(szFile); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::LoadFile( + FILE * a_fpFile + ) +{ + // load the raw file data + int retval = fseek(a_fpFile, 0, SEEK_END); + if (retval != 0) { + return SI_FILE; + } + long lSize = ftell(a_fpFile); + if (lSize < 0) { + return SI_FILE; + } + if (lSize == 0) { + return SI_OK; + } + + // allocate and ensure NULL terminated + char * pData = new(std::nothrow) char[lSize+1]; + if (!pData) { + return SI_NOMEM; + } + pData[lSize] = 0; + + // load data into buffer + fseek(a_fpFile, 0, SEEK_SET); + size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); + if (uRead != (size_t) lSize) { + delete[] pData; + return SI_FILE; + } + + // convert the raw data to unicode + SI_Error rc = LoadData(pData, uRead); + delete[] pData; + return rc; +} + +template +SI_Error +CSimpleIniTempl::LoadData( + const char * a_pData, + size_t a_uDataLen + ) +{ + if (!a_pData) { + return SI_OK; + } + + // if the UTF-8 BOM exists, consume it and set mode to unicode, if we have + // already loaded data and try to change mode half-way through then this will + // be ignored and we will assert in debug versions + if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { + a_pData += 3; + a_uDataLen -= 3; + SI_ASSERT(m_bStoreIsUtf8 || !m_pData); // we don't expect mixed mode data + SetUnicode(); + } + + if (a_uDataLen == 0) { + return SI_OK; + } + + // determine the length of the converted data + SI_CONVERTER converter(m_bStoreIsUtf8); + size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); + if (uLen == (size_t)(-1)) { + return SI_FAIL; + } + + // allocate memory for the data, ensure that there is a NULL + // terminator wherever the converted data ends + SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen+1]; + if (!pData) { + return SI_NOMEM; + } + memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); + + // convert the data + if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { + delete[] pData; + return SI_FAIL; + } + + // parse it + const static SI_CHAR empty = 0; + SI_CHAR * pWork = pData; + const SI_CHAR * pSection = ∅ + const SI_CHAR * pItem = NULL; + const SI_CHAR * pVal = NULL; + const SI_CHAR * pComment = NULL; + + // We copy the strings if we are loading data into this class when we + // already have stored some. + bool bCopyStrings = (m_pData != NULL); + + // find a file comment if it exists, this is a comment that starts at the + // beginning of the file and continues until the first blank line. + SI_Error rc = FindFileComment(pWork, bCopyStrings); + if (rc < 0) return rc; + + // add every entry in the file to the data table + while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { + rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); + if (rc < 0) return rc; + } + + // store these strings if we didn't copy them + if (bCopyStrings) { + delete[] pData; + } + else { + m_pData = pData; + m_uDataLen = uLen+1; + } + + return SI_OK; +} + +#ifdef SI_SUPPORT_IOSTREAMS +template +SI_Error +CSimpleIniTempl::LoadData( + std::istream & a_istream + ) +{ + std::string strData; + char szBuf[512]; + do { + a_istream.get(szBuf, sizeof(szBuf), '\0'); + strData.append(szBuf); + } + while (a_istream.good()); + return LoadData(strData); +} +#endif // SI_SUPPORT_IOSTREAMS + +template +SI_Error +CSimpleIniTempl::FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ) +{ + // there can only be a single file comment + if (m_pFileComment) { + return SI_OK; + } + + // Load the file comment as multi-line text, this will modify all of + // the newline characters to be single \n chars + if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { + return SI_OK; + } + + // copy the string if necessary + if (a_bCopyStrings) { + SI_Error rc = CopyString(m_pFileComment); + if (rc < 0) return rc; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const +{ + a_pComment = NULL; + + SI_CHAR * pTrail = NULL; + while (*a_pData) { + // skip spaces and empty lines + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + if (!*a_pData) { + break; + } + + // skip processing of comment lines but keep a pointer to + // the start of the comment. + if (IsComment(*a_pData)) { + LoadMultiLineText(a_pData, a_pComment, NULL, true); + continue; + } + + // process section names + if (*a_pData == '[') { + // skip leading spaces + ++a_pData; + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the section name (it may contain spaces) + // and convert it to lowercase as necessary + a_pSection = a_pData; + while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != ']') { + continue; + } + + // remove trailing spaces from the section + pTrail = a_pData - 1; + while (pTrail >= a_pSection && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip to the end of the line + ++a_pData; // safe as checked that it == ']' above + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + a_pKey = NULL; + a_pVal = NULL; + return true; + } + + // find the end of the key name (it may contain spaces) + // and convert it to lowercase as necessary + a_pKey = a_pData; + while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != '=') { + continue; + } + + // empty keys are invalid + if (a_pKey == a_pData) { + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + continue; + } + + // remove trailing spaces from the key + pTrail = a_pData - 1; + while (pTrail >= a_pKey && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip leading whitespace on the value + ++a_pData; // safe as checked that it == '=' above + while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the value which is the end of this line + a_pVal = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // remove trailing spaces from the value + pTrail = a_pData - 1; + if (*a_pData) { // prepare for the next round + SkipNewLine(a_pData); + } + while (pTrail >= a_pVal && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // check for multi-line entries + if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { + // skip the "<<<" to get the tag that will end the multiline + const SI_CHAR * pTagName = a_pVal + 3; + return LoadMultiLineText(a_pData, a_pVal, pTagName); + } + + // return the standard entry + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsMultiLineTag( + const SI_CHAR * a_pVal + ) const +{ + // check for the "<<<" prefix for a multi-line entry + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + return true; +} + +template +bool +CSimpleIniTempl::IsMultiLineData( + const SI_CHAR * a_pData + ) const +{ + // data is multi-line if it has any of the following features: + // * whitespace prefix + // * embedded newlines + // * whitespace suffix + + // empty string + if (!*a_pData) { + return false; + } + + // check for prefix + if (IsSpace(*a_pData)) { + return true; + } + + // embedded newlines + while (*a_pData) { + if (IsNewLineChar(*a_pData)) { + return true; + } + ++a_pData; + } + + // check for suffix + if (IsSpace(*--a_pData)) { + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsNewLineChar( + SI_CHAR a_c + ) const +{ + return (a_c == '\n' || a_c == '\r'); +} + +template +bool +CSimpleIniTempl::LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment + ) const +{ + // we modify this data to strip all newlines down to a single '\n' + // character. This means that on Windows we need to strip out some + // characters which will make the data shorter. + // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become + // LINE1-LINE1\nLINE2-LINE2\0 + // The pDataLine entry is the pointer to the location in memory that + // the current line needs to start to run following the existing one. + // This may be the same as pCurrLine in which case no move is needed. + SI_CHAR * pDataLine = a_pData; + SI_CHAR * pCurrLine; + + // value starts at the current line + a_pVal = a_pData; + + // find the end tag. This tag must start in column 1 and be + // followed by a newline. We ignore any whitespace after the end + // tag but not whitespace before it. + SI_CHAR cEndOfLineChar = *a_pData; + for(;;) { + // if we are loading comments then we need a comment character as + // the first character on every line + if (!a_pTagName && !IsComment(*a_pData)) { + // if we aren't allowing blank lines then we're done + if (!a_bAllowBlankLinesInComment) { + break; + } + + // if we are allowing blank lines then we only include them + // in this comment if another comment follows, so read ahead + // to find out. + SI_CHAR * pCurr = a_pData; + int nNewLines = 0; + while (IsSpace(*pCurr)) { + if (IsNewLineChar(*pCurr)) { + ++nNewLines; + SkipNewLine(pCurr); + } + else { + ++pCurr; + } + } + + // we have a comment, add the blank lines to the output + // and continue processing from here + if (IsComment(*pCurr)) { + for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; + a_pData = pCurr; + continue; + } + + // the comment ends here + break; + } + + // find the end of this line + pCurrLine = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; + + // move this line down to the location that it should be if necessary + if (pDataLine < pCurrLine) { + size_t nLen = (size_t) (a_pData - pCurrLine); + memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); + pDataLine[nLen] = '\0'; + } + + // end the line with a NULL + cEndOfLineChar = *a_pData; + *a_pData = 0; + + // if are looking for a tag then do the check now. This is done before + // checking for end of the data, so that if we have the tag at the end + // of the data then the tag is removed correctly. + if (a_pTagName) { + // strip whitespace from the end of this tag + SI_CHAR* pc = a_pData - 1; + while (pc > pDataLine && IsSpace(*pc)) --pc; + SI_CHAR ch = *++pc; + *pc = 0; + + if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) { + break; + } + + *pc = ch; + } + + // if we are at the end of the data then we just automatically end + // this entry and return the current data. + if (!cEndOfLineChar) { + return true; + } + + // otherwise we need to process this newline to ensure that it consists + // of just a single \n character. + pDataLine += (a_pData - pCurrLine); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + *pDataLine++ = '\n'; + } + + // if we didn't find a comment at all then return false + if (a_pVal == a_pData) { + a_pVal = NULL; + return false; + } + + // the data (which ends at the end of the last line) needs to be + // null-terminated BEFORE before the newline character(s). If the + // user wants a new line in the multi-line data then they need to + // add an empty line before the tag. + *--pDataLine = '\0'; + + // if looking for a tag and if we aren't at the end of the data, + // then move a_pData to the start of the next line. + if (a_pTagName && cEndOfLineChar) { + SI_ASSERT(IsNewLineChar(cEndOfLineChar)); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::CopyString( + const SI_CHAR *& a_pString + ) +{ + size_t uLen = 0; + if (sizeof(SI_CHAR) == sizeof(char)) { + uLen = strlen((const char *)a_pString); + } + else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + uLen = wcslen((const wchar_t *)a_pString); + } + else { + for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; + } + ++uLen; // NULL character + SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen]; + if (!pCopy) { + return SI_NOMEM; + } + memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); + m_strings.push_back(pCopy); + a_pString = pCopy; + return SI_OK; +} + +template +SI_Error +CSimpleIniTempl::AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ) +{ + SI_Error rc; + bool bInserted = false; + + SI_ASSERT(!a_pComment || IsComment(*a_pComment)); + + // if we are copying strings then make a copy of the comment now + // because we will need it when we add the entry. + if (a_bCopyStrings && a_pComment) { + rc = CopyString(a_pComment); + if (rc < 0) return rc; + } + + // create the section entry if necessary + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + // if the section doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + if (a_bCopyStrings) { + rc = CopyString(a_pSection); + if (rc < 0) return rc; + } + + // only set the comment if this is a section only entry + Entry oSection(a_pSection, ++m_nOrder); + if (a_pComment && (!a_pKey || !a_pValue)) { + oSection.pComment = a_pComment; + } + + typename TSection::value_type oEntry(oSection, TKeyVal()); + typedef typename TSection::iterator SectionIterator; + std::pair i = m_data.insert(oEntry); + iSection = i.first; + bInserted = true; + } + if (!a_pKey || !a_pValue) { + // section only entries are specified with pItem and pVal as NULL + return bInserted ? SI_INSERTED : SI_UPDATED; + } + + // check for existence of the key + TKeyVal & keyval = iSection->second; + typename TKeyVal::iterator iKey = keyval.find(a_pKey); + bInserted = iKey == keyval.end(); + + // remove all existing entries but save the load order and + // comment of the first entry + int nLoadOrder = ++m_nOrder; + if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { + const SI_CHAR * pComment = NULL; + while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { + if (iKey->first.nOrder < nLoadOrder) { + nLoadOrder = iKey->first.nOrder; + pComment = iKey->first.pComment; + } + ++iKey; + } + if (pComment) { + DeleteString(a_pComment); + a_pComment = pComment; + CopyString(a_pComment); + } + Delete(a_pSection, a_pKey); + iKey = keyval.end(); + } + + // make string copies if necessary + bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; + if (a_bCopyStrings) { + if (bForceCreateNewKey || iKey == keyval.end()) { + // if the key doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + // because we will be inserting the key next + rc = CopyString(a_pKey); + if (rc < 0) return rc; + } + + // we always need a copy of the value + rc = CopyString(a_pValue); + if (rc < 0) return rc; + } + + // create the key entry + if (iKey == keyval.end() || bForceCreateNewKey) { + Entry oKey(a_pKey, nLoadOrder); + if (a_pComment) { + oKey.pComment = a_pComment; + } + typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); + iKey = keyval.insert(oEntry); + } + + iKey->second = a_pValue; + return bInserted ? SI_INSERTED : SI_UPDATED; +} + +template +const SI_CHAR * +CSimpleIniTempl::GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault, + bool * a_pHasMultiple + ) const +{ + if (a_pHasMultiple) { + *a_pHasMultiple = false; + } + if (!a_pSection || !a_pKey) { + return a_pDefault; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return a_pDefault; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return a_pDefault; + } + + // check for multiple entries with the same key + if (m_bAllowMultiKey && a_pHasMultiple) { + typename TKeyVal::const_iterator iTemp = iKeyVal; + if (++iTemp != iSection->second.end()) { + if (!IsLess(a_pKey, iTemp->first.pItem)) { + *a_pHasMultiple = true; + } + } + } + + return iKeyVal->second; +} + +template +long +CSimpleIniTempl::GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + // handle the value as hex if prefaced with "0x" + long nValue = a_nDefault; + char * pszSuffix = szValue; + if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { + if (!szValue[2]) return a_nDefault; + nValue = strtol(&szValue[2], &pszSuffix, 16); + } + else { + nValue = strtol(szValue, &pszSuffix, 10); + } + + // any invalid strings will return the default value + if (*pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment, + bool a_bUseHex, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +double +CSimpleIniTempl::GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + char * pszSuffix = NULL; + double nValue = strtod(szValue, &pszSuffix); + + // any invalid strings will return the default value + if (!pszSuffix || *pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, "%f", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, "%f", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_bDefault; + + // we only look at the minimum number of characters + switch (pszValue[0]) { + case 't': case 'T': // true + case 'y': case 'Y': // yes + case '1': // 1 (one) + return true; + + case 'f': case 'F': // false + case 'n': case 'N': // no + case '0': // 0 (zero) + return false; + + case 'o': case 'O': + if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on + if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off + break; + } + + // no recognized value, return the default + return a_bDefault; +} + +template +SI_Error +CSimpleIniTempl::SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + const char * pszInput = a_bValue ? "true" : "false"; + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const +{ + a_values.clear(); + + if (!a_pSection || !a_pKey) { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + // insert all values for this key + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + if (m_bAllowMultiKey) { + ++iKeyVal; + while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + ++iKeyVal; + } + } + + return true; +} + +template +int +CSimpleIniTempl::GetSectionSize( + const SI_CHAR * a_pSection + ) const +{ + if (!a_pSection) { + return -1; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return -1; + } + const TKeyVal & section = iSection->second; + + // if multi-key isn't permitted then the section size is + // the number of keys that we have. + if (!m_bAllowMultiKey || section.empty()) { + return (int) section.size(); + } + + // otherwise we need to count them + int nCount = 0; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + ++nCount; + pLastKey = iKeyVal->first.pItem; + } + } + return nCount; +} + +template +const typename CSimpleIniTempl::TKeyVal * +CSimpleIniTempl::GetSection( + const SI_CHAR * a_pSection + ) const +{ + if (a_pSection) { + typename TSection::const_iterator i = m_data.find(a_pSection); + if (i != m_data.end()) { + return &(i->second); + } + } + return 0; +} + +template +void +CSimpleIniTempl::GetAllSections( + TNamesDepend & a_names + ) const +{ + a_names.clear(); + typename TSection::const_iterator i = m_data.begin(); + for (int n = 0; i != m_data.end(); ++i, ++n ) { + a_names.push_back(i->first); + } +} + +template +bool +CSimpleIniTempl::GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const +{ + a_names.clear(); + + if (!a_pSection) { + return false; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + const TKeyVal & section = iSection->second; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + a_names.push_back(iKeyVal->first); + pLastKey = iKeyVal->first.pItem; + } + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::SaveFile( + const char * a_pszFile, + bool a_bAddSignature + ) const +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::SaveFile( + const SI_WCHAR_T * a_pwszFile, + bool a_bAddSignature + ) const +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return SaveFile(szFile, a_bAddSignature); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::SaveFile( + FILE * a_pFile, + bool a_bAddSignature + ) const +{ + FileWriter writer(a_pFile); + return Save(writer, a_bAddSignature); +} + +template +SI_Error +CSimpleIniTempl::Save( + OutputWriter & a_oOutput, + bool a_bAddSignature + ) const +{ + Converter convert(m_bStoreIsUtf8); + + // add the UTF-8 signature if it is desired + if (m_bStoreIsUtf8 && a_bAddSignature) { + a_oOutput.Write(SI_UTF8_SIGNATURE); + } + + // get all of the sections sorted in load order + TNamesDepend oSections; + GetAllSections(oSections); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oSections.sort(); +#elif defined(__BORLANDC__) + oSections.sort(Entry::LoadOrder()); +#else + oSections.sort(typename Entry::LoadOrder()); +#endif + + // if there is an empty section name, then it must be written out first + // regardless of the load order + typename TNamesDepend::iterator is = oSections.begin(); + for (; is != oSections.end(); ++is) { + if (!*is->pItem) { + // move the empty section name to the front of the section list + if (is != oSections.begin()) { + oSections.splice(oSections.begin(), oSections, is, std::next(is)); + } + break; + } + } + + // write the file comment if we have one + bool bNeedNewLine = false; + if (m_pFileComment) { + if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { + return SI_FAIL; + } + bNeedNewLine = true; + } + + // iterate through our sections and output the data + typename TNamesDepend::const_iterator iSection = oSections.begin(); + for ( ; iSection != oSections.end(); ++iSection ) { + // write out the comment if there is one + if (iSection->pComment) { + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + } + if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { + return SI_FAIL; + } + bNeedNewLine = false; + } + + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + bNeedNewLine = false; + } + + // write the section (unless there is no section name) + if (*iSection->pItem) { + if (!convert.ConvertToStore(iSection->pItem)) { + return SI_FAIL; + } + a_oOutput.Write("["); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("]"); + a_oOutput.Write(SI_NEWLINE_A); + } + + // get all of the keys sorted in load order + TNamesDepend oKeys; + GetAllKeys(iSection->pItem, oKeys); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oKeys.sort(); +#elif defined(__BORLANDC__) + oKeys.sort(Entry::LoadOrder()); +#else + oKeys.sort(typename Entry::LoadOrder()); +#endif + + // write all keys and values + typename TNamesDepend::const_iterator iKey = oKeys.begin(); + for ( ; iKey != oKeys.end(); ++iKey) { + // get all values for this key + TNamesDepend oValues; + GetAllValues(iSection->pItem, iKey->pItem, oValues); + + typename TNamesDepend::const_iterator iValue = oValues.begin(); + for ( ; iValue != oValues.end(); ++iValue) { + // write out the comment if there is one + if (iValue->pComment) { + a_oOutput.Write(SI_NEWLINE_A); + if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { + return SI_FAIL; + } + } + + // write the key + if (!convert.ConvertToStore(iKey->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(convert.Data()); + + // write the value + if (!convert.ConvertToStore(iValue->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(m_bSpaces ? " = " : "="); + if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { + // multi-line data needs to be processed specially to ensure + // that we use the correct newline format for the current system + a_oOutput.Write("<<pItem)) { + return SI_FAIL; + } + a_oOutput.Write("END_OF_TEXT"); + } + else { + a_oOutput.Write(convert.Data()); + } + a_oOutput.Write(SI_NEWLINE_A); + } + } + + bNeedNewLine = true; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const +{ + const SI_CHAR * pEndOfLine; + SI_CHAR cEndOfLineChar = *a_pText; + while (cEndOfLineChar) { + // find the end of this line + pEndOfLine = a_pText; + for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; + cEndOfLineChar = *pEndOfLine; + + // temporarily null terminate, convert and output the line + *const_cast(pEndOfLine) = 0; + if (!a_oConverter.ConvertToStore(a_pText)) { + return false; + } + *const_cast(pEndOfLine) = cEndOfLineChar; + a_pText += (pEndOfLine - a_pText) + 1; + a_oOutput.Write(a_oConverter.Data()); + a_oOutput.Write(SI_NEWLINE_A); + } + return true; +} + +template +bool +CSimpleIniTempl::Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty + ) +{ + return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty); +} + +template +bool +CSimpleIniTempl::DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty + ) +{ + if (!a_pSection) { + return false; + } + + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + // remove a single key if we have a keyname + if (a_pKey) { + typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + const static SI_STRLESS isLess = SI_STRLESS(); + + // remove any copied strings and then the key + typename TKeyVal::iterator iDelete; + bool bDeleted = false; + do { + iDelete = iKeyVal++; + + if(a_pValue == NULL || + (isLess(a_pValue, iDelete->second) == false && + isLess(iDelete->second, a_pValue) == false)) { + DeleteString(iDelete->first.pItem); + DeleteString(iDelete->second); + iSection->second.erase(iDelete); + bDeleted = true; + } + } + while (iKeyVal != iSection->second.end() + && !IsLess(a_pKey, iKeyVal->first.pItem)); + + if(!bDeleted) { + return false; + } + + // done now if the section is not empty or we are not pruning away + // the empty sections. Otherwise let it fall through into the section + // deletion code + if (!a_bRemoveEmpty || !iSection->second.empty()) { + return true; + } + } + else { + // delete all copied strings from this section. The actual + // entries will be removed when the section is removed. + typename TKeyVal::iterator iKeyVal = iSection->second.begin(); + for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { + DeleteString(iKeyVal->first.pItem); + DeleteString(iKeyVal->second); + } + } + + // delete the section itself + DeleteString(iSection->first.pItem); + m_data.erase(iSection); + + return true; +} + +template +void +CSimpleIniTempl::DeleteString( + const SI_CHAR * a_pString + ) +{ + // strings may exist either inside the data block, or they will be + // individually allocated and stored in m_strings. We only physically + // delete those stored in m_strings. + if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (;i != m_strings.end(); ++i) { + if (a_pString == i->pItem) { + delete[] const_cast(i->pItem); + m_strings.erase(i); + break; + } + } + } +} + +// --------------------------------------------------------------------------- +// CONVERSION FUNCTIONS +// --------------------------------------------------------------------------- + +// Defines the conversion classes for different libraries. Before including +// SimpleIni.h, set the converter that you wish you use by defining one of the +// following symbols. +// +// SI_NO_CONVERSION Do not make the "W" wide character version of the +// library available. Only CSimpleIniA etc is defined. +// SI_CONVERT_GENERIC Use the Unicode reference conversion library in +// the accompanying files ConvertUTF.h/c +// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires +// ICU headers on include path and icuuc.lib +// SI_CONVERT_WIN32 Use the Win32 API functions for conversion. + +#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) +# ifdef _WIN32 +# define SI_CONVERT_WIN32 +# else +# define SI_CONVERT_GENERIC +# endif +#endif + +/** + * Generic case-sensitive less than comparison. This class returns numerically + * ordered ASCII case-sensitive text for all possible sizes and types of + * SI_CHAR. + */ +template +struct SI_GenericCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) *pLeft - (long) *pRight; + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Generic ASCII case-insensitive less than comparison. This class returns + * numerically ordered ASCII case-insensitive text for all possible sizes + * and types of SI_CHAR. It is not safe for MBCS text comparison where + * ASCII A-Z characters are used in the encoding of multi-byte characters. + */ +template +struct SI_GenericNoCase { + inline SI_CHAR locase(SI_CHAR ch) const { + return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); + } + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) locase(*pLeft) - (long) locase(*pRight); + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Null conversion class for MBCS/UTF-8 to char (or equivalent). + */ +template +class SI_ConvertA { + bool m_bStoreIsUtf8; +protected: + SI_ConvertA() { } +public: + SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } + SI_ConvertA & operator=(const SI_ConvertA & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + // ASCII/MBCS/UTF-8 needs no conversion + return a_uInputDataLen; + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + // ASCII/MBCS/UTF-8 needs no conversion + if (a_uInputDataLen > a_uOutputDataSize) { + return false; + } + memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + // ASCII/MBCS/UTF-8 needs no conversion + return strlen((const char *)a_pInputData) + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = strlen((const char *)a_pInputData) + 1; + if (uInputLen > a_uOutputDataSize) { + return false; + } + + // ascii/UTF-8 needs no conversion + memcpy(a_pOutputData, a_pInputData, uInputLen); + return true; + } +}; + + +// --------------------------------------------------------------------------- +// SI_CONVERT_GENERIC +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_GENERIC + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include +#include "ConvertUTF.h" + +/** + * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference + * library functions. This can be used on all platforms. + */ +template +class SI_ConvertW { + bool m_bStoreIsUtf8; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + if (m_bStoreIsUtf8) { + // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t + // so we just return the same number of characters required as for + // the source text. + return a_uInputDataLen; + } + +#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) + // fall back processing for platforms that don't support a NULL dest to mbstowcs + // worst case scenario is 1:1, this will be a sufficient buffer size + (void)a_pInputData; + return a_uInputDataLen; +#else + // get the actual required buffer size + return mbstowcs(NULL, a_pInputData, a_uInputDataLen); +#endif + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + if (m_bStoreIsUtf8) { + // This uses the Unicode reference implementation to do the + // conversion from UTF-8 to wchar_t. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + UTF32 * pUtf32 = (UTF32 *) a_pOutputData; + retval = ConvertUTF8toUTF32( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf32, pUtf32 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + UTF16 * pUtf16 = (UTF16 *) a_pOutputData; + retval = ConvertUTF8toUTF16( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf16, pUtf16 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + + // convert to wchar_t + size_t retval = mbstowcs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t)(-1); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + if (m_bStoreIsUtf8) { + // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char + size_t uLen = 0; + while (a_pInputData[uLen]) { + ++uLen; + } + return (6 * uLen) + 1; + } + else { + size_t uLen = wcstombs(NULL, a_pInputData, 0); + if (uLen == (size_t)(-1)) { + return uLen; + } + return uLen + 1; // include NULL terminator + } + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize + ) + { + if (m_bStoreIsUtf8) { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = 0; + while (a_pInputData[uInputLen]) { + ++uInputLen; + } + ++uInputLen; // include the NULL char + + // This uses the Unicode reference implementation to do the + // conversion from wchar_t to UTF-8. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + UTF8 * pUtf8 = (UTF8 *) a_pOutputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; + retval = ConvertUTF32toUTF8( + &pUtf32, pUtf32 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; + retval = ConvertUTF16toUTF8( + &pUtf16, pUtf16 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + else { + size_t retval = wcstombs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t) -1; + } + } +}; + +#endif // SI_CONVERT_GENERIC + + +// --------------------------------------------------------------------------- +// SI_CONVERT_ICU +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_ICU + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include + +/** + * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. + */ +template +class SI_ConvertW { + const char * m_pEncoding; + UConverter * m_pConverter; +protected: + SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { + m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_pEncoding = rhs.m_pEncoding; + m_pConverter = NULL; + return *this; + } + ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } + + /** Calculate the number of UChar required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of UChar required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen; + } + + /** Convert the input string from the storage format to UChar. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in UChar. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + UChar * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_toUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const UChar * a_pInputData) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, + a_pInputData, -1, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const UChar * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_fromUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, -1, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } +}; + +#endif // SI_CONVERT_ICU + + +// --------------------------------------------------------------------------- +// SI_CONVERT_WIN32 +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_WIN32 + +#define SI_Case SI_GenericCase + +// Windows CE doesn't have errno or MBCS libraries +#ifdef _WIN32_WCE +# ifndef SI_NO_MBCS +# define SI_NO_MBCS +# endif +#endif + +#include +#ifdef SI_NO_MBCS +# define SI_NoCase SI_GenericNoCase +#else // !SI_NO_MBCS +/** + * Case-insensitive comparison class using Win32 MBCS functions. This class + * returns a case-insensitive semi-collation order for MBCS text. It may not + * be safe for UTF-8 text returned in char format as we don't know what + * characters will be folded by the function! Therefore, if you are using + * SI_CHAR == char and SetUnicode(true), then you need to use the generic + * SI_NoCase class instead. + */ +#include +template +struct SI_NoCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + if (sizeof(SI_CHAR) == sizeof(char)) { + return _mbsicmp((const unsigned char *)pLeft, + (const unsigned char *)pRight) < 0; + } + if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + return _wcsicmp((const wchar_t *)pLeft, + (const wchar_t *)pRight) < 0; + } + return SI_GenericNoCase()(pLeft, pRight); + } +}; +#endif // SI_NO_MBCS + +/** + * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses + * only the Win32 functions and doesn't require the external Unicode UTF-8 + * conversion library. It will not work on Windows 95 without using Microsoft + * Layer for Unicode in your application. + */ +template +class SI_ConvertW { + UINT m_uCodePage; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) { + m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_uCodePage = rhs.m_uCodePage; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + int retval = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + 0, 0); + return (size_t)(retval > 0 ? retval : -1); + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + int nSize = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); + return (nSize > 0); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + 0, 0, 0, 0); + return (size_t) (retval > 0 ? retval : -1); + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + a_pOutputData, (int) a_uOutputDataSize, 0, 0); + return retval > 0; + } +}; + +#endif // SI_CONVERT_WIN32 + + + +// --------------------------------------------------------------------------- +// SI_NO_CONVERSION +// --------------------------------------------------------------------------- +#ifdef SI_NO_CONVERSION + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#endif // SI_NO_CONVERSION + + + +// --------------------------------------------------------------------------- +// TYPE DEFINITIONS +// --------------------------------------------------------------------------- + +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; + +#if defined(SI_NO_CONVERSION) +// if there is no wide char conversion then we don't need to define the +// widechar "W" versions of CSimpleIni +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +#else +# if defined(SI_CONVERT_ICU) +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# else +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# endif + +# ifdef _UNICODE +# define CSimpleIni CSimpleIniW +# define CSimpleIniCase CSimpleIniCaseW +# define SI_NEWLINE SI_NEWLINE_W +# else // !_UNICODE +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +# endif // _UNICODE +#endif + +#ifdef _MSC_VER +# pragma warning (pop) +#endif + +#endif // INCLUDED_SimpleIni_h + diff --git a/injector/injector.vcxproj b/injector/injector.vcxproj new file mode 100644 index 0000000..7cabb49 --- /dev/null +++ b/injector/injector.vcxproj @@ -0,0 +1,210 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + {704c8746-1bd9-4bc8-9ebe-8187f1a1ad72} + false + + + + 16.0 + Win32Proj + {f578b30c-8de6-4741-99e4-1d30d2acdac4} + testbypassmhyprot + 10.0 + injector + + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + + + false + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + + + false + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + + + false + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\ + $(ProjectDir)bin\$(PlatformShortName)\$(Configuration)\obj\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)include/ + + + Console + true + RequireAdministrator + false + + + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)include/ + + + Console + true + true + true + RequireAdministrator + false + + + + + + + + + Level3 + + + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + false + ProgramDatabase + false + $(ProjectDir)include/ + + + Console + true + RequireAdministrator + + + + + + + + + + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)include/ + + + Console + true + true + true + RequireAdministrator + false + + + + + + + + + + \ No newline at end of file diff --git a/injector/injector.vcxproj.filters b/injector/injector.vcxproj.filters new file mode 100644 index 0000000..21d8cc8 --- /dev/null +++ b/injector/injector.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/injector/src/injector.cpp b/injector/src/injector.cpp new file mode 100644 index 0000000..5e6c178 --- /dev/null +++ b/injector/src/injector.cpp @@ -0,0 +1,412 @@ +#include "injector.h" + +#if defined(DISABLE_OUTPUT) +#define ILog(data, ...) +#define IPrintError(text, ...) +#else +#define ILog(text, ...) printf(text, __VA_ARGS__) +#define ILogError(text, ...) ILog(text, __VA_ARGS__); std::cout << "Error: " << GetLastErrorAsString() << std::endl +#endif + +#ifdef _WIN64 +#define CURRENT_ARCH IMAGE_FILE_MACHINE_AMD64 +#else +#define CURRENT_ARCH IMAGE_FILE_MACHINE_I386 +#endif + +bool InjectDLL(HANDLE hProc, const std::string& filepath) { + +#ifndef _DEBUG // _DEBUG + // Using LoadLibrary inject to be able to debug DLL in attached process. + // NOTE. For debug also needs disable mhyprot protection. (See protection-bypass.h in cheat-library) + bool result = LoadLibraryInject(hProc, filepath); +#else + std::ifstream file(filepath, std::ios::in | std::ios::binary | std::ios::ate); + if (!file.is_open()) + { + std::cout << "Error while reading DLL file!" << std::endl; + return false; + } + + std::streampos size = file.tellg(); + auto memblock = new char[size]; + file.seekg(0, std::ios::beg); + file.read(memblock, size); + file.close(); + + BYTE* fileContent = (BYTE*)memblock; + + // Manual map injection will help us to be like a assasin + bool result = ManualMapDll(hProc, fileContent, size); + + delete[] memblock; +#endif + + return result; +} + +#ifdef _DEBUG +static bool LoadLibraryInject(HANDLE hProc, const std::string& dllpath) +{ + HMODULE hKernel = GetModuleHandle("kernel32.dll"); + if (hKernel == NULL) { + ILogError("[DLL Injection] Failed to get kernel32.dll module address.\n"); + return false; + } + + LPVOID pLoadLibrary = (LPVOID)GetProcAddress(hKernel, "LoadLibraryA"); + if (pLoadLibrary == NULL) { + ILogError("[DLL Injection] Failed to get LoadLibraryA address.\n"); + return false; + } + + LPVOID pDLLPath = VirtualAllocEx(hProc, NULL, strlen(dllpath.c_str()) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (pDLLPath == NULL) { + ILogError("[DLL Injection] Failed to allocate memory for DLLPath in target process.\n"); + return false; + } + + // Write the string name of our DLL in the memory allocated + BOOL writeResult = WriteProcessMemory(hProc, pDLLPath, dllpath.c_str(), strlen(dllpath.c_str()), NULL); + if (writeResult == FALSE) { + ILogError("[DLL Injection] Failed to write remote process memory.\n"); + return false; + } + + // Load our DLL by calling loadlibrary in the other process and passing our dll name + HANDLE hThread = CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)pLoadLibrary, (LPVOID)pDLLPath, NULL, NULL); + if (hThread == NULL) { + ILogError("[DLL Injection] Failed to create remote thread.\n"); + VirtualFreeEx(hProc, pDLLPath, 0, MEM_RELEASE); + return false; + } + CloseHandle(hThread); + + // TODO: Add waiting for thread end and release unneccessary data. + // VirtualFreeEx(hProc, pDLLPath, 0, MEM_RELEASE); + + ILogError("[DLL Injection] Successfully LoadLibraryA injection.\n"); + return true; +} + +#endif // _DEBUG + +bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader, bool ClearNonNeededSections, bool AdjustProtections, bool SEHExceptionSupport, DWORD fdwReason) { + IMAGE_NT_HEADERS* pOldNtHeader = nullptr; + IMAGE_OPTIONAL_HEADER* pOldOptHeader = nullptr; + IMAGE_FILE_HEADER* pOldFileHeader = nullptr; + BYTE* pTargetBase = nullptr; + + if (reinterpret_cast(pSrcData)->e_magic != 0x5A4D) { //"MZ" + ILog("[DLL injection] Invalid file\n"); + return false; + } + + pOldNtHeader = reinterpret_cast(pSrcData + reinterpret_cast(pSrcData)->e_lfanew); + pOldOptHeader = &pOldNtHeader->OptionalHeader; + pOldFileHeader = &pOldNtHeader->FileHeader; + + if (pOldFileHeader->Machine != CURRENT_ARCH) { + ILog("[DLL injection] Invalid platform.\n"); + return false; + } + + ILog("[DLL injection] File ok\n"); + + pTargetBase = reinterpret_cast(VirtualAllocEx(hProc, nullptr, pOldOptHeader->SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + if (!pTargetBase) { + ILogError("[DLL injection] Target process memory allocation failed (ex)\n"); + return false; + } + + DWORD oldp = 0; + VirtualProtectEx(hProc, pTargetBase, pOldOptHeader->SizeOfImage, PAGE_EXECUTE_READWRITE, &oldp); + + MANUAL_MAPPING_DATA data{ 0 }; + data.pLoadLibraryA = LoadLibraryA; + data.pGetProcAddress = GetProcAddress; +#ifdef _WIN64 + data.pRtlAddFunctionTable = (f_RtlAddFunctionTable)RtlAddFunctionTable; +#else + SEHExceptionSupport = false; +#endif + data.pbase = pTargetBase; + data.fdwReasonParam = fdwReason; + data.SEHSupport = SEHExceptionSupport; + + //File header + if (!WriteProcessMemory(hProc, pTargetBase, pSrcData, 0x1000, nullptr)) { //only first 0x1000 bytes for the header + ILogError("[DLL injection] Can't write file header.\n"); + + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + return false; + } + + IMAGE_SECTION_HEADER* pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader); + for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader) { + if (pSectionHeader->SizeOfRawData) { + if (!WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSrcData + pSectionHeader->PointerToRawData, pSectionHeader->SizeOfRawData, nullptr)) { + ILogError("[DLL injection] Can't map sections.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + return false; + } + } + } + + //Mapping params + BYTE* MappingDataAlloc = reinterpret_cast(VirtualAllocEx(hProc, nullptr, sizeof(MANUAL_MAPPING_DATA), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + if (!MappingDataAlloc) { + ILogError("[DLL injection] Target process mapping allocation failed (ex).\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + return false; + } + + if (!WriteProcessMemory(hProc, MappingDataAlloc, &data, sizeof(MANUAL_MAPPING_DATA), nullptr)) { + ILogError("[DLL injection] Can't write mapping.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + return false; + } + + //Shell code + void* pShellcode = VirtualAllocEx(hProc, nullptr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!pShellcode) { + ILogError("[DLL injection] Memory shellcode allocation failed (ex).\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + return false; + } + + if (!WriteProcessMemory(hProc, pShellcode, Shellcode, 0x1000, nullptr)) { + ILogError("[DLL injection] Can't write shellcode.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); + return false; + } + + ILog("[DLL injection] Mapped DLL at %p\n", pTargetBase); + ILog("[DLL injection] Mapping info at %p\n", MappingDataAlloc); + ILog("[DLL injection] Shell code at %p\n", pShellcode); + + ILog("[DLL injection] Data allocated\n"); + +#ifdef _DEBUG + ILog("[DLL injection] My shellcode pointer %p\n", Shellcode); + ILog("[DLL injection] Target point %p\n", pShellcode); +#endif + + HANDLE hThread = CreateRemoteThread(hProc, nullptr, 0, reinterpret_cast(pShellcode), MappingDataAlloc, 0, nullptr); + if (!hThread) { + ILogError("[DLL injection] Thread creation failed.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); + return false; + } + CloseHandle(hThread); + + ILog("[DLL injection] Thread created at: %p, waiting for return...\n", pShellcode); + + HINSTANCE hCheck = NULL; + while (!hCheck) { + DWORD exitcode = 0; + GetExitCodeProcess(hProc, &exitcode); + if (exitcode != STILL_ACTIVE) { + ILog("[DLL injection] Process crashed, exit code: 0x%x\n", exitcode); + return false; + } + + MANUAL_MAPPING_DATA data_checked{ 0 }; + ReadProcessMemory(hProc, MappingDataAlloc, &data_checked, sizeof(data_checked), nullptr); + hCheck = data_checked.hMod; + + if (hCheck == (HINSTANCE)0x404040) { + ILog("[DLL injection] Wrong mapping ptr.\n"); + VirtualFreeEx(hProc, pTargetBase, 0, MEM_RELEASE); + VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE); + VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE); + return false; + } + else if (hCheck == (HINSTANCE)0x505050) { + ILog("[DLL injection] WARNING: Exception support failed!\n"); + } + + Sleep(10); + } + + BYTE* emptyBuffer = (BYTE*)malloc(1024 * 1024 * 20); + if (emptyBuffer == nullptr) { + ILog("[DLL injection] Unable to allocate memory\n"); + return false; + } + memset(emptyBuffer, 0, 1024 * 1024 * 20); + + //CLEAR PE HEAD + if (ClearHeader) { + if (!WriteProcessMemory(hProc, pTargetBase, emptyBuffer, 0x1000, nullptr)) { + ILogError("[DLL injection] WARNING!: Can't clear HEADER\n"); + } + } + //END CLEAR PE HEAD + + + if (ClearNonNeededSections) { + pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader); + for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader) { + if (pSectionHeader->Misc.VirtualSize) { + if ((SEHExceptionSupport ? 0 : strcmp((char*)pSectionHeader->Name, ".pdata") == 0) || + strcmp((char*)pSectionHeader->Name, ".rsrc") == 0 || + strcmp((char*)pSectionHeader->Name, ".reloc") == 0) { + ILog("[DLL injection] Processing %s removal\n", pSectionHeader->Name); + if (!WriteProcessMemory(hProc, pTargetBase + pSectionHeader->VirtualAddress, emptyBuffer, pSectionHeader->Misc.VirtualSize, nullptr)) { + ILogError("[DLL injection] Can't clear section %s.\n", pSectionHeader->Name); + } + } + } + } + } + + if (AdjustProtections) { + pSectionHeader = IMAGE_FIRST_SECTION(pOldNtHeader); + for (UINT i = 0; i != pOldFileHeader->NumberOfSections; ++i, ++pSectionHeader) { + if (pSectionHeader->Misc.VirtualSize) { + DWORD old = 0; + DWORD newP = PAGE_READONLY; + + if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) > 0) { + newP = PAGE_READWRITE; + } + else if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) > 0) { + newP = PAGE_EXECUTE_READ; + } + if (VirtualProtectEx(hProc, pTargetBase + pSectionHeader->VirtualAddress, pSectionHeader->Misc.VirtualSize, newP, &old)) { + ILog("[DLL injection] Section %s set as %lX\n", (char*)pSectionHeader->Name, newP); + } + else { + ILog("[DLL injection] FAIL: section %s not set as %lX\n", (char*)pSectionHeader->Name, newP); + } + } + } + DWORD old = 0; + VirtualProtectEx(hProc, pTargetBase, IMAGE_FIRST_SECTION(pOldNtHeader)->VirtualAddress, PAGE_READONLY, &old); + } + + if (!WriteProcessMemory(hProc, pShellcode, emptyBuffer, 0x1000, nullptr)) { + ILog("[DLL injection] WARNING: Can't clear shellcode\n"); + } + if (!VirtualFreeEx(hProc, pShellcode, 0, MEM_RELEASE)) { + ILog("[DLL injection] WARNING: can't release shell code memory\n"); + } + if (!VirtualFreeEx(hProc, MappingDataAlloc, 0, MEM_RELEASE)) { + ILog("[DLL injection] WARNING: can't release mapping data memory\n"); + } + + return true; +} + +#define RELOC_FLAG32(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_HIGHLOW) +#define RELOC_FLAG64(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_DIR64) + +#ifdef _WIN64 +#define RELOC_FLAG RELOC_FLAG64 +#else +#define RELOC_FLAG RELOC_FLAG32 +#endif + +#pragma runtime_checks( "", off ) +#pragma optimize( "", off ) +void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData) { + + if (!pData) { + pData->hMod = (HINSTANCE)0x404040; + return; + } + + BYTE* pBase = pData->pbase; + auto* pOpt = &reinterpret_cast(pBase + reinterpret_cast((uintptr_t)pBase)->e_lfanew)->OptionalHeader; + + auto _LoadLibraryA = pData->pLoadLibraryA; + auto _GetProcAddress = pData->pGetProcAddress; +#ifdef _WIN64 + auto _RtlAddFunctionTable = pData->pRtlAddFunctionTable; +#endif + auto _DllMain = reinterpret_cast(pBase + pOpt->AddressOfEntryPoint); + + + BYTE* LocationDelta = pBase - pOpt->ImageBase; + if (LocationDelta) { + if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { + auto* pRelocData = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); + const auto* pRelocEnd = reinterpret_cast(reinterpret_cast(pRelocData) + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); + while (pRelocData < pRelocEnd && pRelocData->SizeOfBlock) { + UINT AmountOfEntries = (pRelocData->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); + WORD* pRelativeInfo = reinterpret_cast(pRelocData + 1); + + for (UINT i = 0; i != AmountOfEntries; ++i, ++pRelativeInfo) { + if (RELOC_FLAG(*pRelativeInfo)) { + UINT_PTR* pPatch = reinterpret_cast(pBase + pRelocData->VirtualAddress + ((*pRelativeInfo) & 0xFFF)); + *pPatch += reinterpret_cast(LocationDelta); + } + } + pRelocData = reinterpret_cast(reinterpret_cast(pRelocData) + pRelocData->SizeOfBlock); + } + } + } + + if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) { + auto* pImportDescr = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + while (pImportDescr->Name) { + char* szMod = reinterpret_cast(pBase + pImportDescr->Name); + HINSTANCE hDll = _LoadLibraryA(szMod); + + ULONG_PTR* pThunkRef = reinterpret_cast(pBase + pImportDescr->OriginalFirstThunk); + ULONG_PTR* pFuncRef = reinterpret_cast(pBase + pImportDescr->FirstThunk); + + if (!pThunkRef) + pThunkRef = pFuncRef; + + for (; *pThunkRef; ++pThunkRef, ++pFuncRef) { + if (IMAGE_SNAP_BY_ORDINAL(*pThunkRef)) { + *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, reinterpret_cast(*pThunkRef & 0xFFFF)); + } + else { + auto* pImport = reinterpret_cast(pBase + (*pThunkRef)); + *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, pImport->Name); + } + } + ++pImportDescr; + } + } + + if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) { + auto* pTLS = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + auto* pCallback = reinterpret_cast(pTLS->AddressOfCallBacks); + for (; pCallback && *pCallback; ++pCallback) + (*pCallback)(pBase, DLL_PROCESS_ATTACH, nullptr); + } + + bool ExceptionSupportFailed = false; + +#ifdef _WIN64 + + if (pData->SEHSupport) { + auto excep = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; + if (excep.Size) { + if (!_RtlAddFunctionTable( + reinterpret_cast(pBase + excep.VirtualAddress), + excep.Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), (DWORD64)pBase)) { + ExceptionSupportFailed = true; + } + } + } + +#endif + + _DllMain(pBase, pData->fdwReasonParam, nullptr); + + if (ExceptionSupportFailed) + pData->hMod = reinterpret_cast(0x505050); + else + pData->hMod = reinterpret_cast(pBase); +} \ No newline at end of file diff --git a/injector/src/injector.h b/injector/src/injector.h new file mode 100644 index 0000000..1d3af97 --- /dev/null +++ b/injector/src/injector.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "util.h" + +using f_LoadLibraryA = HINSTANCE(WINAPI*)(const char* lpLibFilename); +using f_GetProcAddress = FARPROC(WINAPI*)(HMODULE hModule, LPCSTR lpProcName); +using f_DLL_ENTRY_POINT = BOOL(WINAPI*)(void* hDll, DWORD dwReason, void* pReserved); + +#ifdef _WIN64 +using f_RtlAddFunctionTable = BOOL(WINAPIV*)(PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount, DWORD64 BaseAddress); +#endif + +struct ConfigInfo { + bool disableMhyprot; + bool consoleLogging; +}; + +struct MANUAL_MAPPING_DATA +{ + f_LoadLibraryA pLoadLibraryA; + f_GetProcAddress pGetProcAddress; +#ifdef _WIN64 + f_RtlAddFunctionTable pRtlAddFunctionTable; +#endif + BYTE* pbase; + HINSTANCE hMod; + DWORD fdwReasonParam; + LPVOID reservedParam; + BOOL SEHSupport; +}; + + +bool InjectDLL(HANDLE hProc, const std::string& filepath); + +#ifdef _DEBUG +static bool LoadLibraryInject(HANDLE hProc, const std::string& dllpath); +#endif + +// Note: Exception support only x64 with build params /EHa or /EHc +bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, SIZE_T FileSize, bool ClearHeader = false, bool ClearNonNeededSections = false, bool AdjustProtections = false, bool SEHExceptionSupport = false, DWORD fdwReason = DLL_PROCESS_ATTACH); +void __stdcall Shellcode(MANUAL_MAPPING_DATA* pData); \ No newline at end of file diff --git a/injector/src/main.cpp b/injector/src/main.cpp new file mode 100644 index 0000000..9e34f76 --- /dev/null +++ b/injector/src/main.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#include "injector.h" +#include "simple-ini.hpp" +#include "util.h" + +const std::string GlobalGenshinProcName = "GenshinImpact.exe"; +const std::string ChinaGenshinProcName = "YuanShen.exe"; + +const char* INIFileName = "config.ini"; + +static CSimpleIni ini; + +HANDLE OpenGenshinProcess(); + +int main(int argc, char* argv[]) +{ + auto path = std::filesystem::path(argv[0]).parent_path(); + std::filesystem::current_path(path); + + WaitForCloseProcess(GlobalGenshinProcName); + WaitForCloseProcess(ChinaGenshinProcName); + + Sleep(1000); // Wait for unloading all dlls. + + ini.SetUnicode(); + ini.LoadFile(INIFileName); + + HANDLE hProcess = OpenGenshinProcess(); + if (hProcess == NULL) + { + std::cout << "Failed to open GenshinImpact process." << std::endl; + return 1; + } + + ini.SaveFile(INIFileName); + + std::filesystem::current_path(path); + + std::string filename = (argc == 2 ? argv[1] : "CLibrary.dll"); + std::filesystem::path currentDllPath = std::filesystem::current_path() / filename; + std::filesystem::path tempDllPath = std::filesystem::temp_directory_path() / filename; + + std::filesystem::copy(currentDllPath, tempDllPath, std::filesystem::copy_options::update_existing); + InjectDLL(hProcess, tempDllPath.string()); + + CloseHandle(hProcess); +} + +HANDLE OpenGenshinProcess() { + STARTUPINFOA startInfo{}; + PROCESS_INFORMATION processInformation{}; + + auto savedPath = ini.GetValue("Inject", "GenshinPath"); + bool exePathNotExist = savedPath == nullptr; + + std::string* filePath = exePathNotExist ? nullptr : new std::string(savedPath); + if (exePathNotExist) { + std::cout << "Genshin path not found. Please point to it manually. ^)" << std::endl; + filePath = GetFilePathByUser(); + if (filePath == nullptr) { + std::cout << "Failed to get genshin path from user. Exiting..." << std::endl; + return NULL; + } + } + + BOOL result = CreateProcessA(filePath->c_str(), + nullptr, 0, 0, false, CREATE_SUSPENDED, nullptr, nullptr, &startInfo, &processInformation); + if (result == FALSE) { + std::cout << "Failed to create game process." << std::endl; + std::cout << "Error: " << GetLastErrorAsString() << std::endl; + std::cout << "If you have problem with GenshinImpact.exe path. You can change it manually in " << INIFileName << "." << std::endl; + return NULL; + } + + if (exePathNotExist) { + ini.SetValue("Inject", "genshinPath", (*filePath).c_str()); + std::cout << "New GenshinImpact.exe path saved to " << INIFileName << "." << std::endl; + } + + delete filePath; + + std::cout << "Created game process." << std::endl; + + ResumeThread(processInformation.hThread); + + return processInformation.hProcess; +} diff --git a/injector/src/util.cpp b/injector/src/util.cpp new file mode 100644 index 0000000..54f29c9 --- /dev/null +++ b/injector/src/util.cpp @@ -0,0 +1,107 @@ +#include "util.h" + +#include + +#include +#include + +//Returns the last Win32 error, in string format. Returns an empty string if there is no error. +std::string GetLastErrorAsString() +{ + //Get the error message ID, if any. + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) { + return std::string(); //No error message has been recorded + } + + LPSTR messageBuffer = nullptr; + + //Ask Win32 to give us the string version of that message ID. + //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + //Copy the error message into a std::string. + std::string message(messageBuffer, size); + + //Free the Win32's string's buffer. + LocalFree(messageBuffer); + + return message; +} + +std::string* GetFilePathByUser() { + + // common dialog box structure, setting all fields to 0 is important + OPENFILENAME ofn = { 0 }; + TCHAR szFile[260] = { 0 }; + + // Initialize remaining fields of OPENFILENAME structure + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "Executable\0*.exe\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + if (GetOpenFileName(&ofn) == TRUE) + { + return new std::string(szFile); + } + + return nullptr; +} + +int FindProcessId(const std::string& processName) { + int pid = -1; + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 process; + ZeroMemory(&process, sizeof(process)); + process.dwSize = sizeof(process); + + if (Process32First(snapshot, &process)) + { + do + { + if (std::string(process.szExeFile) == processName) + { + pid = process.th32ProcessID; + break; + } + } while (Process32Next(snapshot, &process)); + } + + CloseHandle(snapshot); + + return pid; +} + +void WaitForCloseProcess(const std::string& processName) { + int pid = FindProcessId(processName); + if (pid == -1) + return; + + std::cout << "Found '" << processName << "' process. Waiting for closing..." << std::endl; + +#ifdef _DEBUG + std::stringstream stream; + stream << "taskkill /F /T /IM " << processName; + int retval = system(stream.str().c_str()); + + std::cout << "Trying to kill process." << std::endl; +#endif + + HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + DWORD exitCode = 0; + while (hProc && (GetExitCodeProcess(hProc, &exitCode), exitCode == STILL_ACTIVE)) { + Sleep(1000); + } + + if (hProc != NULL) + CloseHandle(hProc); +} \ No newline at end of file diff --git a/injector/src/util.h b/injector/src/util.h new file mode 100644 index 0000000..c2b9415 --- /dev/null +++ b/injector/src/util.h @@ -0,0 +1,9 @@ +#include +#include + +#pragma once +std::string GetLastErrorAsString(); +std::string* GetFilePathByUser(); + +int FindProcessId(const std::string& processName); +void WaitForCloseProcess(const std::string& processName); \ No newline at end of file