newtx/sdk/base/utils.h

460 lines
11 KiB
C
Raw Normal View History

2023-12-01 09:17:09 +00:00
// utilities for platform ...
//
// Date: 2023-06-30
//
#pragma once
#include "plat_types.h"
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>
#include <algorithm>
#include <deque>
#include <functional>
#define USE_SAFE_THREAD
enum log_type
{
LOG_TYPE_NONE = 0, // no logging
LOG_TYPE_CONSOLE, // print to console
LOG_TYPE_FILE, // write log into file
};
enum log_level
{
LOG_LEVEL_ALL = 0,
LOG_LEVEL_DEBUG,
LOG_LEVEL_WARNING,
LOG_LEVEL_FATAL,
};
namespace utils
{
std::string utf82ansi(const char* utf8);
std::string ansi2utf8(const char* ansi);
std::string get_command_result(const char* cmd, int len = -1, int *err = nullptr);
std::string get_local_data_path(void);
std::string temporary_path(void);
std::string format_current_time(void);
std::string get_module_full_path(const char* part_name = nullptr/*nullptr to get main-pe/first module's full path*/);
std::string find_file(const char* root_dir, const char* part_name, bool recursive = false);
std::string target_file_from_link(const char* lnk_file);
std::string from_console(const char* tips = nullptr, console_color clr = console_color::COLOR_CHAR_GREEN);
2023-12-01 09:17:09 +00:00
std::string get_ini_value(const char* seg, const char* key, const char* cfg_file); // return "" if not found
std::string load_mini_file(const char* file, int* err); // <= 1MB
int save_2_file(void* data, size_t len, const char* file, bool append = false/*append or new*/, size_t max_size = -1/*in append mode, truncate file if size is exceeded this value if was not -1*/);
void printf_with_color(const char* msg, console_color text_clr, console_color bkg_clr = COLOR_BKG_NONE, console_display_mode mode = console_display_mode::MODE_DEFAULT);
2023-12-01 09:17:09 +00:00
bool is_match_pattern(const char* text, const char* pattern);
const char* to_lower(std::string& str); // return str.c_str()
const char* trim(std::string& str, const char* sp = "\r\n\t "); // return str.c_str()
2023-12-18 01:39:48 +00:00
bool from_hex_string(const char* hex, uint8_t* val);
bool from_hex_string(const char* hex, uint16_t* val);
bool from_hex_string(const char* hex, uint32_t* val);
bool from_hex_string(const char* hex, uint64_t* val);
2023-12-01 09:17:09 +00:00
HMODULE load_dll(const char* path_file, int flag);
bool create_folder(const char* folder);
void set_ini_value(const char* seg, const char* key, const char* val, const char* cfg_file);
int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param);
int move_file(const char* from, const char* to);
2023-12-09 10:21:05 +00:00
int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist
2023-12-01 09:17:09 +00:00
int get_memory_usage(uint64_t* peak, uint64_t* now, uint64_t* phymem, uint32_t pid = -1);
void print_memory_usage(const char* tips, bool to_log_file);
2023-12-01 09:17:09 +00:00
int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block);
unsigned int get_page_size(unsigned int* map_unit = nullptr);
2023-12-09 10:21:05 +00:00
// return logging file path if 'type' was LOG_TYPE_FILE
std::string init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/);
2023-12-01 09:17:09 +00:00
void uninit(void);
void log_info(const char* info, int level = LOG_LEVEL_ALL);
void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ...
int get_log_type(void);
int get_log_level(void);
int copy_log_file_to(const char* dst);
int clear_log_file(void);
2024-01-11 09:59:23 +00:00
// unit convert ...
int mm_2_pixel(float mm, int dpi = 200);
float pixel_2_mm(int px, int dpi = 200);
// bitmap header ...
std::string bitmap_info_header(int pixel_w, int pixel_h, int bpp, int dpix, int dpiy = 0); // return BITMPINFOHEADER + pallete if need. dpiy same as dpix if was ZERO
std::string bitmap_file_header(BITMAPINFOHEADER *lpbi); // return BITMAPFILEHEADER
2023-12-01 09:17:09 +00:00
#if OS_WIN
// Function: pump message recycle (GetMessageW)
//
// Parameters: hwnd - target window
//
// filter_min - the minimal message
//
// filter_max - the maximal message
//
// msghandler - custom message processor
// MSG*, received message by GetMessage
// bool*, return whether user handled the message, no TranslateMessage and DispatchMessage if this was true
//
// Return: whether quit the message recycle
bool run_get_message(HWND hwnd, UINT filter_min = 0, UINT filter_max = 0, std::function<bool(MSG*, bool*)> msghandler = std::function<bool(MSG*, bool*)>());
#endif
template<typename ... Args>
std::string format_string(const char* fmt, Args ... args)
{
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, fmt, args ...);
return buf.get();
}
2023-12-01 09:17:09 +00:00
template<typename ... Args>
void to_log(int level, const char* fmt, Args ... args)
{
if (get_log_type() != LOG_TYPE_NONE && get_log_level() <= level)
{
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, fmt, args ...);
log_info(buf.get(), (log_level)level);
}
}
template<typename ... Args>
void to_log_with_api(bool(*is_enable)(int), void(*log_api)(const char*, int), int level, const char* fmt, Args ... args)
{
if (is_enable(level))
{
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, fmt, args ...);
log_api(buf.get(), (log_level)level);
}
}
template<class T>
T swap_half(T v)
{
T mask = (1 << (sizeof(T) * 4)) - 1,
h = v & mask;
v >>= sizeof(T) * 4;
v &= mask;
h <<= sizeof(T) * 4;
v |= h;
return v;
}
class base64
{
char base64_ind_[128];
char base64_char_[80];
char padding_char_;
bool is_valid_base64_table(const char* table);
bool initialize_base64_table(const char* table);
public:
base64();
~base64();
public:
bool set_base64_table(const char* table = nullptr);
std::string encode(const char* data, size_t bytes, unsigned int line_bytes = -1, bool need_padding = true);
std::string decode(const char* data, size_t bytes);
};
};
#if OS_WIN
struct _time_val
{
time_t tv_sec; /* Seconds. */
time_t tv_usec; /* Microseconds. */
};
typedef struct _time_val TIMEV;
struct timezone
{
int tz_minuteswest; /* Minutes west of GMT. */
int tz_dsttime; /* Nonzero if DST is ever in effect. */
};
int gettimeofday(TIMEV* tv, struct timezone* tz);
#else
#include <sys/time.h>
typedef struct timeval TIMEV;
#endif
// object life referer
//
// derived from 'refer' if your class used in multi-threads
//
#define MUTEX std::mutex
#define LOCK_WITH_NAME(n, v) std::lock_guard<MUTEX> n(v)
#define SIMPLE_LOCK(v) LOCK_WITH_NAME(locker, v)
class refer
{
volatile int32_t ref_;
MUTEX mutex_;
protected:
refer();
virtual ~refer();
virtual void on_born(void);
virtual void on_dead(void);
public:
virtual int32_t add_ref(void);
virtual int32_t release(void);
};
template<class T>
class refer_guard
{
T *obj_ = nullptr;
void clear(void)
{
if(obj_)
obj_->release();
obj_ = nullptr;
}
public:
refer_guard()
{}
refer_guard(T* obj) : obj_(obj)
{}
~refer_guard()
{
clear();
}
public:
void reset(T* obj)
{
clear();
obj_ = obj;
}
T* operator->(void)
{
return obj_;
}
};
2023-12-01 09:17:09 +00:00
// time utility
class chronograph
{
TIMEV bgn_;
public:
chronograph();
~chronograph();
static bool now(TIMEV* tv);
static bool now(uint64_t* seconds, uint64_t* u_seconds);
static std::string now(bool with_ms = true/*whether with milliseconds*/); // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
public:
uint64_t elapse_s(void);
uint64_t elapse_ms(void);
uint64_t elapse_us(void);
void reset(void);
};
// global info
class global_info
{
public:
global_info();
~global_info();
public:
static uint32_t page_size;
static uint32_t page_map_size;
static uint32_t cluster_size;
static uint32_t gray_pallete[256];
};
2023-12-01 09:17:09 +00:00
// event
class platform_event : public refer
{
sem_t sem_;
volatile bool waiting_;
std::string dbg_info_;
bool log_ = true;
public:
platform_event(const char* info = "");
~platform_event();
public:
bool try_wait(void);
bool wait(unsigned timeout = USB_TIMEOUT_INFINITE/*ms*/); // USB_TIMEOUT_INFINITE is waiting unfinite, true when watied and false for wait timeout
void trigger(void);
void reset(void);
2023-12-01 09:17:09 +00:00
bool is_waiting(void);
void enable_log(bool enable);
void set_debug_info(const char* info);
};
// share memory
class shared_memory : public refer
{
unsigned long long key_;
void* obj_;
bool first_;
size_t bytes_;
size_t len_;
void init(void);
void clear(void);
char* get_buf(void);
void release_buf(void* buf);
#if !defined(WIN32) && !defined(_WIN64)
static std::string get_proc_name_by_pid(pid_t pid);
#endif
public:
shared_memory(unsigned long long key, size_t size = 1024);
protected:
~shared_memory();
public:
bool is_ok(void);
bool is_first(void);
std::string read(void);
int write(const char* data, size_t len);
};
template<class T>
class safe_fifo
{
MUTEX lock_;
std::deque<T> que_;
platform_event* wait_;
public:
safe_fifo(const char* who) : wait_(new platform_event(who && *who ? who : "fifo"))
{}
~safe_fifo()
{
wait_->release();
}
public:
size_t save(const T& t, bool notify = false)
{
SIMPLE_LOCK(lock_);
size_t cnt = que_.size();
que_.push_back(std::move(t));
if (notify)
wait_->trigger();
return cnt + 1;
}
bool take(T& t, bool wait = false, uint32_t to_ms = USB_TIMEOUT_INFINITE)
2023-12-01 09:17:09 +00:00
{
if (wait && size() == 0)
{
if(!wait_->wait(to_ms))
return false;
2023-12-01 09:17:09 +00:00
}
{
SIMPLE_LOCK(lock_);
if (que_.size())
{
t = std::move(que_.front());
que_.pop_front();
return true;
}
else
{
return false;
}
}
}
2024-01-27 09:43:13 +00:00
T front(void)
{
SIMPLE_LOCK(lock_);
return que_.front();
}
void pop_front(void)
{
SIMPLE_LOCK(lock_);
que_.pop_front();
}
2023-12-01 09:17:09 +00:00
size_t size(void)
{
SIMPLE_LOCK(lock_);
return que_.size();
}
void clear(void)
{
SIMPLE_LOCK(lock_);
que_.clear();
wait_->reset();
2023-12-01 09:17:09 +00:00
}
void trigger(void)
{
wait_->trigger();
}
void enable_wait_log(bool enable)
{
wait_->enable_log(enable);
}
};
class safe_thread
{
typedef struct _safe_thrd
{
std::string name;
std::shared_ptr<std::thread> thread;
}SAFETHRD;
volatile bool run_ = true;
MUTEX lock_;
std::unique_ptr<std::thread> notify_thread_;
std::vector<SAFETHRD> threads_;
safe_fifo<std::string> excep_que_;
std::function<void(const char*)> excep_handler_ = std::function<void(const char*)>();
2023-12-09 10:21:05 +00:00
void thread_worker(std::function<void(void)> func, std::string name, void* addr);
2023-12-01 09:17:09 +00:00
void thread_notify_exception(void);
public:
safe_thread(void);
~safe_thread();
public:
void set_exception_handler(std::function<void(const char*)> on_exception = std::function<void(const char*)>());
2023-12-09 10:21:05 +00:00
int start(std::function<void(void)> f, const char* thread_name, void* addr = nullptr);
2023-12-01 09:17:09 +00:00
int stop(const char* thread_name);
};