feat: Calibration and mod option querying are functional, as well as basic commands
This commit is contained in:
parent
403735ab4e
commit
535253f910
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,8 +1,7 @@
|
||||
|
||||
*.o
|
||||
include/*.hpp.gch
|
||||
CMakeFiles/
|
||||
include/etw-lmm_config.h
|
||||
include/etw-lmm_config.hpp
|
||||
cmake/CMake_Uninstall.cmake
|
||||
cmake_install.cmake
|
||||
CMakeCache.txt
|
||||
|
@ -9,8 +9,8 @@ set (CMAKE_EXPORT_COMPILE_COMMANDS 0)
|
||||
|
||||
# Generate header file with Caventure version
|
||||
configure_file (
|
||||
"${PROJECT_SOURCE_DIR}/include/etw-lmm_config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/include/etw-lmm_config.h")
|
||||
"${PROJECT_SOURCE_DIR}/include/etw-lmm_config.hpp.in"
|
||||
"${PROJECT_BINARY_DIR}/include/etw-lmm_config.hpp")
|
||||
|
||||
# Set $CMAKE_MODULE_PATH to standard /cmake
|
||||
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
@ -32,11 +32,16 @@ include_directories (${PROJECT_BINARY_DIR})
|
||||
|
||||
# Pre-build: set source files
|
||||
set (SOURCE_FILES src/main.cpp
|
||||
src/md5.cpp
|
||||
src/args.cpp
|
||||
src/utils.cpp
|
||||
src/etw_lmm.cpp
|
||||
src/backup.cpp
|
||||
src/calibrate.cpp
|
||||
src/install.cpp)
|
||||
src/calibratetext.cpp
|
||||
src/md5_wrapper.cpp
|
||||
src/generic.cpp
|
||||
src/exceptionhandler.cpp
|
||||
src/calibrationmanager.cpp
|
||||
src/installationmanager.cpp
|
||||
src/query.cpp)
|
||||
|
||||
# Build: set binary to source files
|
||||
add_executable (etw-lmm ${SOURCE_FILES})
|
||||
@ -45,10 +50,8 @@ add_executable (etw-lmm ${SOURCE_FILES})
|
||||
target_link_libraries (etw-lmm ${OPENSSL_LIBRARIES})
|
||||
|
||||
# Pre-install: create config directory
|
||||
file(MAKE_DIRECTORY ~/.config/etw-lmm)
|
||||
set (PROJECT_CONFIG_DIR ~/.config/etw-lmm)
|
||||
file(MAKE_DIRECTORY $ENV{HOME}/.local/share/etw-lmm)
|
||||
set (PROJECT_CONFIG_DIR $ENV{HOME}/.local/share/etw-lmm)
|
||||
|
||||
# Install: move reminaing files
|
||||
# Install: move remianing files
|
||||
install(TARGETS etw-lmm DESTINATION bin)
|
||||
install(DIRECTORY DESTINATION share/caventure)
|
||||
install(DIRECTORY share/json DESTINATION share/caventure)
|
||||
|
17
include/backup.hpp
Normal file
17
include/backup.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef BACKUP_HPP
|
||||
#define BACKUP_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Backup
|
||||
{
|
||||
public:
|
||||
Backup(const std::string&, const std::vector<std::string>&);
|
||||
void Execute(const std::string&) const;
|
||||
private:
|
||||
std::string _prefix;
|
||||
std::vector<std::string> _vec;
|
||||
};
|
||||
|
||||
#endif
|
55
include/calibrate.hpp
Normal file
55
include/calibrate.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef CALIBRATE_HPP
|
||||
#define CALIBRATE_HPP
|
||||
|
||||
#include "generic.hpp"
|
||||
#include "md5_wrapper.hpp"
|
||||
|
||||
class Calibrate : public Generic
|
||||
{
|
||||
public:
|
||||
Calibrate(const std::string&, const std::string&);
|
||||
inline static void PlusCount();
|
||||
inline static void ClearCount();
|
||||
inline static unsigned int GetCount();
|
||||
inline const MD5_wrapper& GetMD5Wrapper() const;
|
||||
bool CompareMD5(unsigned char*) const;
|
||||
|
||||
inline bool operator==(const Calibrate&) const;
|
||||
inline bool operator!=(const Calibrate&) const;
|
||||
private:
|
||||
MD5_wrapper _md5;
|
||||
static unsigned int _i;
|
||||
unsigned long GetSizeByFD(const int) const;
|
||||
};
|
||||
|
||||
inline void Calibrate::PlusCount()
|
||||
{
|
||||
_i++;
|
||||
}
|
||||
|
||||
inline void Calibrate::ClearCount()
|
||||
{
|
||||
_i = 0;
|
||||
}
|
||||
|
||||
inline unsigned int Calibrate::GetCount()
|
||||
{
|
||||
return _i;
|
||||
}
|
||||
|
||||
inline const MD5_wrapper &Calibrate::GetMD5Wrapper() const
|
||||
{
|
||||
return _md5;
|
||||
}
|
||||
|
||||
inline bool Calibrate::operator==(const Calibrate &rhs) const
|
||||
{
|
||||
return this->GetMD5Wrapper().GetString() == rhs.GetMD5Wrapper().GetString();
|
||||
}
|
||||
|
||||
inline bool Calibrate::operator!=(const Calibrate &rhs) const
|
||||
{
|
||||
return this->GetMD5Wrapper().GetString() != rhs.GetMD5Wrapper().GetString();
|
||||
}
|
||||
|
||||
#endif
|
23
include/calibratetext.hpp
Normal file
23
include/calibratetext.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef CALIBRATE_TEXT_HPP
|
||||
#define CALIBRATE_TEXT_HPP
|
||||
|
||||
#include "calibrate.hpp"
|
||||
|
||||
enum CalibrateFlag
|
||||
{
|
||||
NORMAL,
|
||||
UCS2
|
||||
};
|
||||
|
||||
class CalibrateText : public Calibrate
|
||||
{
|
||||
public:
|
||||
CalibrateText(const std::string&, const std::string&, const std::string&, const std::string&, const CalibrateFlag);
|
||||
void Execute() const;
|
||||
private:
|
||||
std::string _before;
|
||||
std::string _after;
|
||||
CalibrateFlag _cf;
|
||||
};
|
||||
|
||||
#endif
|
21
include/calibrationmanager.hpp
Normal file
21
include/calibrationmanager.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef CALIBRATIONMANAGER_HPP
|
||||
#define CALIBRATIONMANAGER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "calibratetext.hpp"
|
||||
|
||||
class CalibrationManager
|
||||
{
|
||||
public:
|
||||
CalibrationManager(const std::string&);
|
||||
void execute();
|
||||
private:
|
||||
std::string _hd;
|
||||
|
||||
void _verify();
|
||||
void _text(const std::string&, const CalibrateText&, const CalibrateFlag);
|
||||
void _backup();
|
||||
};
|
||||
|
||||
#endif
|
@ -1,2 +0,0 @@
|
||||
#define etw_lmm_VERSION_MAJOR @etw-lmm_VERSION_MAJOR@
|
||||
#define etw_lmm_VERSION_MINOR @etw-lmm_VERSION_MINOR@
|
7
include/etw-lmm_config.hpp.in
Normal file
7
include/etw-lmm_config.hpp.in
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef ETW_LMM_CONFIG_HPP
|
||||
#define ETW_LMM_CONFIG_HPP
|
||||
|
||||
const unsigned int etw_lmm_VERSION_MAJOR = @etw-lmm_VERSION_MAJOR@;
|
||||
const unsigned int etw_lmm_VERSION_MINOR = @etw-lmm_VERSION_MINOR@;
|
||||
|
||||
#endif
|
25
include/etw_lmm.hpp
Normal file
25
include/etw_lmm.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef ETW_LMM_HPP
|
||||
#define ETW_LMM_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class ETW_LMM
|
||||
{
|
||||
public:
|
||||
ETW_LMM(int argc, char **argv);
|
||||
unsigned int execute();
|
||||
private:
|
||||
std::vector<std::string> _args;
|
||||
std::string _hd;
|
||||
|
||||
void _set_homedir();
|
||||
void _help();
|
||||
void _menu();
|
||||
void _list();
|
||||
void _calibrate();
|
||||
void _install();
|
||||
void _uninstall(const std::string&);
|
||||
};
|
||||
|
||||
#endif
|
28
include/exceptionhandler.hpp
Normal file
28
include/exceptionhandler.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef EXCEPTION_HANDLER_HPP
|
||||
#define EXCEPTION_HANDLER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
enum ErrorCode
|
||||
{
|
||||
UNKNOWN_ERROR,
|
||||
CUSTOM_ERROR,
|
||||
INVALID_PATH_ERROR,
|
||||
INVALID_ARGUMENT_ERROR,
|
||||
NO_ARGUMENT_ERROR,
|
||||
PROCESS_ERROR
|
||||
};
|
||||
|
||||
class ExceptionHandler
|
||||
{
|
||||
public:
|
||||
ExceptionHandler(const ErrorCode, const std::string&);
|
||||
ExceptionHandler(const ErrorCode);
|
||||
void GrabError();
|
||||
private:
|
||||
ErrorCode _e;
|
||||
std::string _s;
|
||||
};
|
||||
|
||||
#endif
|
20
include/generic.hpp
Normal file
20
include/generic.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef GENERIC_HPP
|
||||
#define GENERIC_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class Generic
|
||||
{
|
||||
public:
|
||||
Generic(const std::string&);
|
||||
const inline std::string& GetPath() const;
|
||||
protected:
|
||||
std::string _path;
|
||||
};
|
||||
|
||||
const inline std::string& Generic::GetPath() const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
#endif
|
28
include/installationmanager.hpp
Normal file
28
include/installationmanager.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef INSTALLATIONMANAGER_HPP
|
||||
#define INSTALLATIONMANAGER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
class InstallationManager
|
||||
{
|
||||
public:
|
||||
InstallationManager(const std::string&, const std::string&);
|
||||
void execute();
|
||||
private:
|
||||
std::string _hd, _mod, _modname, _ver;
|
||||
int _campaigns, _turns;
|
||||
std::vector<bool> _packs;
|
||||
rapidjson::Document _cfg;
|
||||
|
||||
void _print_title(const std::string&);
|
||||
void _print_selection(const int);
|
||||
void _grab_json(const std::string&, rapidjson::Document&);
|
||||
void _version_query();
|
||||
void _campaign_query();
|
||||
void _pack_query();
|
||||
};
|
||||
|
||||
#endif
|
36
include/md5_wrapper.hpp
Normal file
36
include/md5_wrapper.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef MD5_WRAPPER_HPP
|
||||
#define MD5_WRAPPER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class MD5_wrapper
|
||||
{
|
||||
public:
|
||||
MD5_wrapper(unsigned char*);
|
||||
MD5_wrapper(const char*);
|
||||
MD5_wrapper(const std::string&);
|
||||
inline const std::string& GetString() const;
|
||||
|
||||
inline bool operator==(const MD5_wrapper&) const;
|
||||
inline bool operator!=(const MD5_wrapper&) const;
|
||||
private:
|
||||
unsigned long GetSizeByFD(const int) const;
|
||||
std::string _md5;
|
||||
};
|
||||
|
||||
inline const std::string &MD5_wrapper::GetString() const
|
||||
{
|
||||
return _md5;
|
||||
}
|
||||
|
||||
inline bool MD5_wrapper::operator==(const MD5_wrapper &rhs) const
|
||||
{
|
||||
return this->GetString() == rhs.GetString();
|
||||
}
|
||||
|
||||
inline bool MD5_wrapper::operator!=(const MD5_wrapper &rhs) const
|
||||
{
|
||||
return this->GetString() != rhs.GetString();
|
||||
}
|
||||
|
||||
#endif
|
158
include/paths.hpp
Normal file
158
include/paths.hpp
Normal file
@ -0,0 +1,158 @@
|
||||
#ifndef PATHS_HPP
|
||||
#define PATHS_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <openssl/md5.h> /* md5sum */
|
||||
|
||||
#include "generic.hpp"
|
||||
#include "backup.hpp"
|
||||
#include "calibrate.hpp"
|
||||
#include "calibratetext.hpp"
|
||||
|
||||
const std::string FERAL_PREFIX = "/.local/share/feral-interactive/Empire/";
|
||||
const std::string STEAM_PREFIX = "/.local/share/Steam/steamapps/common/Empire\ Total\ War/";
|
||||
const std::string MAIN_CAMPAIGN = "data/campaigns/main";
|
||||
const std::string GLOBAL_MAP = "data/campaign_maps/global_map";
|
||||
|
||||
const std::map<std::string, std::string> PATH_MD5_MAP =
|
||||
{
|
||||
{FERAL_PREFIX + "AppData/scripts/preferences.empire_script.txt",
|
||||
"5d064a6cfdc35f4714fd31d5d99735d0"},
|
||||
{FERAL_PREFIX + "preferences",
|
||||
"a0f283d89d97a00011f292cc8f9c0d24"},
|
||||
{STEAM_PREFIX + MAIN_CAMPAIGN + "/" + "scripting.lua",
|
||||
"89b18f2c2c3f98b6fed7ed7ae4e3e4f9"},
|
||||
{STEAM_PREFIX + MAIN_CAMPAIGN + "/" + "startpos.esf",
|
||||
"084b14b4174b93c6489422fe33dc7b2b"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "america_lookup.tga",
|
||||
"086f52fb74d2d0c03ef4e0a969fac4d9"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "america_map.tga",
|
||||
"92569145991bb8c1937769f023264fbb"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "brazil_map.tga",
|
||||
"c77b3468113aae3e1ebf43d0a2279986"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "east_indies_lookup.tga",
|
||||
"98f9a1c82a9fbf2ce15aa9c37eb5735c"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "east_indies_map.tga",
|
||||
"c15c8e4db971585dce18f764db084f2c"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "europe_lookup.tga",
|
||||
"62c929e8849b77b3d3060bdd448fe0db"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "europe_map.tga",
|
||||
"dd31679ed17096692475dad452c2d2c5"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "india_lookup.tga",
|
||||
"a731bf4b7574ad3abf4cbbff0873880d"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "india_map.tga",
|
||||
"6a69c2b16c421aabc642396a8f5ecf48"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "ivory_coast_map.tga",
|
||||
"e03faec4549366c5d6df0e37e37e9c28"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "madagascar_map.tga",
|
||||
"46788119db0b0c3e79d307f7005dbac4"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_america.tga",
|
||||
"84648966d1ad44ae072b698dc0e311d4"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_brazil.tga",
|
||||
"c77b3468113aae3e1ebf43d0a2279986"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_east_indies.tga",
|
||||
"c15c8e4db971585dce18f764db084f2c"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_europe.tga",
|
||||
"b95431493f9a1078c013efb627cfe12a"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_india.tga",
|
||||
"e25d189f93fa3761a48a033d0818176a"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_ivory_coast.tga",
|
||||
"e03faec4549366c5d6df0e37e37e9c28"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "stratradar_madagascar.tga",
|
||||
"46788119db0b0c3e79d307f7005dbac4"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "pathfinding.esf",
|
||||
"d3cd17af453c9aaa5dd64dfeb8499585"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "poi.esf",
|
||||
"57d6dac4b3c39587819607fce460e00e"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "regions.esf",
|
||||
"e30d0b9873fad972d490a7cacb039ea9"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "sea_grids.esf",
|
||||
"ebd02a0e4f39e07816054445cbd59d3d"},
|
||||
{STEAM_PREFIX + GLOBAL_MAP + "/" + "trade_routes.esf",
|
||||
"dd853d15992a5c0f15da0cdd6ac443c1"}
|
||||
};
|
||||
|
||||
const Generic INSTALLED =
|
||||
{
|
||||
"/.local/share/etw-lmm/installed"
|
||||
};
|
||||
|
||||
const CalibrateText EMPIRE_SCRIPT =
|
||||
{
|
||||
"~" + FERAL_PREFIX + "AppData/scripts/preferences.empire_script.txt",
|
||||
"fbf65ef80563e0bd76836c150e49ecd0",
|
||||
"write_preferences_at_exit true",
|
||||
"write_preferences_at_exit false",
|
||||
UCS2
|
||||
};
|
||||
|
||||
const CalibrateText PREFERENCES =
|
||||
{
|
||||
"~" + FERAL_PREFIX + "preferences",
|
||||
"1d7c5d84f79a3d361bfa7c608b71d8c8",
|
||||
"\"UsePBOSurfaces\" type=\"integer\">1",
|
||||
"\"UsePBOSurfaces\" type=\"integer\">0",
|
||||
NORMAL
|
||||
};
|
||||
|
||||
const std::array<CalibrateText, 2> CALIB_VERIFY_ARR =
|
||||
{
|
||||
EMPIRE_SCRIPT,
|
||||
PREFERENCES
|
||||
};
|
||||
|
||||
const std::vector<std::string> MAIN_CAMPAIGN_PATH_VEC =
|
||||
{
|
||||
"scripting.lua",
|
||||
"startpos.esf"
|
||||
};
|
||||
|
||||
const std::vector<std::string> GLOBAL_MAP_PATH_VEC =
|
||||
{
|
||||
"america_lookup.tga",
|
||||
"america_map.tga",
|
||||
"brazil_map.tga",
|
||||
"east_indies_lookup.tga",
|
||||
"east_indies_map.tga",
|
||||
"europe_lookup.tga",
|
||||
"europe_map.tga",
|
||||
"india_lookup.tga",
|
||||
"india_map.tga",
|
||||
"ivory_coast_map.tga",
|
||||
"madagascar_map.tga",
|
||||
"stratradar_america.tga",
|
||||
"stratradar_brazil.tga",
|
||||
"stratradar_east_indies.tga",
|
||||
"stratradar_europe.tga",
|
||||
"stratradar_india.tga",
|
||||
"stratradar_ivory_coast.tga",
|
||||
"stratradar_madagascar.tga",
|
||||
"pathfinding.esf",
|
||||
"poi.esf",
|
||||
"regions.esf",
|
||||
"sea_grids.esf",
|
||||
"trade_routes.esf"
|
||||
};
|
||||
|
||||
const Backup MAIN_CAMPAIGN_BACKUP =
|
||||
{
|
||||
STEAM_PREFIX + "data/campaigns/main",
|
||||
MAIN_CAMPAIGN_PATH_VEC
|
||||
};
|
||||
|
||||
const Backup GLOBAL_MAP_BACKUP =
|
||||
{
|
||||
STEAM_PREFIX + "data/campaign_maps/global_map",
|
||||
GLOBAL_MAP_PATH_VEC
|
||||
};
|
||||
|
||||
const std::array<Backup, 2> BACKUP_ARR =
|
||||
{
|
||||
MAIN_CAMPAIGN_BACKUP,
|
||||
GLOBAL_MAP_BACKUP
|
||||
};
|
||||
|
||||
#endif
|
26
include/query.hpp
Normal file
26
include/query.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef QUERY_HPP
|
||||
#define QUERY_HPP
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
template <class OUTPUT>
|
||||
class Query
|
||||
{
|
||||
public:
|
||||
Query<OUTPUT>(const std::string&);
|
||||
Query<OUTPUT>(const std::string&, char*);
|
||||
OUTPUT execute(const rapidjson::Document&) const;
|
||||
private:
|
||||
std::string _query;
|
||||
char* _list;
|
||||
|
||||
bool _bool(const rapidjson::Document&);
|
||||
std::string _string(const rapidjson::Document&);
|
||||
int _int(const rapidjson::Document&);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,32 +0,0 @@
|
||||
{
|
||||
"md5":
|
||||
[
|
||||
"5d064a6cfdc35f4714fd31d5d99735d0",
|
||||
"a0f283d89d97a00011f292cc8f9c0d24",
|
||||
"89b18f2c2c3f98b6fed7ed7ae4e3e4f9",
|
||||
"084b14b4174b93c6489422fe33dc7b2b",
|
||||
"086f52fb74d2d0c03ef4e0a969fac4d9",
|
||||
"92569145991bb8c1937769f023264fbb",
|
||||
"c77b3468113aae3e1ebf43d0a2279986",
|
||||
"98f9a1c82a9fbf2ce15aa9c37eb5735c",
|
||||
"c15c8e4db971585dce18f764db084f2c",
|
||||
"62c929e8849b77b3d3060bdd448fe0db",
|
||||
"dd31679ed17096692475dad452c2d2c5",
|
||||
"a731bf4b7574ad3abf4cbbff0873880d",
|
||||
"6a69c2b16c421aabc642396a8f5ecf48",
|
||||
"e03faec4549366c5d6df0e37e37e9c28",
|
||||
"46788119db0b0c3e79d307f7005dbac4",
|
||||
"84648966d1ad44ae072b698dc0e311d4",
|
||||
"c77b3468113aae3e1ebf43d0a2279986",
|
||||
"c15c8e4db971585dce18f764db084f2c",
|
||||
"b95431493f9a1078c013efb627cfe12a",
|
||||
"e25d189f93fa3761a48a033d0818176a",
|
||||
"e03faec4549366c5d6df0e37e37e9c28",
|
||||
"46788119db0b0c3e79d307f7005dbac4",
|
||||
"d3cd17af453c9aaa5dd64dfeb8499585",
|
||||
"57d6dac4b3c39587819607fce460e00e",
|
||||
"e30d0b9873fad972d490a7cacb039ea9",
|
||||
"ebd02a0e4f39e07816054445cbd59d3d",
|
||||
"dd853d15992a5c0f15da0cdd6ac443c1"
|
||||
]
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
{
|
||||
"data":
|
||||
[
|
||||
"/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt",
|
||||
"/.local/share/feral-interactive/Empire/preferences",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main/scripting.lua",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main/startpos.esf",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/america_lookup.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/america_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/brazil_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/east_indies_lookup.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/east_indies_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/europe_lookup.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/europe_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/india_lookup.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/india_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/ivory_coast_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/madagascar_map.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_america.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_brazil.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_east_indies.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_europe.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_india.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_ivory_coast.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/stratradar_madagascar.tga",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/pathfinding.esf",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/poi.esf",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/regions.esf",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/sea_grids.esf",
|
||||
"/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/trade_routes.esf"
|
||||
],
|
||||
"preferences.empire_script":
|
||||
{
|
||||
"name": "feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt",
|
||||
"path": "~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt"
|
||||
},
|
||||
"preferences":
|
||||
{
|
||||
"name": "feral-interactive/Empire/preferences",
|
||||
"path": "~/.local/share/feral-interactive/Empire/preferences"
|
||||
},
|
||||
"main_backup":
|
||||
{
|
||||
"name": "data/campaigns/main_backup/",
|
||||
"path": "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main_backup/"
|
||||
},
|
||||
"global_map_backup":
|
||||
{
|
||||
"name": "data/campaign_maps/global_map_backup/",
|
||||
"path": "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map_backup/"
|
||||
}
|
||||
}
|
182
src/args.cpp
182
src/args.cpp
@ -1,182 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <openssl/md5.h> /* md5sum */
|
||||
|
||||
#include "../include/etw-lmm_config.h"
|
||||
#include "../include/rapidjson/document.h"
|
||||
|
||||
|
||||
std::string to_hex(unsigned char*);
|
||||
void md5sum(std::string, unsigned char [MD5_DIGEST_LENGTH]);
|
||||
void print_md5_sum(unsigned char*);
|
||||
int calibrate_preferences();
|
||||
int calibrate_text_bug_fix();
|
||||
int calibrate_backup(const std::string&);
|
||||
int yn_query(const std::string&, bool);
|
||||
int dir_not_exists(const std::string&);
|
||||
|
||||
/**
|
||||
* Brings up the command list/help menu
|
||||
*/
|
||||
void help_menu()
|
||||
{
|
||||
std::cout << "EMPIRE: TOTAL WAR -- LINUX MOD MANAGER "
|
||||
<< std::to_string(etw_lmm_VERSION_MAJOR) << "." << std::to_string(etw_lmm_VERSION_MINOR) << "\n"
|
||||
<< "Options:\n"
|
||||
<< "\thelp\t\tShow this help message\n"
|
||||
<< "\tinstall [MOD]\tInstall a mod\n"
|
||||
<< "\tuninstall [MOD]\tUninstall a mod\n"
|
||||
<< "\tcalibrate\tCalibrate original game files for modding\n"
|
||||
<< "\tlist\t\tList installed mods\n"
|
||||
<< "\tquery [MOD]\tQuery available mods"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists installed mods in mods filepath
|
||||
*
|
||||
* @param Path for file MODS
|
||||
*/
|
||||
int list(const std::string& hd)
|
||||
{
|
||||
const std::string mods = hd + "/.config/etw-lmm/MODS";
|
||||
|
||||
/* If file MODS doesn't exist */
|
||||
if (access(mods.c_str(), F_OK) == -1)
|
||||
{
|
||||
std::cout << "No mods installed!";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::ifstream ioMODS(mods);
|
||||
std::string name;
|
||||
|
||||
while (std::getline (ioMODS, name))
|
||||
{
|
||||
if (name == "\0")
|
||||
{
|
||||
std::cout << "No mods installed!";
|
||||
}
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
|
||||
ioMODS.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int calibrate(const std::string& hd, const std::vector<std::string>& path, const char* path_md5[])
|
||||
{
|
||||
const std::string mods = hd + "/.config/etw-lmm/MODS";
|
||||
|
||||
/* If file MODS exists */
|
||||
if (access(mods.c_str(), F_OK) != -1)
|
||||
{
|
||||
std::ifstream ioMODS(mods);
|
||||
std::string name;
|
||||
|
||||
std::getline (ioMODS, name);
|
||||
if (name != "\0")
|
||||
{
|
||||
std::cerr << "Either get a fresh install of Empire: Total War or uninstall the following mods: " << std::endl;
|
||||
list(mods);
|
||||
ioMODS.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ioMODS.close();
|
||||
}
|
||||
|
||||
unsigned int x = 0;
|
||||
|
||||
std::cout << "No mods installed! Calibrating files now..." << std::endl;
|
||||
for (unsigned int i = 0; i < path.size(); i++)
|
||||
{
|
||||
unsigned char md5_local[MD5_DIGEST_LENGTH];
|
||||
md5sum(path[i], md5_local);
|
||||
if ((strcmp(to_hex(md5_local).c_str(), path_md5[i]) != 0))
|
||||
{
|
||||
/* write_preferences_at_exit false in preferences.empire_script.txt */
|
||||
if (i == 0 && to_hex(md5_local) == "fbf65ef80563e0bd76836c150e49ecd0")
|
||||
{
|
||||
if (calibrate_preferences())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* preferences has VBOSurfaces set to 1, TEXT BUG FIX */
|
||||
if (i == 1 && to_hex(md5_local) == "1d7c5d84f79a3d361bfa7c608b71d8c8")
|
||||
{
|
||||
if (calibrate_text_bug_fix())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
print_md5_sum(md5_local);
|
||||
std::cerr << " != " << path_md5[i] << "\n" << path[i] << " is not calibrated!" << std::endl;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
std::cerr << "Number of files uncalibrated: " << x << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "All files are calibrated!" << std::endl;
|
||||
|
||||
/* GAME FILE BACKUPS */
|
||||
|
||||
if (calibrate_backup(hd))
|
||||
{
|
||||
if (yn_query("Would you like to backup your game files? This is recommended.", true))
|
||||
{
|
||||
std::cout << "Backing up files now..." << std::endl;
|
||||
|
||||
const std::string dir_main_backup = hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main_backup";
|
||||
const std::string dir_global_map_backup = hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map_backup";
|
||||
|
||||
if (dir_not_exists(dir_main_backup))
|
||||
{
|
||||
const std::string dir_main = hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main/";
|
||||
|
||||
const std::string backup_main = "cp -R " + dir_main + ". " + dir_main_backup;
|
||||
|
||||
if (system(backup_main.c_str()))
|
||||
{
|
||||
std::cerr << "Failed to backup data/campaigns/main/!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir_not_exists(dir_global_map_backup))
|
||||
{
|
||||
const std::string dir_global_map = hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map/";
|
||||
|
||||
const std::string backup_global_map = "cp -R " + dir_global_map + ". " + dir_global_map_backup;
|
||||
|
||||
if (system(backup_global_map.c_str()))
|
||||
{
|
||||
std::cerr << "Failed to backup data/campaign_map/global_map/!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Critical game data is now backed up!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "The game is now ready to install mods." << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
53
src/backup.cpp
Normal file
53
src/backup.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sys/sendfile.h> // sendfile
|
||||
#include <fcntl.h> // open
|
||||
#include <unistd.h> // close
|
||||
#include <sys/stat.h> // fstat
|
||||
#include <sys/types.h> // fstat
|
||||
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
#include "../include/backup.hpp"
|
||||
|
||||
Backup::Backup(const std::string &prefix, const std::vector<std::string> &vec)
|
||||
: _prefix(prefix), _vec(vec) {};
|
||||
|
||||
void Backup::Execute(const std::string &hd) const
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
const std::string bkp = hd + _prefix + "_backup/";
|
||||
|
||||
struct stat stat_dir;
|
||||
if (stat(bkp.c_str(), &stat_dir) != 0)
|
||||
{
|
||||
mkdir(bkp.c_str(), 0700);
|
||||
}
|
||||
|
||||
for (auto &i : _vec)
|
||||
{
|
||||
const std::string source_file = hd + _prefix + "/" + i;
|
||||
const std::string dest_file = bkp + i;
|
||||
|
||||
std::cout << "Backing up " << _prefix << "/" << i << "\n";
|
||||
|
||||
int source = open(source_file.c_str(), O_RDONLY, 0);
|
||||
int dest = open(dest_file.c_str(), O_WRONLY | O_CREAT /*| O_TRUNC/**/, 0644);
|
||||
|
||||
// struct required, rationale: function stat() exists also
|
||||
struct stat stat_source;
|
||||
fstat(source, &stat_source);
|
||||
|
||||
sendfile(dest, source, 0, stat_source.st_size);
|
||||
|
||||
close(source);
|
||||
close(dest);
|
||||
|
||||
if (access(dest_file.c_str(), F_OK) != 0)
|
||||
{
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "Backing up " + dest_file + " failed!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +1,67 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h> /* md5sum */
|
||||
|
||||
int replace_string(const std::string&, const std::string&, const std::string&);
|
||||
int dir_not_exists(const std::string&);
|
||||
#include "../include/calibrate.hpp"
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
|
||||
int calibrate_preferences()
|
||||
unsigned int Calibrate::_i = 0;
|
||||
|
||||
Calibrate::Calibrate(const std::string &path, const std::string &md5)
|
||||
: Generic(std::move(path)), _md5(std::move(md5)) {}
|
||||
|
||||
bool Calibrate::CompareMD5(unsigned char *md5) const
|
||||
{
|
||||
std::cout << "Calibrating preferences.empire_script.txt..." << std::endl;
|
||||
|
||||
/* Converting .txt file from UCS-2 to UTF-8 into a new .txt_utf8 file */
|
||||
if (system("iconv -f ucs-2 -t utf-8 -o ~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt_utf8 ~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt"))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Replacing string in utf_8 */
|
||||
if (replace_string("~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt_utf8", "write_preferences_at_exit true", "write_preferences_at_exit false"))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Converting back from UTF-8 to UCS-2 in .txt*/
|
||||
return system("iconv -f utf-8 -t ucs-2 -o ~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt ~/.local/share/feral-interactive/Empire/AppData/scripts/preferences.empire_script.txt_utf8");
|
||||
|
||||
/** NOT FUNCTIONAL
|
||||
|
||||
// Verifying MD5 checksum
|
||||
md5sum(path[i], md5_local);
|
||||
if ((strcmp(to_hex(md5_local).c_str(), path_md5[i]) != 0))
|
||||
{
|
||||
print_md5_sum(md5_local);
|
||||
std::cerr << " != " << path_md5[i] << "\nFailed to calibrate preferences.empire_script.txt !" << std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Variable initialisation
|
||||
*/
|
||||
}
|
||||
int file_descript;
|
||||
unsigned long file_size;
|
||||
unsigned char* file_buffer;
|
||||
|
||||
int calibrate_text_bug_fix()
|
||||
{
|
||||
std::cout << "Calibrating preferences XML file..." << std::endl;
|
||||
|
||||
/* Replacing string */
|
||||
return replace_string("~/.local/share/feral-interactive/Empire/preferences", "\"UsePBOSurfaces\" type=\"integer\">1", "\"UsePBOSurfaces\" type=\"integer\">0");
|
||||
}
|
||||
|
||||
int calibrate_backup(const std::string& hd)
|
||||
{
|
||||
std::cout << "Searching for backup files and directories..." << std::endl;
|
||||
|
||||
if (dir_not_exists(hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaigns/main_backup/"))
|
||||
/* Checks if the file path can be opened. */
|
||||
file_descript = open(_path.c_str(), O_RDONLY);
|
||||
if (file_descript < 0)
|
||||
{
|
||||
std::cerr << "data/campaigns/main_backup/ not found!" << std::endl;
|
||||
return 1;
|
||||
throw ExceptionHandler(INVALID_PATH_ERROR, _path);
|
||||
}
|
||||
|
||||
if (dir_not_exists(hd + "/.local/share/Steam/steamapps/common/Empire\ Total\ War/data/campaign_maps/global_map_backup/"))
|
||||
/* Grabs the size of file */
|
||||
file_size = GetSizeByFD(file_descript);
|
||||
|
||||
/* Generates the buffer */
|
||||
file_buffer = static_cast<unsigned char*>(mmap(static_cast<caddr_t>(0), file_size, PROT_READ, MAP_SHARED, file_descript, 0));
|
||||
|
||||
/* Computes the MD5 checksum to result */
|
||||
MD5(file_buffer, file_size, md5);
|
||||
|
||||
/* Removes fime_buffer and file_size */
|
||||
munmap(file_buffer, file_size);
|
||||
|
||||
MD5_wrapper md5_wrapper(md5);
|
||||
|
||||
if (_md5.GetString() != md5_wrapper.GetString())
|
||||
{
|
||||
std::cerr << "data/campaign_maps/global_map_backup/ not found!" << std::endl;
|
||||
return 1;
|
||||
std::cout << "WARNING! " << _md5.GetString() << " != " << md5_wrapper.GetString() << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the file by its file descriptor
|
||||
*
|
||||
* @param file_descript
|
||||
*/
|
||||
unsigned long Calibrate::GetSizeByFD(const int fd) const
|
||||
{
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) < 0)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return statbuf.st_size;
|
||||
}
|
||||
|
68
src/calibratetext.cpp
Normal file
68
src/calibratetext.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "../include/calibratetext.hpp"
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
|
||||
CalibrateText::CalibrateText(const std::string &path, const std::string &md5, const std::string &before, const std::string &after, const CalibrateFlag cf)
|
||||
: Calibrate(path, md5), _before(before), _after(after), _cf(cf) {}
|
||||
|
||||
void CalibrateText::Execute() const
|
||||
{
|
||||
std::cout << "Calibrating " << _path << "\n";
|
||||
|
||||
std::string cmd = "sed -i -- 's/" + _before + "/" + _after + "/g' " + _path;
|
||||
std::string ucs2_to_utf8;
|
||||
std::string utf8_to_ucs2;
|
||||
|
||||
switch (_cf)
|
||||
{
|
||||
case UCS2:
|
||||
cmd += "_utf8";
|
||||
ucs2_to_utf8 = "iconv -f ucs-2 -t utf-8 -o " + _path + "_utf8" + " " + _path;
|
||||
utf8_to_ucs2 = "iconv -f utf-8 -t ucs-2 -o " + _path + " " + _path + "_utf8";
|
||||
|
||||
/* Converting .txt file from UCS-2 to UTF-8 into a new .txt_utf8 file */
|
||||
if (system(ucs2_to_utf8.c_str()))
|
||||
{
|
||||
throw ExceptionHandler(PROCESS_ERROR, _path);
|
||||
}
|
||||
break;
|
||||
case NORMAL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
throw ExceptionHandler(PROCESS_ERROR, _path);
|
||||
}
|
||||
|
||||
switch (_cf)
|
||||
{
|
||||
case UCS2:
|
||||
/* Converting back from UTF-8 to UCS-2 in .txt*/
|
||||
if (system(utf8_to_ucs2.c_str()))
|
||||
{
|
||||
throw ExceptionHandler(PROCESS_ERROR, _path);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case NORMAL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** NOT FUNCTIONAL
|
||||
|
||||
// Verifying MD5 checksum
|
||||
md5sum(path[i], md5_local);
|
||||
if ((strcmp(to_hex(md5_local).c_str(), path_md5[i]) != 0))
|
||||
{
|
||||
print_md5_sum(md5_local);
|
||||
std::cerr << " != " << path_md5[i] << "\nFailed to calibrate preferences.empire_script.txt !" << "\n";
|
||||
}*/
|
||||
}
|
87
src/calibrationmanager.cpp
Normal file
87
src/calibrationmanager.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "../include/calibrationmanager.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
#include "../include/paths.hpp"
|
||||
|
||||
CalibrationManager::CalibrationManager(const std::string &hd)
|
||||
: _hd(hd) {}
|
||||
|
||||
void CalibrationManager::execute()
|
||||
{
|
||||
const std::string fp = _hd + INSTALLED.GetPath();
|
||||
|
||||
/* If file exists */
|
||||
if (access(std::move(fp).c_str(), F_OK) == 0)
|
||||
{
|
||||
std::cout << "Please uninstall any installed mods." << "\n";
|
||||
throw ExceptionHandler(UNKNOWN_ERROR);
|
||||
}
|
||||
|
||||
/* MD5 DIGEST VERIFICATION */
|
||||
|
||||
std::cout << "No mods installed! Calibrating files now..." << "\n";
|
||||
|
||||
/* Verifies the MD5 digest of each path */
|
||||
_verify();
|
||||
|
||||
if (Calibrate::GetCount() > 0)
|
||||
{
|
||||
std::cout << "Number of files uncalibrated: " << Calibrate::GetCount() << "\n";
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "Please reinstall the game.");
|
||||
}
|
||||
|
||||
std::cout << "All files are calibrated!" << "\n";
|
||||
|
||||
/* GAME FILE BACKUPS */
|
||||
|
||||
_backup();
|
||||
|
||||
std::cout << "The game is now ready to install mods." << "\n";
|
||||
}
|
||||
|
||||
void CalibrationManager::_verify()
|
||||
{
|
||||
Calibrate::ClearCount();
|
||||
|
||||
for (auto &it : PATH_MD5_MAP)
|
||||
{
|
||||
const std::string fp = _hd + it.first;
|
||||
unsigned char md5_local[MD5_DIGEST_LENGTH];
|
||||
|
||||
Calibrate calibrate_local(std::move(fp), it.second);
|
||||
|
||||
if (!calibrate_local.CompareMD5(md5_local))
|
||||
{
|
||||
bool blocal = true;
|
||||
for (auto &i : CALIB_VERIFY_ARR)
|
||||
{
|
||||
if (i.CompareMD5(md5_local))
|
||||
{
|
||||
i.Execute();
|
||||
blocal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (blocal)
|
||||
{
|
||||
Calibrate::PlusCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationManager::_backup()
|
||||
{
|
||||
std::cout << "Searching for backup files and directories..." << "\n";
|
||||
|
||||
for (auto &i : BACKUP_ARR)
|
||||
{
|
||||
i.Execute(_hd);
|
||||
}
|
||||
|
||||
std::cout << "Critical game data is now backed up!" << "\n";
|
||||
}
|
139
src/etw_lmm.cpp
Normal file
139
src/etw_lmm.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../include/paths.hpp"
|
||||
#include "../include/etw_lmm.hpp"
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
#include "../include/etw-lmm_config.hpp"
|
||||
#include "../include/calibrationmanager.hpp"
|
||||
#include "../include/installationmanager.hpp"
|
||||
|
||||
ETW_LMM::ETW_LMM(int argc, char **argv)
|
||||
{
|
||||
for (unsigned int i = 0; i < argc; ++i)
|
||||
{
|
||||
_args.push_back(argv[i]);
|
||||
}
|
||||
|
||||
_set_homedir();
|
||||
}
|
||||
|
||||
unsigned int ETW_LMM::execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
_menu();
|
||||
}
|
||||
catch (ExceptionHandler& e)
|
||||
{
|
||||
std::cerr << _args[0] << ": ";
|
||||
e.GrabError();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ETW_LMM::_menu()
|
||||
{
|
||||
if (_args.size() > 1)
|
||||
{
|
||||
if (_args[1] == "help") { _help(); }
|
||||
else if (_args[1] == "calibrate") { _calibrate(); }
|
||||
else if (_args[1] == "list") { _list(); }
|
||||
else if (_args[1] == "install")
|
||||
{
|
||||
if (_args.size() < 3)
|
||||
{
|
||||
throw ExceptionHandler(NO_ARGUMENT_ERROR);
|
||||
}
|
||||
|
||||
_install();
|
||||
}
|
||||
else if (_args[1] == "uninstall")
|
||||
{
|
||||
if (_args.size() < 3) // TO DO
|
||||
{
|
||||
throw ExceptionHandler(NO_ARGUMENT_ERROR);
|
||||
}
|
||||
|
||||
// INSTALLATION
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ExceptionHandler(INVALID_ARGUMENT_ERROR, _args[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_help();
|
||||
}
|
||||
}
|
||||
|
||||
void ETW_LMM::_set_homedir()
|
||||
{
|
||||
/* Retrieve home directory */
|
||||
char* char_homedir;
|
||||
if ((char_homedir = getenv("HOME")) == NULL)
|
||||
{
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
char_homedir = pw->pw_dir;
|
||||
}
|
||||
|
||||
_hd = char_homedir;
|
||||
}
|
||||
|
||||
void ETW_LMM::_help()
|
||||
{
|
||||
std::cout << "EMPIRE: TOTAL WAR -- LINUX MOD MANAGER "
|
||||
<< etw_lmm_VERSION_MAJOR << "." << etw_lmm_VERSION_MINOR << "\n"
|
||||
<< "Options:\n"
|
||||
<< "\thelp\t\tShow this help message\n"
|
||||
<< "\tinstall [MOD]\tInstall a mod\n"
|
||||
<< "\tuninstall [MOD]\tUninstall a mod\n"
|
||||
<< "\tcalibrate\tCalibrate original game files for modding\n"
|
||||
<< "\tlist\t\tList installed mods\n"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void ETW_LMM::_list()
|
||||
{
|
||||
const std::string fp = _hd + INSTALLED.GetPath();
|
||||
|
||||
/* If file doesn't exist */
|
||||
if (access(std::move(fp).c_str(), F_OK) != 0)
|
||||
{
|
||||
std::cout << "No mods installed!";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ifstream ifs(std::move(fp));
|
||||
std::string name;
|
||||
|
||||
while (std::getline(ifs, name))
|
||||
{
|
||||
if (name == "\0")
|
||||
{
|
||||
std::cout << "No mods installed!";
|
||||
break;
|
||||
}
|
||||
std::cout << name << "\n";
|
||||
}
|
||||
|
||||
ifs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void ETW_LMM::_calibrate()
|
||||
{
|
||||
CalibrationManager cm(_hd);
|
||||
cm.execute();
|
||||
}
|
||||
|
||||
void ETW_LMM::_install()
|
||||
{
|
||||
InstallationManager im(_hd, _args[2]);
|
||||
im.execute();
|
||||
}
|
27
src/exceptionhandler.cpp
Normal file
27
src/exceptionhandler.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
|
||||
ExceptionHandler::ExceptionHandler(const ErrorCode e, const std::string &s)
|
||||
: _e(e), _s(s) {}
|
||||
|
||||
ExceptionHandler::ExceptionHandler(const ErrorCode e)
|
||||
: _e(e) {}
|
||||
|
||||
void ExceptionHandler::GrabError()
|
||||
{
|
||||
std::string str;
|
||||
|
||||
std::cerr << "Error code " << _e << "!" << "\n";
|
||||
|
||||
switch (_e)
|
||||
{
|
||||
case CUSTOM_ERROR: str += _s; break;
|
||||
case INVALID_PATH_ERROR: str += "\"" + _s + "\" is an invalid path."; break;
|
||||
case INVALID_ARGUMENT_ERROR: str += "\"" + _s + "\" is an invalid argument."; break;
|
||||
case NO_ARGUMENT_ERROR: str += "No arguments found."; break;
|
||||
case PROCESS_ERROR: str += "Failed to process " + _s; break;
|
||||
case UNKNOWN_ERROR:
|
||||
default: str += "Unknown error."; break;
|
||||
}
|
||||
|
||||
std::cerr << str << "\n";
|
||||
}
|
4
src/generic.cpp
Normal file
4
src/generic.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "../include/generic.hpp"
|
||||
|
||||
Generic::Generic(const std::string &path)
|
||||
: _path(path) {};
|
268
src/install.cpp
268
src/install.cpp
@ -1,268 +0,0 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "../include/rapidjson/document.h"
|
||||
#include "../include/rapidjson/istreamwrapper.h"
|
||||
#include "../include/rapidjson/error/en.h"
|
||||
|
||||
int file_not_exists(const std::string&);
|
||||
int yn_query(const std::string&, bool);
|
||||
|
||||
int install_query(const std::string &hd, const std::string &mod, std::string& ver)
|
||||
{
|
||||
const std::string modjson_path(hd + "/modlist/" + mod + ".json");
|
||||
|
||||
if (file_not_exists(modjson_path))
|
||||
{
|
||||
std::cerr << mod << " not found!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
rapidjson::Document modlist;
|
||||
std::ifstream modjson_stream(modjson_path);
|
||||
rapidjson::IStreamWrapper isw_modlist(modjson_stream);
|
||||
modlist.ParseStream(isw_modlist);
|
||||
|
||||
std::cout << "Name: " << modlist["name"].GetString() << std::endl
|
||||
<< "Author: " << modlist["author"].GetString() << std::endl
|
||||
<< "Last update: " << modlist["update"].GetString() << std::endl;
|
||||
|
||||
const rapidjson::Value& versions = modlist["versions"];
|
||||
|
||||
std::cout << "Latest version: " << versions[0].GetString() << std::endl
|
||||
<< "Available versions: ";
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < versions.Size(); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
std::cout << ", ";
|
||||
}
|
||||
|
||||
std::cout << versions[i].GetString();
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
/* PRE-INSTALLATION PROCESS */
|
||||
/* --VERSION */
|
||||
|
||||
if (yn_query("Are you sure you want to install " + mod + " version " + versions[0].GetString() + "?", true))
|
||||
{
|
||||
ver = versions[0].GetString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (versions.Size() > 1)
|
||||
{
|
||||
// std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
do
|
||||
{
|
||||
std::string install_ver_input;
|
||||
std::cout << "Please type in the version you would like to install [enter q to quit]: ";
|
||||
std::cin.clear();
|
||||
|
||||
std::getline(std::cin, install_ver_input);
|
||||
|
||||
if (install_ver_input == "q" || install_ver_input == "q\n")
|
||||
{
|
||||
std::cout << "Quitting!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << install_ver_input << std::endl;
|
||||
|
||||
bool install_ver_set = false;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < versions.Size(); i++)
|
||||
{
|
||||
if (install_ver_input == versions[i].GetString())
|
||||
{
|
||||
ver = install_ver_input;
|
||||
install_ver_set = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (install_ver_set)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << "Error! " << install_ver_input << " not found in versions list!" << std::endl;
|
||||
} while (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Exiting installation!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Preparing to install " << mod << " version " << ver << "..." << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int install(const std::string &hd, const std::string &mod)
|
||||
{
|
||||
std::string install_ver;
|
||||
if (install_query(hd, mod, install_ver))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* --PACKPREINSTALLATION*/
|
||||
|
||||
const std::string modconfig_path(hd + "/" + mod + "/" + install_ver + "/modconfig.json");
|
||||
|
||||
std::cout << modconfig_path << std::endl;
|
||||
|
||||
if (file_not_exists(modconfig_path))
|
||||
{
|
||||
std::cerr << modconfig_path << " not found!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
rapidjson::Document modconfig;
|
||||
std::ifstream modconfig_stream(modconfig_path);
|
||||
rapidjson::IStreamWrapper isw_config(modconfig_stream);
|
||||
if (modconfig.ParseStream<0>(isw_config).HasParseError())
|
||||
{
|
||||
std::cerr << GetParseError_En(modconfig.GetParseError()) << std::endl;
|
||||
return 1;
|
||||
}
|
||||
modconfig.ParseStream(isw_config);
|
||||
|
||||
std::cout << "CAMPAIGN SELECTION" << std::endl
|
||||
<< "==================" << std::endl;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < modconfig["campaigns"].Size(); i++)
|
||||
{
|
||||
std::cout << "[" << (i+1) << "] " << modconfig["campaigns"][i]["name"].GetString() << std::endl << "Description: " << modconfig["campaigns"][i]["desc"].GetString() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
int campaign_selection, turn_selection;
|
||||
|
||||
/* CAMPAIGN SELECTION */
|
||||
do
|
||||
{
|
||||
char campaign_selection_char;
|
||||
std::cout << std::endl << "Please select a campaign:";
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < modconfig["campaigns"].Size(); i++)
|
||||
{
|
||||
std::cout << " [" << (i+1) << "] " << modconfig["campaigns"][i]["name"].GetString();
|
||||
}
|
||||
|
||||
std::cout << " [press q to exit]" << std::endl;
|
||||
std::cin.get(campaign_selection_char);
|
||||
campaign_selection = campaign_selection_char - '0';
|
||||
if (campaign_selection_char == 'q')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (campaign_selection < 1 || campaign_selection > (int) modconfig["campaigns"].Size())
|
||||
{
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
std::cout << "Error! \"" << campaign_selection_char << "\" is not a valid input." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
|
||||
/* TURN SELECTION */
|
||||
do
|
||||
{
|
||||
char turn_selection_char;
|
||||
std::cout << std::endl << "Please select your preferred number of turns per campaign year:";
|
||||
|
||||
const rapidjson::Value& turns = modconfig["turns"];
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < turns.Size(); i++)
|
||||
{
|
||||
std::cout << " [" << (i+1) << "] " << turns[i]["name"].GetString();
|
||||
}
|
||||
|
||||
std::cout << " [press q to exit]" << std::endl;
|
||||
std::cin.get(turn_selection_char);
|
||||
turn_selection = turn_selection_char - '0';
|
||||
if (turn_selection_char == 'q')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (turn_selection < 1 || turn_selection > (int) turns.Size())
|
||||
{
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
std::cout << "Error! \"" << turn_selection_char << "\" is not a valid input." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
std::cout << std::endl << "You have selected:" << std::endl
|
||||
<< "Campaign: " << modconfig["campaigns"][campaign_selection-1]["name"].GetString() << std::endl
|
||||
<< "Turns: " << modconfig["turns"][turn_selection-1]["name"].GetString() << std::endl << std::endl;
|
||||
|
||||
/* PACKS SELECTION */
|
||||
|
||||
std::cout << "PACK SELECTION" << std::endl
|
||||
<< "==============" << std::endl;
|
||||
|
||||
std::vector<bool> pack_vector;
|
||||
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
// std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
for (rapidjson::SizeType i = 0; i < modconfig["packs"].Size(); i++)
|
||||
{
|
||||
std::cout << std::endl << modconfig["packs"][i]["name"].GetString() << std::endl
|
||||
<< modconfig["packs"][i]["desc"].GetString() << std::endl;
|
||||
|
||||
if (yn_query("Do you want to install this pack?", true))
|
||||
{
|
||||
pack_vector.insert(pack_vector.end(), true);
|
||||
}
|
||||
else pack_vector.insert(pack_vector.end(), false);
|
||||
|
||||
std::cin.clear();
|
||||
}
|
||||
|
||||
/* SELECTION SUMMARY */
|
||||
|
||||
std::cout << "SELECTION SUMMARY" << std::endl
|
||||
<< "=================" << std::endl;
|
||||
|
||||
std::cout << "Campaign: " << modconfig["campaigns"][campaign_selection-1]["name"].GetString() << std::endl
|
||||
<< "Turns: " << modconfig["turns"][turn_selection-1]["name"].GetString() << std::endl
|
||||
<< "Packs: ";
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < modconfig["packs"].Size(); i++)
|
||||
{
|
||||
if (pack_vector[i])
|
||||
{
|
||||
std::cout << modconfig["packs"][i]["name"].GetString();
|
||||
if (i != (modconfig["packs"].Size() - 1))
|
||||
{
|
||||
std::cout << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl << std::endl;
|
||||
|
||||
if (!yn_query("Are you sure you want to install this selection?", true))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
247
src/installationmanager.cpp
Normal file
247
src/installationmanager.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
#include "../include/installationmanager.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
#include <deque>
|
||||
|
||||
#include "../include/exceptionhandler.hpp"
|
||||
#include "../include/query.hpp"
|
||||
#include "../include/rapidjson/istreamwrapper.h"
|
||||
#include "../include/rapidjson/error/en.h"
|
||||
#include "../include/rapidjson/filereadstream.h"
|
||||
|
||||
InstallationManager::InstallationManager(const std::string &hd, const std::string &mod)
|
||||
: _hd(hd), _mod(std::move(mod)) {}
|
||||
|
||||
void InstallationManager::execute()
|
||||
{
|
||||
_version_query();
|
||||
/* --PACKPREINSTALLATION*/
|
||||
|
||||
/* TEMPORARY JSON */
|
||||
const std::string fp = _hd + "/" + _mod + "/" + _ver + "/modconfig.json";
|
||||
_grab_json(std::move(fp), _cfg);
|
||||
/* TEMPORARY JSON */
|
||||
|
||||
_campaign_query();
|
||||
|
||||
std::cout << "\n" << "You have selected:" << "\n";
|
||||
_print_selection(2);
|
||||
|
||||
/* PACKS SELECTION */
|
||||
_pack_query();
|
||||
|
||||
/* SELECTION SUMMARY */
|
||||
_print_title("SELECTION SUMMARY");
|
||||
|
||||
_print_selection(3);
|
||||
|
||||
std::cout << "\n";
|
||||
const Query<bool> query_final = {"Are you sure you want to install this selection?"};
|
||||
if (!query_final.execute(_cfg))
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// INSTALLATION
|
||||
|
||||
std::cout << "Installing " << _modname << " version " << _ver << "...\n";
|
||||
}
|
||||
|
||||
void InstallationManager::_version_query()
|
||||
{
|
||||
/* TEMPORARY JSON */
|
||||
const std::string fp = _hd + "/" + _mod + "/modinfo.json";
|
||||
rapidjson::Document modlist;
|
||||
_grab_json(std::move(fp), modlist);
|
||||
/* TEMPORARY JSON */
|
||||
|
||||
/* Printing mod info */
|
||||
std::cout << "Name: " << modlist["name"].GetString() << "\n"
|
||||
<< "Author: " << modlist["author"].GetString() << "\n"
|
||||
<< "Latest version: " << modlist["versions"][0].GetString() << "\n"
|
||||
<< "Available versions: ";
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < modlist["versions"].Size(); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
std::cout << ", ";
|
||||
}
|
||||
|
||||
std::cout << modlist["versions"][i].GetString();
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
/* PRE-INSTALLATION PROCESS */
|
||||
/* --VERSION */
|
||||
|
||||
const Query<bool> query_verify = {"Are you sure you want to install " + std::string(modlist["name"].GetString()) + " version " + modlist["versions"][0].GetString() + "?"};
|
||||
|
||||
/* Asks user for mod version */
|
||||
if (query_verify.execute(modlist))
|
||||
{
|
||||
_modname = modlist["name"].GetString();
|
||||
_ver = modlist["versions"][0].GetString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modlist["versions"].Size() > 1)
|
||||
{
|
||||
// std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
const Query<std::string> query_version = {"Please specify the version you would like to install", "versions"};
|
||||
_ver = query_version.execute(modlist);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Exiting installation!" << "\n";
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Preparing to install " << _modname << " version " << _ver << "..." << "\n";
|
||||
}
|
||||
|
||||
void InstallationManager::_campaign_query()
|
||||
{
|
||||
_print_title("CAMPAIGN SELECTION");
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < _cfg["campaigns"].Size(); i++)
|
||||
{
|
||||
std::cout << "[" << (i+1) << "] " << _cfg["campaigns"][i]["name"].GetString() << "\n"
|
||||
<< "Description: " << _cfg["campaigns"][i]["desc"].GetString() << "\n" << "\n";
|
||||
}
|
||||
|
||||
/* CAMPAIGN SELECTION */
|
||||
const Query<int> query_campaign = {"Please select your campaign", "campaigns"};
|
||||
_campaigns = query_campaign.execute(_cfg) - 1;
|
||||
/* TURN SELECTION */
|
||||
const Query<int> query_turns = {"Please select your preferred turns per year", "turns"};
|
||||
_turns = query_turns.execute(_cfg) - 1;
|
||||
}
|
||||
|
||||
void InstallationManager::_pack_query()
|
||||
{
|
||||
_print_title("PACK SELECTION");
|
||||
const Query<bool> query_pack = {"Do you want to install this pack?"};
|
||||
for (rapidjson::SizeType i = 0; i < _cfg["packs"].Size(); i++)
|
||||
{
|
||||
std::cout << "\n" << _cfg["packs"][i]["name"].GetString() << "\n"
|
||||
<< _cfg["packs"][i]["desc"].GetString() << "\n";
|
||||
|
||||
_packs.push_back(query_pack.execute(_cfg));
|
||||
|
||||
std::cin.clear();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void InstallationManager::_grab_json(const std::string &path, rapidjson::Document &d)
|
||||
{
|
||||
if ((access(path.c_str(), F_OK) != 0))
|
||||
{
|
||||
throw ExceptionHandler(INVALID_ARGUMENT_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
std::ifstream ifs(path.c_str());
|
||||
rapidjson::IStreamWrapper isw(ifs);
|
||||
d.ParseStream(isw);
|
||||
|
||||
if (d.ParseStream<0>(isw).HasParseError())
|
||||
{
|
||||
std::cerr << "Failed to parse via string stream!" << "\n";
|
||||
std::cerr << "RapidJson ERROR: ";
|
||||
std::cerr << GetParseError_En(d.GetParseError()) << "\n";
|
||||
std::cerr << "Filepath: " << path << "\n";
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "Failed to parse JSON file!");
|
||||
}
|
||||
else
|
||||
{
|
||||
d.ParseStream(isw);
|
||||
return 0;
|
||||
}
|
||||
if (d.Parse<0>(path.c_str()).HasParseError())
|
||||
{
|
||||
std::cerr << "Failed to parse via string!" << "\n";
|
||||
std::cerr << "RapidJson ERROR: ";
|
||||
std::cerr << GetParseError_En(d.GetParseError()) << "\n";
|
||||
std::cerr << "Filepath: " << path << "\n";
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "Failed to parse JSON file!");
|
||||
}
|
||||
{
|
||||
d.Parse(path.c_str());
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
char readBuffer[65536];
|
||||
FILE *fp = fopen(path.c_str(), "r");
|
||||
rapidjson::FileReadStream is(fp, readBuffer, sizeof(readBuffer));
|
||||
|
||||
if (d.ParseStream<0>(is).HasParseError())
|
||||
{
|
||||
std::cerr << "Failed to parse via file stream!" << "\n";
|
||||
std::cerr << "RapidJson ERROR: ";
|
||||
std::cerr << GetParseError_En(d.GetParseError()) << "\n";
|
||||
std::cerr << "Filepath: " << path << "\n";
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "Failed to parse JSON file!");
|
||||
}
|
||||
else
|
||||
{
|
||||
d.ParseStream(is);
|
||||
}
|
||||
}
|
||||
|
||||
void InstallationManager::_print_title(const std::string &str)
|
||||
{
|
||||
std::cout << str << "\n";
|
||||
for (auto i : str)
|
||||
{
|
||||
std::cout << "=";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void InstallationManager::_print_selection(const int i)
|
||||
{
|
||||
std::deque<std::string> print;
|
||||
switch (i)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::vector<std::string> packs;
|
||||
for (rapidjson::SizeType i = 0; i < _cfg["packs"].Size(); i++)
|
||||
{
|
||||
if (_packs[i])
|
||||
{
|
||||
packs.push_back(_cfg["packs"][i]["name"].GetString());
|
||||
}
|
||||
}
|
||||
ss << "Packs: ";
|
||||
for (auto it = packs.begin(); it != packs.end(); ++it)
|
||||
{
|
||||
ss << *it;
|
||||
if (it != (packs.end() - 1))
|
||||
{
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << "\n";
|
||||
print.push_front(ss.str());
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
print.push_front("Turns: " + std::string(_cfg["turns"][_turns]["name"].GetString()) + "\n");
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
print.push_front("Campaign: " + std::string(_cfg["campaigns"][_campaigns]["name"].GetString()) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &i : print) std::cout << i;
|
||||
}
|
73
src/main.cpp
73
src/main.cpp
@ -1,72 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "../include/etw_lmm.hpp"
|
||||
|
||||
/**
|
||||
* Function prototypes
|
||||
*/
|
||||
int list(const std::string&);
|
||||
int calibrate(const std::string&);
|
||||
std::string retrieve_path();
|
||||
void help_menu();
|
||||
int install(const std::string&, const std::string&);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/**
|
||||
* Paths
|
||||
*/
|
||||
const std::string hd = retrieve_path();
|
||||
|
||||
for (unsigned int i = 0; i < path.size(); i++)
|
||||
{
|
||||
path[i].insert(0, hd);
|
||||
}
|
||||
/**
|
||||
* Turning char arguments to string
|
||||
*/
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
|
||||
/**
|
||||
* Argument handler
|
||||
*/
|
||||
if (args[1] == "help")
|
||||
{
|
||||
help_menu();
|
||||
}
|
||||
else if (args[1] == "calibrate")
|
||||
{
|
||||
return calibrate(hd);
|
||||
}
|
||||
else if (args[1] == "list")
|
||||
{
|
||||
return list(hd);
|
||||
}
|
||||
else if (args[1] == "install")
|
||||
{
|
||||
if (argc < 3) // TO DO
|
||||
{
|
||||
std::cerr << "Argument required!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if (install(hd, args[2]))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (args[1] == "uninstall")
|
||||
{
|
||||
|
||||
}
|
||||
else if (args[1] == "query")
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
help_menu();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ETW_LMM lmm(argc, argv);
|
||||
return lmm.execute();
|
||||
}
|
||||
|
89
src/md5.cpp
89
src/md5.cpp
@ -1,89 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h> /* md5sum */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
/**
|
||||
* Get the size of the file by its file descriptor
|
||||
*
|
||||
* @param file_descript
|
||||
*/
|
||||
unsigned long get_size_by_fd(int fd)
|
||||
{
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) < 0)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return statbuf.st_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the MD5 sum as hex-digits.
|
||||
*
|
||||
* @param MD5 checksum
|
||||
*/
|
||||
void print_md5_sum(unsigned char* md5)
|
||||
{
|
||||
for (unsigned int i = 0; i < MD5_DIGEST_LENGTH; i++)
|
||||
{
|
||||
printf("%02x", md5[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts MD5 checksum to hex.
|
||||
*
|
||||
* @param MD5 checksum
|
||||
*/
|
||||
std::string to_hex(unsigned char* md5)
|
||||
{
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
std::string result;
|
||||
|
||||
for (unsigned int i = 0; i < MD5_DIGEST_LENGTH; i++)
|
||||
{
|
||||
result += digits[md5[i] / MD5_DIGEST_LENGTH];
|
||||
result += digits[md5[i] % MD5_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a MD5 checksum and compares it to its corresponding calibrated checksum.
|
||||
*
|
||||
* @param File path to compute checksum, corresponding calibrated checksum
|
||||
*/
|
||||
void md5sum(std::string file_path, unsigned char md5[MD5_DIGEST_LENGTH])
|
||||
{
|
||||
/*
|
||||
* Variable initialisation
|
||||
*/
|
||||
int file_descript;
|
||||
unsigned long file_size;
|
||||
unsigned char* file_buffer;
|
||||
|
||||
/* Checks if the file path can be opened. */
|
||||
file_descript = open(file_path.c_str(), O_RDONLY);
|
||||
if (file_descript < 0)
|
||||
{
|
||||
std::cerr << "Unable to open " << file_path << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Grabs the size of file */
|
||||
file_size = get_size_by_fd(file_descript);
|
||||
|
||||
/* Generates the buffer */
|
||||
file_buffer = (unsigned char*) mmap((caddr_t)0, file_size, PROT_READ, MAP_SHARED, file_descript, 0);
|
||||
|
||||
/* Computes the MD5 checksum to result */
|
||||
MD5(file_buffer, file_size, md5);
|
||||
|
||||
/* Removes fime_buffer and file_size */
|
||||
munmap(file_buffer, file_size);
|
||||
}
|
17
src/md5_wrapper.cpp
Normal file
17
src/md5_wrapper.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <openssl/md5.h> /* md5sum */
|
||||
|
||||
#include "../include/md5_wrapper.hpp"
|
||||
|
||||
MD5_wrapper::MD5_wrapper(unsigned char *md5)
|
||||
{
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
|
||||
for (unsigned int i = 0; i < MD5_DIGEST_LENGTH; i++)
|
||||
{
|
||||
_md5 += digits[md5[i] / MD5_DIGEST_LENGTH];
|
||||
_md5 += digits[md5[i] % MD5_DIGEST_LENGTH];
|
||||
}
|
||||
}
|
||||
|
||||
MD5_wrapper::MD5_wrapper(const std::string &s)
|
||||
: _md5(s) {}
|
116
src/query.cpp
Normal file
116
src/query.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "../include/query.hpp"
|
||||
|
||||
template <>
|
||||
Query<bool>::Query(const std::string &query)
|
||||
: _query(std::move(query)) {}
|
||||
|
||||
template <>
|
||||
Query<int>::Query(const std::string &query, char *list)
|
||||
: _query(std::move(query)), _list(std::move(list)) {}
|
||||
|
||||
template <>
|
||||
Query<std::string>::Query(const std::string &query, char *list)
|
||||
: _query(std::move(query)), _list(std::move(list)) {}
|
||||
|
||||
/*template <class OUTPUT>
|
||||
OUTPUT Query<OUTPUT>::execute()
|
||||
{
|
||||
switch (_qf)
|
||||
{
|
||||
case BOOL: return _bool();
|
||||
case STRING: return _string();
|
||||
case INT: return _int();
|
||||
default:
|
||||
throw ExceptionHandler(CUSTOM_ERROR, "No flag set for query.");
|
||||
}
|
||||
}*/
|
||||
|
||||
template <>
|
||||
bool Query<bool>::execute(const rapidjson::Document &cfg) const
|
||||
{
|
||||
char in;
|
||||
|
||||
do
|
||||
{
|
||||
std::cout << _query << " [Y/n] ";
|
||||
std::cin.get(in);
|
||||
|
||||
switch (in)
|
||||
{
|
||||
case 'N':
|
||||
case 'n': std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return false;
|
||||
case 'Y':
|
||||
case 'y': std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
case '\n': return true;
|
||||
default:
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
std::cerr << "ERROR: \"" << in << "\" is not a valid input!\n";
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string Query<std::string>::execute(const rapidjson::Document &cfg) const
|
||||
{
|
||||
std::string input;
|
||||
|
||||
do
|
||||
{
|
||||
std::cout << _query << " [enter q to quit]" << "\n";
|
||||
std::cin.clear();
|
||||
|
||||
std::cout << ">>> ";
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input == "q" || input == "q\n") { exit(0); }
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < cfg[_list].Size(); i++)
|
||||
{
|
||||
if (input == cfg[_list][i].GetString())
|
||||
{
|
||||
return std::move(input);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Error! \"" << input << "\" not found in " << _list << " list!" << "\n";
|
||||
} while (true);
|
||||
}
|
||||
|
||||
template <>
|
||||
int Query<int>::execute(const rapidjson::Document &cfg) const
|
||||
{
|
||||
char input;
|
||||
int output;
|
||||
|
||||
do
|
||||
{
|
||||
std::cout << "\n" << _query;
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < cfg[_list].Size(); i++)
|
||||
{
|
||||
std::cout << " [" << (i+1) << "] " << cfg[_list][i]["name"].GetString();
|
||||
}
|
||||
|
||||
std::cout << " [press q to exit]" << "\n";
|
||||
|
||||
std::cout << ">>> ";
|
||||
std::cin.get(input);
|
||||
output = input - '0';
|
||||
|
||||
if (input == 'q')
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (output < 1 || output > static_cast<int>(cfg[_list].Size()))
|
||||
{
|
||||
std::cout << "Error! \"" << input << "\" is not a valid input." << "\n";
|
||||
}
|
||||
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
} while (output < 1 || output > static_cast<int>(cfg[_list].Size()));
|
||||
|
||||
return output;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
|
||||
std::string retrieve_path()
|
||||
{
|
||||
/* Retrieve home directory */
|
||||
const char* char_homedir;
|
||||
if ((char_homedir = getenv("HOME")) == NULL)
|
||||
{
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
char_homedir = pw->pw_dir;
|
||||
}
|
||||
|
||||
/* Convert char pointer to string */
|
||||
const std::string s(char_homedir);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int replace_string(const std::string& file, const std::string& old_str, const std::string& new_str)
|
||||
{
|
||||
std::string cmd = "sed -i -- 's/" + old_str + "/" + new_str + "/g' " + file;
|
||||
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
std::cerr << "Failed to calibrate: " << file;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 0 = true
|
||||
* 1 = false
|
||||
*/
|
||||
int dir_not_exists(const std::string& dir)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(dir.c_str(), &sb) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !S_ISDIR(sb.st_mode);
|
||||
}
|
||||
|
||||
int file_not_exists(const std::string& dir)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(dir.c_str(), &sb) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !S_ISREG(sb.st_mode);
|
||||
}
|
||||
|
||||
int yn_query(const std::string& query, bool b_yes)
|
||||
{
|
||||
const std::string str_yn = b_yes ? " [Y/n] " : " [y/N] " ;
|
||||
char yn;
|
||||
|
||||
std::cout << query << str_yn;
|
||||
std::cin.get(yn);
|
||||
|
||||
do
|
||||
{
|
||||
switch (yn)
|
||||
{
|
||||
case 'Y':
|
||||
case 'y': std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return 1;
|
||||
case 'N':
|
||||
case 'n': std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return 0;
|
||||
case '\n': return b_yes ? 1 : 0;
|
||||
default:
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
std::cerr << "Error! \"" << yn << "\" is not a valid input!\n" << query << str_yn;
|
||||
std::cin.get(yn);
|
||||
}
|
||||
} while (1);
|
||||
}
|
Reference in New Issue
Block a user