mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added c++ configurator
This commit is contained in:
parent
fbd42ade6e
commit
532a83fe91
@ -4,9 +4,9 @@ cd src
|
||||
msbuild olympus.sln /t:Rebuild /p:Configuration=Release
|
||||
cd ..
|
||||
|
||||
cd scripts/python/configurator
|
||||
call build_configurator.bat
|
||||
cd ../../..
|
||||
cd configurator
|
||||
msbuild configurator.sln /t:Rebuild /p:Configuration=Release
|
||||
cd ..
|
||||
|
||||
cd client
|
||||
rmdir /s /q "hgt"
|
||||
|
||||
31
configurator/configurator.sln
Normal file
31
configurator/configurator.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32929.385
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "configurator", "configurator\configurator.vcxproj", "{FF484257-F6D1-43E9-B6BA-A892B86E8963}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Debug|x86.Build.0 = Debug|Win32
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Release|x64.Build.0 = Release|x64
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Release|x86.ActiveCfg = Release|Win32
|
||||
{FF484257-F6D1-43E9-B6BA-A892B86E8963}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {19612EF0-B177-4572-A304-ECE142C31BDC}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
170
configurator/configurator/configurator.cpp
Normal file
170
configurator/configurator/configurator.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
// configurator.cpp : This file contains the 'main' function. Program execution begins and ends there.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "argparse/argparse.hpp"
|
||||
#include "sha256.h"
|
||||
#include "windows.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace std;
|
||||
|
||||
struct MyArgs : public argparse::Args {
|
||||
string& address = kwarg("a", "Address");
|
||||
int& clientPort = kwarg("c", "Client port");
|
||||
int& backendPort = kwarg("b", "Backend port");
|
||||
string& gameMasterPassword = kwarg("p", "Game master password");
|
||||
string& blueCommanderPassword = kwarg("bp", "Blue commander password");
|
||||
string& redCommanderPassword = kwarg("rp", "Red commander password");
|
||||
};
|
||||
|
||||
void SetStdinEcho(bool enable = true)
|
||||
{
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD mode;
|
||||
GetConsoleMode(hStdin, &mode);
|
||||
|
||||
if (!enable)
|
||||
mode &= ~ENABLE_ECHO_INPUT;
|
||||
else
|
||||
mode |= ENABLE_ECHO_INPUT;
|
||||
|
||||
SetConsoleMode(hStdin, mode);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
cout << "DCS Olympus configurator v1.0.0" << endl << endl << endl;
|
||||
|
||||
SHA256 sha256;
|
||||
|
||||
std::ifstream f("olympus.json");
|
||||
json data = json::parse(f);
|
||||
|
||||
string address = data["server"]["address"];
|
||||
int clientPort = data["client"]["port"];
|
||||
int backendPort = data["server"]["port"];
|
||||
string gameMasterPassword = data["authentication"]["gameMasterPassword"];
|
||||
string blueCommanderPassword = data["authentication"]["blueCommanderPassword"];
|
||||
string redCommanderPassword = data["authentication"]["redCommanderPassword"];
|
||||
|
||||
if (argc > 1) {
|
||||
auto args = argparse::parse<MyArgs>(argc, argv);
|
||||
args.print(); // prints all variables
|
||||
|
||||
address = args.address;
|
||||
clientPort = args.clientPort;
|
||||
backendPort = args.backendPort;
|
||||
gameMasterPassword = sha256(args.gameMasterPassword);
|
||||
blueCommanderPassword = sha256(args.blueCommanderPassword);
|
||||
redCommanderPassword = sha256(args.redCommanderPassword);
|
||||
|
||||
} else {
|
||||
cout << "No arguments provided, running in interactive mode" << endl;
|
||||
|
||||
SetStdinEcho(true);
|
||||
|
||||
string newValue;
|
||||
|
||||
cout << "Insert a new address or press Enter to keep current value: " << address << endl << ">";
|
||||
getline(cin, newValue);
|
||||
if (newValue != "")
|
||||
address = newValue;
|
||||
|
||||
while (true) {
|
||||
cout << "Insert a new client port or press Enter to keep current value: " << clientPort << endl << ">";
|
||||
getline(cin, newValue);
|
||||
if (newValue != "") {
|
||||
try {
|
||||
clientPort = stoi(newValue);
|
||||
break;
|
||||
}
|
||||
catch (...) {
|
||||
cout << "Insert a valid integer number" << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
cout << "Insert a new backend port or press Enter to keep current value: " << backendPort << endl << ">";
|
||||
getline(cin, newValue);
|
||||
if (newValue != "") {
|
||||
try {
|
||||
backendPort = stoi(newValue);
|
||||
break;
|
||||
}
|
||||
catch (...) {
|
||||
cout << "Insert a valid integer number" << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
SetStdinEcho(false);
|
||||
|
||||
while (true) {
|
||||
cout << "Insert a new Game Master password" << endl << ">";
|
||||
getline(cin, newValue);
|
||||
cout << endl;
|
||||
if (newValue != "") {
|
||||
gameMasterPassword = sha256(newValue);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
cout << "Value can't be empty" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
cout << "Insert a new Blue Commander password" << endl << ">";
|
||||
getline(cin, newValue);
|
||||
cout << endl;
|
||||
if (newValue != "") {
|
||||
blueCommanderPassword = sha256(newValue);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
cout << "Value can't be empty" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
cout << "Insert a new Red Commander password" << endl << ">";
|
||||
getline(cin, newValue);
|
||||
cout << endl;
|
||||
if (newValue != "") {
|
||||
redCommanderPassword = sha256(newValue);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
cout << "Value can't be empty" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data["server"]["address"] = address;
|
||||
data["server"]["port"] = backendPort;
|
||||
data["authentication"]["gameMasterPassword"] = gameMasterPassword;
|
||||
data["authentication"]["blueCommanderPassword"] = blueCommanderPassword;
|
||||
data["authentication"]["redCommanderPassword"] = redCommanderPassword;
|
||||
data["client"]["port"] = clientPort;
|
||||
|
||||
std::ofstream o("olympus.json");
|
||||
o << std::setw(4) << data << std::endl;
|
||||
|
||||
cout << endl;
|
||||
cout << "Configuration updated successfully, bye!" << endl;
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(2000));
|
||||
}
|
||||
|
||||
143
configurator/configurator/configurator.vcxproj
Normal file
143
configurator/configurator/configurator.vcxproj
Normal file
@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{ff484257-f6d1-43e9-b6ba-a892b86e8963}</ProjectGuid>
|
||||
<RootNamespace>configurator</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>third-party\hash-library\include;third-party</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>third-party\hash-library\include;third-party</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="configurator.cpp" />
|
||||
<ClCompile Include="third-party\hash-library\src\sha256.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="argparse.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
30
configurator/configurator/configurator.vcxproj.filters
Normal file
30
configurator/configurator/configurator.vcxproj.filters
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="configurator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="third-party\hash-library\src\sha256.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="argparse.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
586
configurator/configurator/third-party/argparse/argparse.hpp
vendored
Normal file
586
configurator/configurator/third-party/argparse/argparse.hpp
vendored
Normal file
@ -0,0 +1,586 @@
|
||||
#pragma once
|
||||
//
|
||||
// @author : Morris Franken
|
||||
// https://github.com/morrisfranken/argparse
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
// obtaining a copy of the software and accompanying documentation covered by
|
||||
// this license (the "Software") to use, reproduce, display, distribute,
|
||||
// execute, and transmit the Software, and to prepare derivative works of the
|
||||
// Software, and to permit third-parties to whom the Software is furnished to
|
||||
// do so, all subject to the following:
|
||||
//
|
||||
// The copyright notices in the Software and this entire statement, including
|
||||
// the above license grant, this restriction and the following disclaimer,
|
||||
// must be included in all copies of the Software, in whole or in part, and
|
||||
// all derivative works of the Software, unless such copies or derivative
|
||||
// works are solely in the form of machine-executable object code generated by
|
||||
// a source language processor.
|
||||
//
|
||||
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#include <cctype> // for isdigit, tolower
|
||||
#include <sstream>
|
||||
#include <cstdlib> // for size_t, exit
|
||||
#include <algorithm> // for max, transform, copy, min
|
||||
#include <iomanip> // for operator<<, setw
|
||||
#include <iostream> // for operator<<, basic_ostream, endl, ostream
|
||||
#include <iterator> // for ostream_iterator
|
||||
#include <map> // for operator!=, map, _Rb_tree_iterator
|
||||
#include <memory> // for allocator, shared_ptr, __shared_ptr_ac...
|
||||
#include <optional> // for optional, nullopt
|
||||
#include <stdexcept> // for runtime_error, invalid_argument
|
||||
#include <filesystem> // for getting program_name from path
|
||||
#include <string> // for string, operator+, basic_string, char_...
|
||||
#include <type_traits> // for declval, false_type, true_type, is_enum
|
||||
#include <utility> // for move, pair
|
||||
#include <vector> // for vector
|
||||
|
||||
#if __has_include(<magic_enum.hpp>)
|
||||
#include <magic_enum.hpp> // for enum_entries
|
||||
#define HAS_MAGIC_ENUM
|
||||
#endif
|
||||
|
||||
#define ARGPARSE_VERSION 4
|
||||
|
||||
namespace argparse {
|
||||
class Args;
|
||||
using std::cout, std::cerr, std::endl, std::setw, std::size_t;
|
||||
|
||||
template<typename T> struct is_vector : public std::false_type {};
|
||||
template<typename T, typename A> struct is_vector<std::vector<T, A>> : public std::true_type {};
|
||||
|
||||
template<typename T> struct is_optional : public std::false_type {};
|
||||
template<typename T> struct is_optional<std::optional<T>> : public std::true_type {};
|
||||
|
||||
template<typename T> struct is_shared_ptr : public std::false_type {};
|
||||
template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : public std::true_type {};
|
||||
|
||||
template <typename, typename = void> struct has_ostream_operator : std::false_type {};
|
||||
template <typename T> struct has_ostream_operator<T, decltype(void(std::declval<std::ostream&>() << std::declval<const T&>()))> : std::true_type {};
|
||||
|
||||
inline std::string bold(const std::string& input_str) {
|
||||
#ifdef _WIN32
|
||||
return input_str; // no bold for windows
|
||||
#else
|
||||
return "\033[1m" + input_str + "\033[0m";
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> std::string toString(const T &v) {
|
||||
if constexpr (has_ostream_operator<T>::value) {
|
||||
return static_cast<std::ostringstream &&>((std::ostringstream() << std::boolalpha << v)).str(); // https://github.com/stan-dev/math/issues/590#issuecomment-550122627
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> inline split(const std::string &str) {
|
||||
std::vector<std::string> splits;
|
||||
std::stringstream ss(str);
|
||||
std::string key;
|
||||
while (std::getline(ss, key, ',')) {
|
||||
if (!key.empty() && key.back() == '\0')
|
||||
key.pop_back(); // last variables contain a '\0', which is unexpected when comparing to raw string, e.g. value == "test" will fail when the last character is '\0'. Therefore we can remove it
|
||||
splits.emplace_back(std::move(key));
|
||||
}
|
||||
return splits;
|
||||
}
|
||||
|
||||
template <typename T> std::string to_lower(const T &str_) { // both std::string and std::basic_string_view<char> (for magic_enum) are using to_lower
|
||||
std::string str(str_.size(), '\0');
|
||||
std::transform(str_.begin(), str_.end(), str.begin(), ::tolower);
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename T> inline T get(const std::string &v);
|
||||
template<> inline std::string get(const std::string &v) { return v; }
|
||||
template<> inline char get(const std::string &v) { return v.empty()? throw std::invalid_argument("empty string") : v.size() > 1? v.substr(0,2) == "0x"? (char)std::stoul(v, nullptr, 16) : (char)std::stoi(v) : v[0]; }
|
||||
template<> inline int get(const std::string &v) { return std::stoi(v); }
|
||||
template<> inline short get(const std::string &v) { return std::stoi(v); }
|
||||
template<> inline long get(const std::string &v) { return std::stol(v); }
|
||||
template<> inline bool get(const std::string &v) { return to_lower(v) == "true" || v == "1"; }
|
||||
template<> inline float get(const std::string &v) { return std::stof(v); }
|
||||
template<> inline double get(const std::string &v) { return std::stod(v); }
|
||||
template<> inline unsigned char get(const std::string &v) { return get<char>(v); }
|
||||
template<> inline unsigned int get(const std::string &v) { return std::stoul(v); }
|
||||
template<> inline unsigned short get(const std::string &v) { return std::stoul(v); }
|
||||
template<> inline unsigned long get(const std::string &v) { return std::stoul(v); }
|
||||
|
||||
template<typename T> inline T get(const std::string &v) { // remaining types
|
||||
if constexpr (is_vector<T>::value) {
|
||||
const std::vector<std::string> splitted = split(v);
|
||||
T res(splitted.size());
|
||||
if (!v.empty())
|
||||
std::transform (splitted.begin(), splitted.end(), res.begin(), get<typename T::value_type>);
|
||||
return res;
|
||||
} else if constexpr (std::is_pointer<T>::value) {
|
||||
return new typename std::remove_pointer<T>::type(get<typename std::remove_pointer<T>::type>(v));
|
||||
} else if constexpr (is_shared_ptr<T>::value) {
|
||||
return std::make_shared<typename T::element_type>(get<typename T::element_type>(v));
|
||||
} else if constexpr (is_optional<T>::value) {
|
||||
return get<typename T::value_type>(v);
|
||||
} else if constexpr (std::is_enum<T>::value) { // case-insensitive enum conversion
|
||||
#ifdef HAS_MAGIC_ENUM
|
||||
constexpr auto& enum_entries = magic_enum::enum_entries<T>();
|
||||
const std::string lower_str = to_lower(v);
|
||||
for (const auto &[value, name] : enum_entries) {
|
||||
if (to_lower(name) == lower_str)
|
||||
return value;
|
||||
}
|
||||
std::string error = "enum is only accepting [";
|
||||
for (size_t i = 0; i < enum_entries.size(); i++)
|
||||
error += (i==0? "" : ", ") + to_lower(enum_entries[i].second);
|
||||
error += "]";
|
||||
throw std::runtime_error(error);
|
||||
#else
|
||||
throw std::runtime_error("Enum not supported, please install magic_enum (https://github.com/Neargye/magic_enum)");
|
||||
#endif
|
||||
} else {
|
||||
return T(v);
|
||||
}
|
||||
}
|
||||
|
||||
struct ConvertBase {
|
||||
virtual ~ConvertBase() = default;
|
||||
virtual void convert(const std::string &v) = 0;
|
||||
virtual void set_default(const std::unique_ptr<ConvertBase> &default_value, const std::string &default_string) = 0;
|
||||
[[nodiscard]] virtual size_t get_type_id() const = 0;
|
||||
[[nodiscard]] virtual std::string get_allowed_entries() const = 0;
|
||||
};
|
||||
|
||||
template <typename T> struct ConvertType : public ConvertBase {
|
||||
T data;
|
||||
~ConvertType() override = default;
|
||||
ConvertType() : ConvertBase() {};
|
||||
explicit ConvertType(const T &value) : ConvertBase(), data(value) {};
|
||||
|
||||
void convert(const std::string &v) override {
|
||||
data = get<T>(v);
|
||||
}
|
||||
|
||||
void set_default(const std::unique_ptr<ConvertBase> &default_value, const std::string &default_string) override {
|
||||
if (this->get_type_id() == default_value->get_type_id()) // When the types do not match exactly. resort to string conversion
|
||||
data = ((ConvertType<T>*)(default_value.get()))->data;
|
||||
else
|
||||
data = get<T>(default_string);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t get_type_id() const override {
|
||||
return typeid(T).hash_code();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string get_allowed_entries() const override {
|
||||
std::stringstream ss;
|
||||
|
||||
#ifdef HAS_MAGIC_ENUM
|
||||
if constexpr (std::is_enum<T>::value) {
|
||||
for (const auto &[value, name] : magic_enum::enum_entries<T>()) {
|
||||
ss << to_lower(name) << ", ";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
enum ARG_TYPE {ARG, KWARG, FLAG} type;
|
||||
|
||||
Entry(ARG_TYPE type, const std::string& key, std::string help, std::optional<std::string> implicit_value=std::nullopt) :
|
||||
type(type),
|
||||
keys_(split(key)),
|
||||
help(std::move(help)),
|
||||
implicit_value_(std::move(implicit_value)) {
|
||||
}
|
||||
|
||||
// Allow both string inputs and direct-type inputs. Where a string-input will be converted like it would when using the commandline, and the direct approach is to simply use the value provided.
|
||||
template <typename T> Entry &set_default(const T &default_value) {
|
||||
this->default_str_ = toString(default_value);
|
||||
if constexpr (!(std::is_array<T>::value || std::is_same<typename std::remove_all_extents<T>::type, char>::value)) {
|
||||
data_default = std::make_unique<ConvertType<T>>(default_value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Entry &multi_argument() {
|
||||
_is_multi_argument = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Magically convert the value string to the requested type
|
||||
template <typename T> operator T&() {
|
||||
// Automatically set the default to nullptr for pointer types and empty for optional types
|
||||
if constexpr (is_optional<T>::value || std::is_pointer<T>::value || is_shared_ptr<T>::value) {
|
||||
if (!default_str_.has_value()) {
|
||||
default_str_ = "none";
|
||||
if constexpr(is_optional<T>::value) {
|
||||
data_default = std::make_unique<ConvertType<T>> (T{std::nullopt});
|
||||
} else {
|
||||
data_default = std::make_unique<ConvertType<T>> ((T) nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
datap = std::make_unique<ConvertType<T>>();
|
||||
return ((ConvertType<T>*)(datap.get()))->data;
|
||||
}
|
||||
|
||||
// Force an ambiguous error when not using a reference.
|
||||
template <typename T> operator T() {} // When you get here because you received an error, make sure all parameters of argparse are references (e.g. with `&`)
|
||||
|
||||
private:
|
||||
std::vector<std::string> keys_;
|
||||
std::string help;
|
||||
std::optional<std::string> value_;
|
||||
std::optional<std::string> implicit_value_;
|
||||
std::optional<std::string> default_str_;
|
||||
std::string error;
|
||||
std::unique_ptr<ConvertBase> datap;
|
||||
std::unique_ptr<ConvertBase> data_default;
|
||||
bool _is_multi_argument = false;
|
||||
bool is_set_by_user = true;
|
||||
|
||||
[[nodiscard]] std::string _get_keys() const {
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < keys_.size(); i++)
|
||||
ss << (i? "," : "") << (type == ARG? "" : (keys_[i].size() > 1 ? "--" : "-")) + keys_[i];
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void _convert(const std::string &value) {
|
||||
try {
|
||||
this->value_ = value;
|
||||
datap->convert(value);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
error = "Invalid argument, could not convert \"" + value + "\" for " + _get_keys() + " (" + help + ")";
|
||||
} catch (const std::runtime_error &e) {
|
||||
error = "Invalid argument \"" + value + "\" for " + _get_keys() + " (" + help + "). Error: " + e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void _apply_default() {
|
||||
is_set_by_user = false;
|
||||
if (data_default != nullptr) {
|
||||
value_ = *default_str_; // for printing
|
||||
datap->set_default(data_default, *default_str_);
|
||||
} else if (default_str_.has_value()) { // in cases where a string is provided to the `set_default` function
|
||||
_convert(default_str_.value());
|
||||
} else {
|
||||
error = "Argument missing: " + _get_keys() + " (" + help + ")";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string info() const {
|
||||
const std::string allowed_entries = datap->get_allowed_entries();
|
||||
const std::string default_value = default_str_.has_value() ? "default: " + *default_str_ : "required";
|
||||
const std::string implicit_value = implicit_value_.has_value() ? "implicit: \"" + *implicit_value_ + "\", ": "";
|
||||
const std::string allowed_value = !allowed_entries.empty()? "allowed: <" + allowed_entries.substr(0, allowed_entries.size()-2) + ">, ": "";
|
||||
return " [" + allowed_value + implicit_value + default_value + "]";
|
||||
}
|
||||
|
||||
friend class Args;
|
||||
};
|
||||
|
||||
struct SubcommandEntry {
|
||||
std::shared_ptr<Args> subargs;
|
||||
std::string subcommand_name;
|
||||
|
||||
explicit SubcommandEntry(std::string subcommand_name) : subcommand_name(std::move(subcommand_name)) {}
|
||||
|
||||
template<typename T> operator T &() {
|
||||
static_assert(std::is_base_of_v<Args, T>, "Subcommand type must be a derivative of argparse::Args");
|
||||
|
||||
std::shared_ptr<T> res = std::make_shared<T>();
|
||||
res->program_name = subcommand_name;
|
||||
subargs = res;
|
||||
return *(T*)(subargs.get());
|
||||
}
|
||||
|
||||
// Force an ambiguous error when not using a reference.
|
||||
template <typename T> operator T() {} // When you get here because you received an error, make sure all parameters of argparse are references (e.g. with `&`)
|
||||
};
|
||||
|
||||
class Args {
|
||||
private:
|
||||
size_t _arg_idx = 0;
|
||||
std::vector<std::string> params;
|
||||
std::vector<std::shared_ptr<Entry>> all_entries;
|
||||
std::map<std::string, std::shared_ptr<Entry>> kwarg_entries;
|
||||
std::vector<std::shared_ptr<Entry>> arg_entries;
|
||||
std::map<std::string, std::shared_ptr<SubcommandEntry>> subcommand_entries;
|
||||
|
||||
public:
|
||||
std::string program_name;
|
||||
bool is_valid = false;
|
||||
|
||||
virtual ~Args() = default;
|
||||
|
||||
/* Add a positional argument, the order in which it is defined equals the order in which they are being read.
|
||||
* help : Description of the variable
|
||||
*
|
||||
* Returns a reference to the Entry, which will collapse into the requested type in `Entry::operator T()`
|
||||
*/
|
||||
Entry &arg(const std::string &help) {
|
||||
return arg("arg_" + std::to_string(_arg_idx), help);
|
||||
}
|
||||
|
||||
/* Add a *named* positional argument, the order in which it is defined equals the order in which they are being read.
|
||||
* key : The name of the argument, otherwise arg_<position> will be used
|
||||
* help : Description of the variable
|
||||
*
|
||||
* Returns a reference to the Entry, which will collapse into the requested type in `Entry::operator T()`
|
||||
*/
|
||||
Entry &arg(const std::string& key, const std::string &help) {
|
||||
std::shared_ptr<Entry> entry = std::make_shared<Entry>(Entry::ARG, key, help);
|
||||
// Increasing _arg_idx, so that arg2 will be arg_2, irregardless of whether it is preceded by other positional arguments
|
||||
_arg_idx++;
|
||||
arg_entries.emplace_back(entry);
|
||||
all_entries.emplace_back(entry);
|
||||
return *entry;
|
||||
}
|
||||
|
||||
/* Add a Key-Worded argument that takes a variable.
|
||||
* key : A comma-separated string, e.g. "k,key", which denotes the short (-k) and long(--key) keys_
|
||||
* help : Description of the variable
|
||||
* implicit_value : Implicit values are used when no value is provided.
|
||||
*
|
||||
* Returns a reference to the Entry, which will collapse into the requested type in `Entry::operator T()`
|
||||
*/
|
||||
Entry &kwarg(const std::string &key, const std::string &help, const std::optional<std::string>& implicit_value=std::nullopt) {
|
||||
std::shared_ptr<Entry> entry = std::make_shared<Entry>(Entry::KWARG, key, help, implicit_value);
|
||||
all_entries.emplace_back(entry);
|
||||
for (const std::string &k : entry->keys_) {
|
||||
kwarg_entries[k] = entry;
|
||||
}
|
||||
return *entry;
|
||||
}
|
||||
|
||||
/* Add a flag which will be false by default.
|
||||
* key : A comma-separated string, e.g. "k,key", which denotes the short (-k) and long(--key) keys_
|
||||
* help : Description of the variable
|
||||
*
|
||||
* Returns reference to Entry like kwarg
|
||||
*/
|
||||
Entry &flag(const std::string &key, const std::string &help) {
|
||||
return kwarg(key, help, "true").set_default<bool>(false);
|
||||
}
|
||||
|
||||
/* Add a a subcommand
|
||||
* command : name of the subcommand, e.g. 'commit', if you wish to implement a function like 'git commit'
|
||||
*
|
||||
* Returns a reference to the Entry, which will collapse into the requested type in `Entry::operator T()`
|
||||
* Expected type *Must* be an std::shared_ptr of derivative of the argparse::Args class
|
||||
*/
|
||||
SubcommandEntry &subcommand(const std::string &command) {
|
||||
std::shared_ptr<SubcommandEntry> entry = std::make_shared<SubcommandEntry>(command);
|
||||
subcommand_entries[command] = entry;
|
||||
return *entry;
|
||||
}
|
||||
|
||||
virtual void welcome() {} // Allow to overwrite the `welcome` function to add a welcome-message to the help output
|
||||
virtual void help() {
|
||||
welcome();
|
||||
cout << "Usage: " << program_name << " ";
|
||||
for (const auto &entry : arg_entries)
|
||||
cout << entry->keys_[0] << ' ';
|
||||
cout << " [options...]";
|
||||
if (!subcommand_entries.empty()) {
|
||||
cout << " [SUBCOMMAND: ";
|
||||
for (const auto &[subcommand, subentry]: subcommand_entries) {
|
||||
cout << subcommand << ", ";
|
||||
}
|
||||
cout << "]";
|
||||
}
|
||||
cout << endl;
|
||||
for (const auto &entry : arg_entries) {
|
||||
cout << setw(17) << entry->keys_[0] << " : " << entry->help << entry->info() << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Options:" << endl;
|
||||
for (const auto &entry : all_entries) {
|
||||
if (entry->type != Entry::ARG) {
|
||||
cout << setw(17) << entry->_get_keys() << " : " << entry->help << entry->info() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[subcommand, subentry] : subcommand_entries) {
|
||||
cout << endl << endl << bold("Subcommand: ") << bold(subcommand) << endl;
|
||||
subentry->subargs->help();
|
||||
}
|
||||
}
|
||||
|
||||
void validate(const bool &raise_on_error) {
|
||||
for (const auto &entry : all_entries) {
|
||||
if (!entry->error.empty()) {
|
||||
if (raise_on_error) {
|
||||
throw std::runtime_error(entry->error);
|
||||
} else {
|
||||
std::cerr << entry->error << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse all parameters and also check for the help_flag which was set in this constructor
|
||||
* Upon error, it will print the error and exit immediately if validation_action is ValidationAction::EXIT_ON_ERROR
|
||||
*/
|
||||
void parse(int argc, const char* const *argv, const bool &raise_on_error) {
|
||||
auto parse_subcommands = [&]() -> int {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
for (auto &[subcommand, subentry] : subcommand_entries) {
|
||||
if (subcommand == argv[i]) {
|
||||
subentry->subargs->parse(argc - i, argv + i, raise_on_error);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
};
|
||||
argc = parse_subcommands(); // argc_ is the number of arguments that should be parsed after the subcommand has finished parsing
|
||||
|
||||
program_name = std::filesystem::path(argv[0]).stem().string();
|
||||
params = std::vector<std::string>(argv + 1, argv + argc);
|
||||
|
||||
bool& _help = flag("?,help", "print help");
|
||||
|
||||
auto is_value = [&](const size_t &i) -> bool {
|
||||
return params.size() > i && (params[i][0] != '-' || (params[i].size() > 1 && std::isdigit(params[i][1]))); // check for number to not accidentally mark negative numbers as non-parameter
|
||||
};
|
||||
auto parse_param = [&](size_t &i, const std::string &key, const bool is_short, const std::optional<std::string> &equal_value=std::nullopt) {
|
||||
auto itt = kwarg_entries.find(key);
|
||||
if (itt != kwarg_entries.end()) {
|
||||
auto &entry = itt->second;
|
||||
if (equal_value.has_value()) {
|
||||
entry->_convert(equal_value.value());
|
||||
} else if (entry->implicit_value_.has_value()) {
|
||||
entry->_convert(*entry->implicit_value_);
|
||||
} else if (!is_short) { // short values are not allowed to look ahead for the next parameter
|
||||
if (is_value(i + 1)) {
|
||||
std::string value = params[++i];
|
||||
if (entry->_is_multi_argument) {
|
||||
while (is_value(i + 1))
|
||||
value += "," + params[++i];
|
||||
}
|
||||
entry->_convert(value);
|
||||
} else if (entry->_is_multi_argument) {
|
||||
entry->_convert(""); // for multiargument parameters, return an empty vector when not passing any more values
|
||||
} else {
|
||||
entry->error = "No value provided for: " + key;
|
||||
}
|
||||
} else {
|
||||
entry->error = "No value provided for: " + key;
|
||||
}
|
||||
} else {
|
||||
cerr << "unrecognised commandline argument: " << key << endl;
|
||||
}
|
||||
};
|
||||
auto add_param = [&](size_t &i, const size_t &start) {
|
||||
size_t eq_idx = params[i].find('='); // check if value was passed using the '=' sign
|
||||
if (eq_idx != std::string::npos) { // key/value from = notation
|
||||
std::string key = params[i].substr(start, eq_idx - start);
|
||||
std::string value = params[i].substr(eq_idx + 1);
|
||||
parse_param(i, key, false, value);
|
||||
} else {
|
||||
std::string key = std::string(params[i].substr(start));
|
||||
parse_param(i, key, false);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::string> arguments_flat;
|
||||
for (size_t i = 0; i < params.size(); i++) {
|
||||
if (!is_value(i)) {
|
||||
if (params[i].size() > 1 && params[i][1] == '-') { // long --
|
||||
add_param(i, 2);
|
||||
} else { // short -
|
||||
const size_t j_end = std::min(params[i].size(), params[i].find('=')) - 1;
|
||||
for (size_t j = 1; j < j_end; j++) { // add possible other flags
|
||||
const std::string key = std::string(1, params[i][j]);
|
||||
parse_param(i, key, true);
|
||||
}
|
||||
add_param(i, j_end);
|
||||
}
|
||||
} else {
|
||||
arguments_flat.emplace_back(params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all the positional arguments, making sure multi_argument positional arguments are processed last to enable arguments afterwards
|
||||
size_t arg_i = 0;
|
||||
for (; arg_i < arg_entries.size() && !arg_entries[arg_i]->_is_multi_argument; arg_i++) { // iterate over positional arguments until a multi-argument is found
|
||||
if (arg_i < arguments_flat.size())
|
||||
arg_entries[arg_i]->_convert(arguments_flat[arg_i]);
|
||||
}
|
||||
size_t arg_j = 1;
|
||||
for (size_t j_end = arg_entries.size() - arg_i; arg_j <= j_end; arg_j++) { // iterate from back to front, to ensure non-multi-arguments in the front and back are given preference
|
||||
size_t flat_idx = arguments_flat.size() - arg_j;
|
||||
if (flat_idx < arguments_flat.size() && flat_idx >= arg_i) {
|
||||
if (arg_entries[arg_entries.size() - arg_j]->_is_multi_argument) {
|
||||
std::stringstream s; // Combine multiple arguments into 1 comma-separated string for parsing
|
||||
copy(&arguments_flat[arg_i],&arguments_flat[flat_idx] + 1, std::ostream_iterator<std::string>(s,","));
|
||||
std::string value = s.str();
|
||||
value.back() = '\0'; // remove trailing ','
|
||||
arg_entries[arg_i]->_convert(value);
|
||||
} else {
|
||||
arg_entries[arg_entries.size() - arg_j]->_convert(arguments_flat[flat_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try to apply default values for arguments which have not been set
|
||||
for (const auto &entry : all_entries) {
|
||||
if (!entry->value_.has_value()) {
|
||||
entry->_apply_default();
|
||||
}
|
||||
}
|
||||
|
||||
if (_help) {
|
||||
help();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
validate(raise_on_error);
|
||||
is_valid = true;
|
||||
}
|
||||
|
||||
void print() const {
|
||||
for (const auto &entry : all_entries) {
|
||||
std::string snip = entry->type == Entry::ARG ? "(" + (entry->help.size() > 10 ? entry->help.substr(0, 7) + "..." : entry->help) + ")" : "";
|
||||
cout << setw(21) << entry->_get_keys() + snip << " : " << (entry->is_set_by_user? bold(entry->value_.value_or("null")) : entry->value_.value_or("null")) << endl;
|
||||
}
|
||||
|
||||
for (const auto &[subcommand, subentry] : subcommand_entries) {
|
||||
if (subentry->subargs->is_valid) {
|
||||
cout << endl << "--- Subcommand: " << subcommand << endl;
|
||||
subentry->subargs->print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual int run() {return 0;} // For automatically running subcommands
|
||||
int run_subcommands() {
|
||||
for (const auto &[subcommand, subentry] : subcommand_entries) {
|
||||
if (subentry->subargs->is_valid) {
|
||||
return subentry->subargs->run();
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "No subcommand provided" << std::endl;
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> T parse(int argc, const char* const *argv, const bool &raise_on_error=false) {
|
||||
T args = T();
|
||||
args.parse(argc, argv, raise_on_error);
|
||||
return args;
|
||||
}
|
||||
}
|
||||
10
configurator/configurator/third-party/hash-library/LICENSE
vendored
Normal file
10
configurator/configurator/third-party/hash-library/LICENSE
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
zlib License
|
||||
|
||||
Copyright (c) 2014,2015 Stephan Brumme
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
69
configurator/configurator/third-party/hash-library/include/crc32.h
vendored
Normal file
69
configurator/configurator/third-party/hash-library/include/crc32.h
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// crc32.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute CRC32 hash, based on Intel's Slicing-by-8 algorithm
|
||||
/** Usage:
|
||||
CRC32 crc32;
|
||||
std::string myHash = crc32("Hello World"); // std::string
|
||||
std::string myHash2 = crc32("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
CRC32 crc32;
|
||||
while (more data available)
|
||||
crc32.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = crc32.getHash();
|
||||
|
||||
Note:
|
||||
You can find code for the faster Slicing-by-16 algorithm on my website, too:
|
||||
http://create.stephan-brumme.com/crc32/
|
||||
Its unrolled version is about twice as fast but its look-up table doubled in size as well.
|
||||
*/
|
||||
class CRC32 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// hash is 4 bytes long
|
||||
enum { HashBytes = 4 };
|
||||
|
||||
/// same as reset()
|
||||
CRC32();
|
||||
|
||||
/// compute CRC32 of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute CRC32 of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as 8 hex characters
|
||||
std::string getHash();
|
||||
/// return latest hash as bytes
|
||||
void getHash(unsigned char buffer[HashBytes]);
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// hash
|
||||
uint32_t m_hash;
|
||||
};
|
||||
28
configurator/configurator/third-party/hash-library/include/hash.h
vendored
Normal file
28
configurator/configurator/third-party/hash-library/include/hash.h
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// hash.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/// abstract base class
|
||||
class Hash
|
||||
{
|
||||
public:
|
||||
/// compute hash of a memory block
|
||||
virtual std::string operator()(const void* data, size_t numBytes) = 0;
|
||||
/// compute hash of a string, excluding final zero
|
||||
virtual std::string operator()(const std::string& text) = 0;
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
virtual void add(const void* data, size_t numBytes) = 0;
|
||||
|
||||
/// return latest hash as hex characters
|
||||
virtual std::string getHash() = 0;
|
||||
|
||||
/// restart
|
||||
virtual void reset() = 0;
|
||||
};
|
||||
83
configurator/configurator/third-party/hash-library/include/hmac.h
vendored
Normal file
83
configurator/configurator/third-party/hash-library/include/hmac.h
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// hmac.h
|
||||
// Copyright (c) 2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// based on http://tools.ietf.org/html/rfc2104
|
||||
// see also http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
||||
|
||||
/** Usage:
|
||||
std::string msg = "The quick brown fox jumps over the lazy dog";
|
||||
std::string key = "key";
|
||||
std::string md5hmac = hmac< MD5 >(msg, key);
|
||||
std::string sha1hmac = hmac< SHA1 >(msg, key);
|
||||
std::string sha2hmac = hmac<SHA256>(msg, key);
|
||||
|
||||
Note:
|
||||
To keep my code simple, HMAC computation currently needs the whole message at once.
|
||||
This is in contrast to the hashes MD5, SHA1, etc. where an add() method is available
|
||||
for incremental computation.
|
||||
You can use any hash for HMAC as long as it provides:
|
||||
- constant HashMethod::BlockSize (typically 64)
|
||||
- constant HashMethod::HashBytes (length of hash in bytes, e.g. 20 for SHA1)
|
||||
- HashMethod::add(buffer, bufferSize)
|
||||
- HashMethod::getHash(unsigned char buffer[HashMethod::BlockSize])
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <cstring> // memcpy
|
||||
|
||||
/// compute HMAC hash of data and key using MD5, SHA1 or SHA256
|
||||
template <typename HashMethod>
|
||||
std::string hmac(const void* data, size_t numDataBytes, const void* key, size_t numKeyBytes)
|
||||
{
|
||||
// initialize key with zeros
|
||||
unsigned char usedKey[HashMethod::BlockSize] = {0};
|
||||
|
||||
// adjust length of key: must contain exactly blockSize bytes
|
||||
if (numKeyBytes <= HashMethod::BlockSize)
|
||||
{
|
||||
// copy key
|
||||
memcpy(usedKey, key, numKeyBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shorten key: usedKey = hashed(key)
|
||||
HashMethod keyHasher;
|
||||
keyHasher.add(key, numKeyBytes);
|
||||
keyHasher.getHash(usedKey);
|
||||
}
|
||||
|
||||
// create initial XOR padding
|
||||
for (size_t i = 0; i < HashMethod::BlockSize; i++)
|
||||
usedKey[i] ^= 0x36;
|
||||
|
||||
// inside = hash((usedKey ^ 0x36) + data)
|
||||
unsigned char inside[HashMethod::HashBytes];
|
||||
HashMethod insideHasher;
|
||||
insideHasher.add(usedKey, HashMethod::BlockSize);
|
||||
insideHasher.add(data, numDataBytes);
|
||||
insideHasher.getHash(inside);
|
||||
|
||||
// undo usedKey's previous 0x36 XORing and apply a XOR by 0x5C
|
||||
for (size_t i = 0; i < HashMethod::BlockSize; i++)
|
||||
usedKey[i] ^= 0x5C ^ 0x36;
|
||||
|
||||
// hash((usedKey ^ 0x5C) + hash((usedKey ^ 0x36) + data))
|
||||
HashMethod finalHasher;
|
||||
finalHasher.add(usedKey, HashMethod::BlockSize);
|
||||
finalHasher.add(inside, HashMethod::HashBytes);
|
||||
|
||||
return finalHasher.getHash();
|
||||
}
|
||||
|
||||
|
||||
/// convenience function for std::string
|
||||
template <typename HashMethod>
|
||||
std::string hmac(const std::string& data, const std::string& key)
|
||||
{
|
||||
return hmac<HashMethod>(data.c_str(), data.size(), key.c_str(), key.size());
|
||||
}
|
||||
81
configurator/configurator/third-party/hash-library/include/keccak.h
vendored
Normal file
81
configurator/configurator/third-party/hash-library/include/keccak.h
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// keccak.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute Keccak hash (designated SHA3)
|
||||
/** Usage:
|
||||
Keccak keccak;
|
||||
std::string myHash = keccak("Hello World"); // std::string
|
||||
std::string myHash2 = keccak("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
Keccak keccak;
|
||||
while (more data available)
|
||||
keccak.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = keccak.getHash();
|
||||
*/
|
||||
class Keccak //: public Hash
|
||||
{
|
||||
public:
|
||||
/// algorithm variants
|
||||
enum Bits { Keccak224 = 224, Keccak256 = 256, Keccak384 = 384, Keccak512 = 512 };
|
||||
|
||||
/// same as reset()
|
||||
explicit Keccak(Bits bits = Keccak256);
|
||||
|
||||
/// compute hash of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute hash of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as hex characters
|
||||
std::string getHash();
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process a full block
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224)
|
||||
enum { StateSize = 1600 / (8 * 8),
|
||||
MaxBlockSize = 200 - 2 * (224 / 8) };
|
||||
|
||||
/// hash
|
||||
uint64_t m_hash[StateSize];
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// block size (less or equal to MaxBlockSize)
|
||||
size_t m_blockSize;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[MaxBlockSize];
|
||||
/// variant
|
||||
Bits m_bits;
|
||||
};
|
||||
78
configurator/configurator/third-party/hash-library/include/md5.h
vendored
Normal file
78
configurator/configurator/third-party/hash-library/include/md5.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// md5.h
|
||||
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute MD5 hash
|
||||
/** Usage:
|
||||
MD5 md5;
|
||||
std::string myHash = md5("Hello World"); // std::string
|
||||
std::string myHash2 = md5("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
MD5 md5;
|
||||
while (more data available)
|
||||
md5.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = md5.getHash();
|
||||
*/
|
||||
class MD5 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long
|
||||
enum { BlockSize = 512 / 8, HashBytes = 16 };
|
||||
|
||||
/// same as reset()
|
||||
MD5();
|
||||
|
||||
/// compute MD5 of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute MD5 of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as 32 hex characters
|
||||
std::string getHash();
|
||||
/// return latest hash as bytes
|
||||
void getHash(unsigned char buffer[HashBytes]);
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process 64 bytes
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[BlockSize];
|
||||
|
||||
enum { HashValues = HashBytes / 4 };
|
||||
/// hash, stored as integers
|
||||
uint32_t m_hash[HashValues];
|
||||
};
|
||||
78
configurator/configurator/third-party/hash-library/include/sha1.h
vendored
Normal file
78
configurator/configurator/third-party/hash-library/include/sha1.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha1.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute SHA1 hash
|
||||
/** Usage:
|
||||
SHA1 sha1;
|
||||
std::string myHash = sha1("Hello World"); // std::string
|
||||
std::string myHash2 = sha1("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
SHA1 sha1;
|
||||
while (more data available)
|
||||
sha1.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = sha1.getHash();
|
||||
*/
|
||||
class SHA1 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// split into 64 byte blocks (=> 512 bits), hash is 20 bytes long
|
||||
enum { BlockSize = 512 / 8, HashBytes = 20 };
|
||||
|
||||
/// same as reset()
|
||||
SHA1();
|
||||
|
||||
/// compute SHA1 of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute SHA1 of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as 40 hex characters
|
||||
std::string getHash();
|
||||
/// return latest hash as bytes
|
||||
void getHash(unsigned char buffer[HashBytes]);
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process 64 bytes
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[BlockSize];
|
||||
|
||||
enum { HashValues = HashBytes / 4 };
|
||||
/// hash, stored as integers
|
||||
uint32_t m_hash[HashValues];
|
||||
};
|
||||
78
configurator/configurator/third-party/hash-library/include/sha256.h
vendored
Normal file
78
configurator/configurator/third-party/hash-library/include/sha256.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha256.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute SHA256 hash
|
||||
/** Usage:
|
||||
SHA256 sha256;
|
||||
std::string myHash = sha256("Hello World"); // std::string
|
||||
std::string myHash2 = sha256("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
SHA256 sha256;
|
||||
while (more data available)
|
||||
sha256.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = sha256.getHash();
|
||||
*/
|
||||
class SHA256 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// split into 64 byte blocks (=> 512 bits), hash is 32 bytes long
|
||||
enum { BlockSize = 512 / 8, HashBytes = 32 };
|
||||
|
||||
/// same as reset()
|
||||
SHA256();
|
||||
|
||||
/// compute SHA256 of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute SHA256 of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as 64 hex characters
|
||||
std::string getHash();
|
||||
/// return latest hash as bytes
|
||||
void getHash(unsigned char buffer[HashBytes]);
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process 64 bytes
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[BlockSize];
|
||||
|
||||
enum { HashValues = HashBytes / 4 };
|
||||
/// hash, stored as integers
|
||||
uint32_t m_hash[HashValues];
|
||||
};
|
||||
81
configurator/configurator/third-party/hash-library/include/sha3.h
vendored
Normal file
81
configurator/configurator/third-party/hash-library/include/sha3.h
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha3.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute SHA3 hash
|
||||
/** Usage:
|
||||
SHA3 sha3;
|
||||
std::string myHash = sha3("Hello World"); // std::string
|
||||
std::string myHash2 = sha3("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
SHA3 sha3;
|
||||
while (more data available)
|
||||
sha3.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = sha3.getHash();
|
||||
*/
|
||||
class SHA3 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// algorithm variants
|
||||
enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 };
|
||||
|
||||
/// same as reset()
|
||||
explicit SHA3(Bits bits = Bits256);
|
||||
|
||||
/// compute hash of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute hash of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as hex characters
|
||||
std::string getHash();
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process a full block
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224)
|
||||
enum { StateSize = 1600 / (8 * 8),
|
||||
MaxBlockSize = 200 - 2 * (224 / 8) };
|
||||
|
||||
/// hash
|
||||
uint64_t m_hash[StateSize];
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// block size (less or equal to MaxBlockSize)
|
||||
size_t m_blockSize;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[MaxBlockSize];
|
||||
/// variant
|
||||
Bits m_bits;
|
||||
};
|
||||
51
configurator/configurator/third-party/hash-library/readme.md
vendored
Normal file
51
configurator/configurator/third-party/hash-library/readme.md
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
# Portable C++ Hashing Library
|
||||
|
||||
This is a mirror of my library hosted at https://create.stephan-brumme.com/hash-library/
|
||||
|
||||
In a nutshell:
|
||||
|
||||
- computes CRC32, MD5, SHA1 and SHA256 (most common member of the SHA2 functions), Keccak and its SHA3 sibling
|
||||
- optional HMAC (keyed-hash message authentication code)
|
||||
- no external dependencies, small code size
|
||||
- can work chunk-wise (for example when reading streams block-by-block)
|
||||
- portable: supports Windows and Linux, tested on Little Endian and Big Endian CPUs
|
||||
- roughly as fast as Linux core hashing functions
|
||||
- open source, zlib license
|
||||
|
||||
You can find code examples, benchmarks and much more on my website https://create.stephan-brumme.com/hash-library/
|
||||
|
||||
# How to use
|
||||
|
||||
This example computes SHA256 hashes but the API is more or less identical for all hash algorithms:
|
||||
|
||||
``` cpp
|
||||
// SHA2 test program
|
||||
#include "sha256.h"
|
||||
#include <iostream> // for std::cout only, not needed for hashing library
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// create a new hashing object
|
||||
SHA256 sha256;
|
||||
|
||||
// hashing an std::string
|
||||
std::cout << sha256("Hello World") << std::endl;
|
||||
// => a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
|
||||
|
||||
// hashing a buffer of bytes
|
||||
const char* buffer = "How are you";
|
||||
std::cout << sha256(buffer, 11) << std::endl;
|
||||
// => 9c7d5b046878838da72e40ceb3179580958df544b240869b80d0275cc07209cc
|
||||
|
||||
// or in a streaming fashion (re-use "How are you")
|
||||
SHA256 sha256stream;
|
||||
const char* url = "create.stephan-brumme.com"; // 25 bytes
|
||||
int step = 5;
|
||||
for (int i = 0; i < 25; i += step)
|
||||
sha256stream.add(url + i, step); // add five bytes at a time
|
||||
std::cout << sha256stream.getHash() << std::endl;
|
||||
// => 82aa771f1183c52f973c798c9243a1c73833ea40961c73e55e12430ec77b69f6
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
411
configurator/configurator/third-party/hash-library/src/sha256.cpp
vendored
Normal file
411
configurator/configurator/third-party/hash-library/src/sha256.cpp
vendored
Normal file
@ -0,0 +1,411 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha256.cpp
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
|
||||
#ifndef _MSC_VER
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// same as reset()
|
||||
SHA256::SHA256()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// restart
|
||||
void SHA256::reset()
|
||||
{
|
||||
m_numBytes = 0;
|
||||
m_bufferSize = 0;
|
||||
|
||||
// according to RFC 1321
|
||||
m_hash[0] = 0x6a09e667;
|
||||
m_hash[1] = 0xbb67ae85;
|
||||
m_hash[2] = 0x3c6ef372;
|
||||
m_hash[3] = 0xa54ff53a;
|
||||
m_hash[4] = 0x510e527f;
|
||||
m_hash[5] = 0x9b05688c;
|
||||
m_hash[6] = 0x1f83d9ab;
|
||||
m_hash[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
inline uint32_t rotate(uint32_t a, uint32_t c)
|
||||
{
|
||||
return (a >> c) | (a << (32 - c));
|
||||
}
|
||||
|
||||
inline uint32_t swap(uint32_t x)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_bswap32(x);
|
||||
#endif
|
||||
#ifdef MSC_VER
|
||||
return _byteswap_ulong(x);
|
||||
#endif
|
||||
|
||||
return (x >> 24) |
|
||||
((x >> 8) & 0x0000FF00) |
|
||||
((x << 8) & 0x00FF0000) |
|
||||
(x << 24);
|
||||
}
|
||||
|
||||
// mix functions for processBlock()
|
||||
inline uint32_t f1(uint32_t e, uint32_t f, uint32_t g)
|
||||
{
|
||||
uint32_t term1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25);
|
||||
uint32_t term2 = (e & f) ^ (~e & g); //(g ^ (e & (f ^ g)))
|
||||
return term1 + term2;
|
||||
}
|
||||
|
||||
inline uint32_t f2(uint32_t a, uint32_t b, uint32_t c)
|
||||
{
|
||||
uint32_t term1 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22);
|
||||
uint32_t term2 = ((a | b) & c) | (a & b); //(a & (b ^ c)) ^ (b & c);
|
||||
return term1 + term2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// process 64 bytes
|
||||
void SHA256::processBlock(const void* data)
|
||||
{
|
||||
// get last hash
|
||||
uint32_t a = m_hash[0];
|
||||
uint32_t b = m_hash[1];
|
||||
uint32_t c = m_hash[2];
|
||||
uint32_t d = m_hash[3];
|
||||
uint32_t e = m_hash[4];
|
||||
uint32_t f = m_hash[5];
|
||||
uint32_t g = m_hash[6];
|
||||
uint32_t h = m_hash[7];
|
||||
|
||||
// data represented as 16x 32-bit words
|
||||
const uint32_t* input = (uint32_t*) data;
|
||||
// convert to big endian
|
||||
uint32_t words[64];
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
words[i] = input[i];
|
||||
#else
|
||||
words[i] = swap(input[i]);
|
||||
#endif
|
||||
|
||||
uint32_t x,y; // temporaries
|
||||
|
||||
// first round
|
||||
x = h + f1(e,f,g) + 0x428a2f98 + words[ 0]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0x71374491 + words[ 1]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0xb5c0fbcf + words[ 2]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0xe9b5dba5 + words[ 3]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x3956c25b + words[ 4]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0x59f111f1 + words[ 5]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x923f82a4 + words[ 6]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0xab1c5ed5 + words[ 7]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// secound round
|
||||
x = h + f1(e,f,g) + 0xd807aa98 + words[ 8]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0x12835b01 + words[ 9]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0x243185be + words[10]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0x550c7dc3 + words[11]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x72be5d74 + words[12]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0x80deb1fe + words[13]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x9bdc06a7 + words[14]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0xc19bf174 + words[15]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 24 words
|
||||
for (; i < 24; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// third round
|
||||
x = h + f1(e,f,g) + 0xe49b69c1 + words[16]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0xefbe4786 + words[17]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0x0fc19dc6 + words[18]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0x240ca1cc + words[19]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x2de92c6f + words[20]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0x4a7484aa + words[21]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x5cb0a9dc + words[22]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0x76f988da + words[23]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 32 words
|
||||
for (; i < 32; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// fourth round
|
||||
x = h + f1(e,f,g) + 0x983e5152 + words[24]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0xa831c66d + words[25]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0xb00327c8 + words[26]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0xbf597fc7 + words[27]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0xc6e00bf3 + words[28]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0xd5a79147 + words[29]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x06ca6351 + words[30]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0x14292967 + words[31]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 40 words
|
||||
for (; i < 40; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// fifth round
|
||||
x = h + f1(e,f,g) + 0x27b70a85 + words[32]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0x2e1b2138 + words[33]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0x4d2c6dfc + words[34]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0x53380d13 + words[35]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x650a7354 + words[36]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0x766a0abb + words[37]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x81c2c92e + words[38]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0x92722c85 + words[39]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 48 words
|
||||
for (; i < 48; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// sixth round
|
||||
x = h + f1(e,f,g) + 0xa2bfe8a1 + words[40]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0xa81a664b + words[41]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0xc24b8b70 + words[42]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0xc76c51a3 + words[43]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0xd192e819 + words[44]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0xd6990624 + words[45]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0xf40e3585 + words[46]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0x106aa070 + words[47]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 56 words
|
||||
for (; i < 56; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// seventh round
|
||||
x = h + f1(e,f,g) + 0x19a4c116 + words[48]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0x1e376c08 + words[49]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0x2748774c + words[50]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0x34b0bcb5 + words[51]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x391c0cb3 + words[52]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0x4ed8aa4a + words[53]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0x5b9cca4f + words[54]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0x682e6ff3 + words[55]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// extend to 64 words
|
||||
for (; i < 64; i++)
|
||||
words[i] = words[i-16] +
|
||||
(rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) +
|
||||
words[i-7] +
|
||||
(rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10));
|
||||
|
||||
// eigth round
|
||||
x = h + f1(e,f,g) + 0x748f82ee + words[56]; y = f2(a,b,c); d += x; h = x + y;
|
||||
x = g + f1(d,e,f) + 0x78a5636f + words[57]; y = f2(h,a,b); c += x; g = x + y;
|
||||
x = f + f1(c,d,e) + 0x84c87814 + words[58]; y = f2(g,h,a); b += x; f = x + y;
|
||||
x = e + f1(b,c,d) + 0x8cc70208 + words[59]; y = f2(f,g,h); a += x; e = x + y;
|
||||
x = d + f1(a,b,c) + 0x90befffa + words[60]; y = f2(e,f,g); h += x; d = x + y;
|
||||
x = c + f1(h,a,b) + 0xa4506ceb + words[61]; y = f2(d,e,f); g += x; c = x + y;
|
||||
x = b + f1(g,h,a) + 0xbef9a3f7 + words[62]; y = f2(c,d,e); f += x; b = x + y;
|
||||
x = a + f1(f,g,h) + 0xc67178f2 + words[63]; y = f2(b,c,d); e += x; a = x + y;
|
||||
|
||||
// update hash
|
||||
m_hash[0] += a;
|
||||
m_hash[1] += b;
|
||||
m_hash[2] += c;
|
||||
m_hash[3] += d;
|
||||
m_hash[4] += e;
|
||||
m_hash[5] += f;
|
||||
m_hash[6] += g;
|
||||
m_hash[7] += h;
|
||||
}
|
||||
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void SHA256::add(const void* data, size_t numBytes)
|
||||
{
|
||||
const uint8_t* current = (const uint8_t*) data;
|
||||
|
||||
if (m_bufferSize > 0)
|
||||
{
|
||||
while (numBytes > 0 && m_bufferSize < BlockSize)
|
||||
{
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
// full buffer
|
||||
if (m_bufferSize == BlockSize)
|
||||
{
|
||||
processBlock(m_buffer);
|
||||
m_numBytes += BlockSize;
|
||||
m_bufferSize = 0;
|
||||
}
|
||||
|
||||
// no more data ?
|
||||
if (numBytes == 0)
|
||||
return;
|
||||
|
||||
// process full blocks
|
||||
while (numBytes >= BlockSize)
|
||||
{
|
||||
processBlock(current);
|
||||
current += BlockSize;
|
||||
m_numBytes += BlockSize;
|
||||
numBytes -= BlockSize;
|
||||
}
|
||||
|
||||
// keep remaining bytes in buffer
|
||||
while (numBytes > 0)
|
||||
{
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// process final block, less than 64 bytes
|
||||
void SHA256::processBuffer()
|
||||
{
|
||||
// the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
|
||||
|
||||
// - append "1" bit to message
|
||||
// - append "0" bits until message length in bit mod 512 is 448
|
||||
// - append length as 64 bit integer
|
||||
|
||||
// number of bits
|
||||
size_t paddedLength = m_bufferSize * 8;
|
||||
|
||||
// plus one bit set to 1 (always appended)
|
||||
paddedLength++;
|
||||
|
||||
// number of bits must be (numBits % 512) = 448
|
||||
size_t lower11Bits = paddedLength & 511;
|
||||
if (lower11Bits <= 448)
|
||||
paddedLength += 448 - lower11Bits;
|
||||
else
|
||||
paddedLength += 512 + 448 - lower11Bits;
|
||||
// convert from bits to bytes
|
||||
paddedLength /= 8;
|
||||
|
||||
// only needed if additional data flows over into a second block
|
||||
unsigned char extra[BlockSize];
|
||||
|
||||
// append a "1" bit, 128 => binary 10000000
|
||||
if (m_bufferSize < BlockSize)
|
||||
m_buffer[m_bufferSize] = 128;
|
||||
else
|
||||
extra[0] = 128;
|
||||
|
||||
size_t i;
|
||||
for (i = m_bufferSize + 1; i < BlockSize; i++)
|
||||
m_buffer[i] = 0;
|
||||
for (; i < paddedLength; i++)
|
||||
extra[i - BlockSize] = 0;
|
||||
|
||||
// add message length in bits as 64 bit number
|
||||
uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
|
||||
// find right position
|
||||
unsigned char* addLength;
|
||||
if (paddedLength < BlockSize)
|
||||
addLength = m_buffer + paddedLength;
|
||||
else
|
||||
addLength = extra + paddedLength - BlockSize;
|
||||
|
||||
// must be big endian
|
||||
*addLength++ = (unsigned char)((msgBits >> 56) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 48) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 40) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 32) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 24) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 16) & 0xFF);
|
||||
*addLength++ = (unsigned char)((msgBits >> 8) & 0xFF);
|
||||
*addLength = (unsigned char)( msgBits & 0xFF);
|
||||
|
||||
// process blocks
|
||||
processBlock(m_buffer);
|
||||
// flowed over into a second block ?
|
||||
if (paddedLength > BlockSize)
|
||||
processBlock(extra);
|
||||
}
|
||||
|
||||
|
||||
/// return latest hash as 64 hex characters
|
||||
std::string SHA256::getHash()
|
||||
{
|
||||
// compute hash (as raw bytes)
|
||||
unsigned char rawHash[HashBytes];
|
||||
getHash(rawHash);
|
||||
|
||||
// convert to hex string
|
||||
std::string result;
|
||||
result.reserve(2 * HashBytes);
|
||||
for (int i = 0; i < HashBytes; i++)
|
||||
{
|
||||
static const char dec2hex[16+1] = "0123456789abcdef";
|
||||
result += dec2hex[(rawHash[i] >> 4) & 15];
|
||||
result += dec2hex[ rawHash[i] & 15];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// return latest hash as bytes
|
||||
void SHA256::getHash(unsigned char buffer[SHA256::HashBytes])
|
||||
{
|
||||
// save old hash if buffer is partially filled
|
||||
uint32_t oldHash[HashValues];
|
||||
for (int i = 0; i < HashValues; i++)
|
||||
oldHash[i] = m_hash[i];
|
||||
|
||||
// process remaining bytes
|
||||
processBuffer();
|
||||
|
||||
unsigned char* current = buffer;
|
||||
for (int i = 0; i < HashValues; i++)
|
||||
{
|
||||
*current++ = (m_hash[i] >> 24) & 0xFF;
|
||||
*current++ = (m_hash[i] >> 16) & 0xFF;
|
||||
*current++ = (m_hash[i] >> 8) & 0xFF;
|
||||
*current++ = m_hash[i] & 0xFF;
|
||||
|
||||
// restore old hash
|
||||
m_hash[i] = oldHash[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA256 of a memory block
|
||||
std::string SHA256::operator()(const void* data, size_t numBytes)
|
||||
{
|
||||
reset();
|
||||
add(data, numBytes);
|
||||
return getHash();
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA256 of a string, excluding final zero
|
||||
std::string SHA256::operator()(const std::string& text)
|
||||
{
|
||||
reset();
|
||||
add(text.c_str(), text.size());
|
||||
return getHash();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user