2013-12-19 17:10:14 +00:00
|
|
|
#pragma once
|
|
|
|
#include "types.h"
|
2021-10-16 15:56:21 +00:00
|
|
|
#include "md5/md5.h"
|
2020-03-28 16:58:01 +00:00
|
|
|
|
2020-04-09 09:44:19 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
2023-01-21 15:59:38 +00:00
|
|
|
#include <condition_variable>
|
|
|
|
#include <cstring>
|
|
|
|
#include <mutex>
|
2020-04-04 08:53:19 +00:00
|
|
|
#include <thread>
|
2023-05-09 20:35:25 +00:00
|
|
|
#include <vector>
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2019-08-25 16:38:36 +00:00
|
|
|
#ifdef __ANDROID__
|
2013-12-19 17:10:14 +00:00
|
|
|
#include <sys/mman.h>
|
|
|
|
#undef PAGE_MASK
|
2021-08-06 08:30:30 +00:00
|
|
|
#elif defined(__APPLE__) && defined(__aarch64__)
|
2021-07-23 20:34:12 +00:00
|
|
|
#define PAGE_SIZE 16384
|
|
|
|
#else
|
2013-12-19 17:10:14 +00:00
|
|
|
#define PAGE_SIZE 4096
|
2021-07-23 20:34:12 +00:00
|
|
|
#endif
|
2023-01-30 09:40:07 +00:00
|
|
|
#ifndef PAGE_MASK
|
2013-12-19 17:10:14 +00:00
|
|
|
#define PAGE_MASK (PAGE_SIZE-1)
|
2023-01-30 09:40:07 +00:00
|
|
|
#endif
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2020-04-04 08:53:19 +00:00
|
|
|
class cThread
|
|
|
|
{
|
2013-12-19 17:10:14 +00:00
|
|
|
private:
|
2020-04-04 08:53:19 +00:00
|
|
|
typedef void* ThreadEntryFP(void* param);
|
2019-04-27 12:08:43 +00:00
|
|
|
ThreadEntryFP* entry;
|
2013-12-19 17:10:14 +00:00
|
|
|
void* param;
|
2020-04-04 08:53:19 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
std::thread thread;
|
2019-04-27 12:08:43 +00:00
|
|
|
|
|
|
|
cThread(ThreadEntryFP* function, void* param)
|
2020-04-04 08:53:19 +00:00
|
|
|
:entry(function), param(param) {}
|
2019-04-27 12:08:43 +00:00
|
|
|
~cThread() { WaitToEnd(); }
|
2013-12-19 17:10:14 +00:00
|
|
|
void Start();
|
|
|
|
void WaitToEnd();
|
|
|
|
};
|
2019-04-27 12:08:43 +00:00
|
|
|
|
2013-12-19 17:10:14 +00:00
|
|
|
class cResetEvent
|
|
|
|
{
|
|
|
|
private:
|
2020-04-02 16:48:23 +00:00
|
|
|
std::mutex mutx;
|
|
|
|
std::condition_variable cond;
|
2019-04-27 12:08:43 +00:00
|
|
|
bool state;
|
2013-12-19 17:10:14 +00:00
|
|
|
|
|
|
|
public :
|
2019-04-27 12:08:43 +00:00
|
|
|
cResetEvent();
|
2013-12-19 17:10:14 +00:00
|
|
|
~cResetEvent();
|
|
|
|
void Set(); //Set state to signaled
|
|
|
|
void Reset(); //Set state to non signaled
|
2018-10-29 19:03:47 +00:00
|
|
|
bool Wait(u32 msec);//Wait for signal , then reset[if auto]. Returns false if timed out
|
2013-12-19 17:10:14 +00:00
|
|
|
void Wait(); //Wait for signal , then reset[if auto]
|
|
|
|
};
|
|
|
|
|
2020-03-29 17:29:14 +00:00
|
|
|
void set_user_config_dir(const std::string& dir);
|
|
|
|
void set_user_data_dir(const std::string& dir);
|
|
|
|
void add_system_config_dir(const std::string& dir);
|
|
|
|
void add_system_data_dir(const std::string& dir);
|
2015-08-22 19:49:12 +00:00
|
|
|
|
2020-03-29 17:29:14 +00:00
|
|
|
std::string get_writable_config_path(const std::string& filename);
|
|
|
|
std::string get_writable_data_path(const std::string& filename);
|
|
|
|
std::string get_readonly_config_path(const std::string& filename);
|
|
|
|
std::string get_readonly_data_path(const std::string& filename);
|
|
|
|
bool file_exists(const std::string& filename);
|
|
|
|
bool make_directory(const std::string& path);
|
|
|
|
|
2021-03-02 17:45:18 +00:00
|
|
|
// returns a prefix for a game save file, for example: ~/.local/share/flycast/mvsc2.zip
|
2020-03-29 17:29:14 +00:00
|
|
|
std::string get_game_save_prefix();
|
2021-03-02 17:45:18 +00:00
|
|
|
// returns the position of the last path separator, or string::npos if none
|
2020-11-26 15:45:57 +00:00
|
|
|
size_t get_last_slash_pos(const std::string& path);
|
2020-03-29 17:29:14 +00:00
|
|
|
|
2023-01-30 09:40:07 +00:00
|
|
|
class RamRegion
|
|
|
|
{
|
|
|
|
u8 *data;
|
|
|
|
size_t size;
|
|
|
|
bool ownsMemory = false;
|
|
|
|
|
2019-05-11 20:09:52 +00:00
|
|
|
public:
|
2023-01-30 09:40:07 +00:00
|
|
|
void alloc(size_t size);
|
|
|
|
void free();
|
|
|
|
|
|
|
|
void setRegion(u8 *data, size_t size)
|
|
|
|
{
|
|
|
|
this->data = data;
|
|
|
|
this->size = size;
|
|
|
|
ownsMemory = false;
|
|
|
|
}
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2023-01-30 09:40:07 +00:00
|
|
|
void zero() {
|
2020-03-29 17:29:14 +00:00
|
|
|
std::memset(data, 0, size);
|
2019-05-11 20:09:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 09:40:07 +00:00
|
|
|
u8& operator [](size_t i) {
|
2013-12-19 17:10:14 +00:00
|
|
|
return data[i];
|
|
|
|
}
|
2023-01-30 09:40:07 +00:00
|
|
|
|
|
|
|
void serialize(Serializer &ser) const;
|
|
|
|
void deserialize(Deserializer &deser);
|
2013-12-19 17:10:14 +00:00
|
|
|
};
|
2020-04-09 09:44:19 +00:00
|
|
|
|
|
|
|
static inline void string_tolower(std::string& s)
|
|
|
|
{
|
|
|
|
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); });
|
|
|
|
}
|
|
|
|
|
2023-09-20 15:22:28 +00:00
|
|
|
static inline void string_toupper(std::string& s)
|
|
|
|
{
|
|
|
|
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); });
|
|
|
|
}
|
|
|
|
|
2020-04-09 09:44:19 +00:00
|
|
|
static inline std::string get_file_extension(const std::string& s)
|
|
|
|
{
|
|
|
|
size_t dot = s.find_last_of('.');
|
|
|
|
if (dot == std::string::npos)
|
|
|
|
return "";
|
|
|
|
std::string ext = s.substr(dot + 1, s.length() - dot - 1);
|
|
|
|
string_tolower(ext);
|
|
|
|
return ext;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline std::string get_file_basename(const std::string& s)
|
|
|
|
{
|
|
|
|
size_t dot = s.find_last_of('.');
|
|
|
|
if (dot == std::string::npos)
|
|
|
|
return s;
|
|
|
|
return s.substr(0, dot);
|
|
|
|
}
|
2020-12-28 10:31:26 +00:00
|
|
|
|
|
|
|
static inline std::string trim_trailing_ws(const std::string& str,
|
|
|
|
const std::string& whitespace = " ")
|
|
|
|
{
|
|
|
|
const auto strEnd = str.find_last_not_of(whitespace);
|
|
|
|
if (strEnd == std::string::npos)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
return str.substr(0, strEnd + 1);
|
|
|
|
}
|
2021-10-10 15:24:17 +00:00
|
|
|
|
|
|
|
static inline std::string trim_ws(const std::string& str,
|
|
|
|
const std::string& whitespace = " ")
|
|
|
|
{
|
|
|
|
const auto strStart = str.find_first_not_of(whitespace);
|
|
|
|
if (strStart == std::string::npos)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
return str.substr(strStart, str.find_last_not_of(whitespace) + 1 - strStart);
|
|
|
|
}
|
2021-10-16 15:56:21 +00:00
|
|
|
|
|
|
|
class MD5Sum
|
|
|
|
{
|
|
|
|
MD5_CTX ctx;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MD5Sum() {
|
|
|
|
MD5_Init(&ctx);
|
|
|
|
}
|
|
|
|
|
2021-12-11 17:33:28 +00:00
|
|
|
MD5Sum& add(const void *data, unsigned long len) {
|
2021-10-16 15:56:21 +00:00
|
|
|
MD5_Update(&ctx, data, len);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
MD5Sum& add(std::FILE *file) {
|
|
|
|
std::fseek(file, 0, SEEK_SET);
|
|
|
|
char buf[4096];
|
2021-12-11 17:33:28 +00:00
|
|
|
unsigned long len = 0;
|
|
|
|
while ((len = (unsigned long)std::fread(buf, 1, sizeof(buf), file)) > 0)
|
2021-10-16 15:56:21 +00:00
|
|
|
MD5_Update(&ctx, buf, len);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
MD5Sum& add(const T& v) {
|
2021-12-11 17:33:28 +00:00
|
|
|
MD5_Update(&ctx, &v, (unsigned long)sizeof(T));
|
2021-10-16 15:56:21 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
MD5Sum& add(const std::vector<T>& v) {
|
2023-06-04 10:48:50 +00:00
|
|
|
MD5_Update(&ctx, v.data(), (unsigned long)(v.size() * sizeof(T)));
|
2021-10-16 15:56:21 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getDigest(u8 digest[16]) {
|
|
|
|
MD5_Final(digest, &ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<u8> getDigest() {
|
|
|
|
std::vector<u8> v(16);
|
|
|
|
MD5_Final(v.data(), &ctx);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
};
|