1003 lines
22 KiB
C++
1003 lines
22 KiB
C++
/*
|
||
* TOSLib.cpp
|
||
*
|
||
* Created on: 22 янв. 2023 г.
|
||
* Author: mr_s
|
||
*/
|
||
|
||
#include "TOSLib.hpp"
|
||
#include "boost/regex/v5/icu.hpp"
|
||
#include "boost/regex/v5/regex.hpp"
|
||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||
#include <dlfcn.h>
|
||
#include <filesystem>
|
||
#include <iostream>
|
||
#include <mutex>
|
||
#include <stdexcept>
|
||
#include <string>
|
||
#include <string>
|
||
#define DBOOST_STACKTRACE_USE_ADDR2LINE
|
||
#include <boost/stacktrace.hpp>
|
||
#include <boost/regex.hpp>
|
||
#include <boost/uuid/detail/md5.hpp>
|
||
#include <boost/uuid/detail/sha1.hpp>
|
||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||
#include <boost/archive/iterators/transform_width.hpp>
|
||
#include <boost/nowide/fstream.hpp>
|
||
|
||
namespace TOS {
|
||
|
||
namespace Str {
|
||
|
||
std::vector<std::string> split(const std::string &in, const std::string &delimeter, bool useRegex) {
|
||
if (useRegex) {
|
||
if (maxUnicode(in) != 1) {
|
||
std::u32string u32in = toUStr(in), u32delimeter = toUStr(delimeter);
|
||
|
||
std::vector<std::string> out;
|
||
size_t prev = 0, next = 0;
|
||
|
||
for (boost::u32regex_iterator<std::string::const_iterator> begin(in.begin(), in.end(), boost::make_u32regex(toUStr(delimeter))), end; begin != end; ++begin) {
|
||
out.push_back(std::string(in.data() + prev, begin->position() - prev));
|
||
prev = begin->position() + begin->length(0);
|
||
}
|
||
|
||
out.push_back(std::string(in.data() + prev));
|
||
|
||
return out;
|
||
} else {
|
||
boost::regex pattern(delimeter.begin(), delimeter.end());
|
||
std::vector<std::string> out;
|
||
size_t prev = 0;
|
||
|
||
for (boost::cregex_iterator begin(in.data(), in.data() + in.size(), pattern), end; begin != end; ++begin) {
|
||
if (prev < begin->position())
|
||
out.push_back(std::string(in.data() + prev, begin->position() - prev));
|
||
|
||
prev = begin->position() + begin->length(0);
|
||
}
|
||
|
||
if (prev < in.size())
|
||
out.push_back(std::string(in.data() + prev, in.size() - prev));
|
||
|
||
return out;
|
||
}
|
||
} else {
|
||
size_t prev = 0, next, count = 0;
|
||
|
||
while ((next = in.find(delimeter, prev)) != std::string::npos) {
|
||
count++;
|
||
prev = next + delimeter.size();
|
||
}
|
||
|
||
std::vector<std::string> out(count + 1);
|
||
prev = next = count = 0;
|
||
|
||
while ((next = in.find(delimeter, prev)) != std::string::npos) {
|
||
out[count++] = {in.data() + prev, next - prev};
|
||
prev = next + delimeter.size();
|
||
}
|
||
|
||
out[count] = {in.data() + prev, in.size() - prev};
|
||
|
||
return out;
|
||
}
|
||
}
|
||
|
||
std::string replace(const std::string &in, const std::string &pattern, const std::string &to, bool useRegex)
|
||
{
|
||
std::vector<std::string> views = split(in, pattern, useRegex);
|
||
std::string out;
|
||
|
||
{
|
||
size_t size = views.size() * to.size();
|
||
for(auto &view : views)
|
||
size += view.size();
|
||
|
||
out.reserve(size);
|
||
}
|
||
|
||
for(size_t iter = 0; iter < views.size(); iter++)
|
||
{
|
||
out.append(views[iter]);
|
||
if(iter < views.size()-1)
|
||
out.append(to);
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
bool contains(const std::string &in, const std::string &pattern, bool useRegex)
|
||
{
|
||
if(useRegex)
|
||
return boost::cregex_iterator(in.data(), in.data()+in.size(), boost::regex(pattern.begin(), pattern.end())) != boost::cregex_iterator();
|
||
else
|
||
return in.find(pattern) != std::string::npos;
|
||
}
|
||
|
||
size_t count(const std::string &in, const std::string &pattern)
|
||
{
|
||
return split(in, pattern, false).size();
|
||
}
|
||
|
||
std::optional<std::vector<std::optional<std::string>>> match(const std::string &in, const std::string &pattern)
|
||
{
|
||
boost::smatch xResults;
|
||
bool matched;
|
||
|
||
if(maxUnicode(in) != 1)
|
||
{
|
||
matched = boost::u32regex_match(in, xResults, boost::make_u32regex(toUStr(pattern)));
|
||
} else {
|
||
matched = boost::regex_match(in, xResults, boost::regex(pattern.begin(), pattern.end()));
|
||
}
|
||
|
||
if(!matched)
|
||
return {};
|
||
|
||
std::vector<std::optional<std::string>> data(xResults.size());
|
||
|
||
for(size_t index = 0; index<xResults.size(); index++)
|
||
if(xResults[index].matched)
|
||
data[index].emplace(xResults[index].str());
|
||
|
||
return data;
|
||
}
|
||
|
||
std::wstring toWStr(const std::string &view)
|
||
{
|
||
std::wstring out;
|
||
out.reserve(view.size());
|
||
|
||
for(size_t ret = 0; ret < view.size(); ret++)
|
||
{
|
||
char c = view[ret];
|
||
if((c & 0x80) == 0)
|
||
out += c;
|
||
else if((c & 0xC0) == 0xC0)
|
||
{
|
||
if(ret+1 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80)
|
||
out += (view[ret+1] & 0x3F) | ((view[ret] & 0x1F) << 6);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret--;
|
||
}
|
||
|
||
ret++;
|
||
} else if((c & 0xE0) == 0xE0)
|
||
{
|
||
if(ret+2 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80)
|
||
out += (view[ret+2] & 0x3F) + ((view[ret+1] & 0x3F) << 6) | ((view[ret] & 0xF) << 12);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret -= 2;
|
||
}
|
||
|
||
ret += 2;
|
||
} else if((c & 0xF0) == 0xF0)
|
||
{
|
||
if(ret+3 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80 && (view[ret+3] & 0x80) == 0x80)
|
||
out += (view[ret+3] & 0x3F) | ((view[ret+2] & 0x3F) << 6) | ((view[ret+1] & 0x3F) << 12) | ((view[ret] & 0xF) << 18);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret -= 3;
|
||
}
|
||
|
||
ret += 3;
|
||
}
|
||
}
|
||
|
||
out.shrink_to_fit();
|
||
|
||
return out;
|
||
}
|
||
|
||
std::string toStr(const std::wstring &view)
|
||
{
|
||
int size = 0;
|
||
|
||
for(wchar_t sym : view)
|
||
{
|
||
if(sym & (~0x7F))
|
||
{
|
||
if(sym & (~0x7FF))
|
||
size += 3;
|
||
else
|
||
size += 2;
|
||
} else
|
||
size++;
|
||
}
|
||
|
||
std::string out;
|
||
out.reserve(size);
|
||
|
||
for(wchar_t sym : view)
|
||
{
|
||
if(sym & (~0x7F))
|
||
{
|
||
if(sym & (~0x7FF))
|
||
{
|
||
out += 0xE0 | ((sym >> 12) & 0x0F);
|
||
out += 0x80 | ((sym >> 6) & 0x3F);
|
||
out += 0x80 | (sym & 0x3F);
|
||
} else {
|
||
out += 0xC0 | ((sym >> 6) & 0x1F);
|
||
out += 0x80 | (sym & 0x3F);
|
||
}
|
||
} else
|
||
out += sym;
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
std::u32string toUStr(const std::string &view)
|
||
{
|
||
std::u32string out;
|
||
out.reserve(view.size());
|
||
|
||
for(size_t ret = 0; ret < view.size(); ret++)
|
||
{
|
||
char c = view[ret];
|
||
if((c & 0x80) == 0)
|
||
out += c;
|
||
else if((c & 0xC0) == 0xC0)
|
||
{
|
||
if(ret+1 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80)
|
||
out += (view[ret+1] & 0x3F) | ((view[ret] & 0x1F) << 6);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret--;
|
||
}
|
||
|
||
ret++;
|
||
} else if((c & 0xE0) == 0xE0)
|
||
{
|
||
if(ret+2 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80)
|
||
out += (view[ret+2] & 0x3F) | ((view[ret+1] & 0x3F) << 6) | ((view[ret] & 0xF) << 12);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret-=2;
|
||
}
|
||
|
||
ret += 2;
|
||
} else if((c & 0xF0) == 0xF0)
|
||
{
|
||
if(ret+3 >= view.size())
|
||
out += L'?';
|
||
else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80 && (view[ret+3] & 0x80) == 0x80)
|
||
out += (view[ret+3] & 0x3F) | ((view[ret+2] & 0x3F) << 6) | ((view[ret+1] & 0x3F) << 12) | ((view[ret] & 0xF) << 18);
|
||
else
|
||
{
|
||
out += L'?';
|
||
ret -= 3;
|
||
}
|
||
|
||
ret += 3;
|
||
}
|
||
}
|
||
|
||
out.shrink_to_fit();
|
||
|
||
return out;
|
||
}
|
||
|
||
std::string toStr(const std::u32string &view)
|
||
{
|
||
int size = 0;
|
||
|
||
for(wchar_t sym : view)
|
||
{
|
||
if(sym & (~0x7F))
|
||
{
|
||
if(sym & (~0x7FF))
|
||
size += 4;
|
||
else
|
||
size += 2;
|
||
} else
|
||
size++;
|
||
}
|
||
|
||
std::string out;
|
||
out.reserve(size);
|
||
|
||
for(char32_t sym : view)
|
||
{
|
||
if(sym & (~0x7F))
|
||
{
|
||
if(sym & (~0x7FF))
|
||
{
|
||
out += 0xF0;
|
||
out += 0x80 | ((sym >> 12) & 0x3F);
|
||
out += 0x80 | ((sym >> 6) & 0x3F);
|
||
out += 0x80 | (sym & 0x3F);
|
||
} else {
|
||
out += 0xC0 | ((sym >> 6) & 0x1F);
|
||
out += 0x80 | (sym & 0x3F);
|
||
}
|
||
} else
|
||
out += sym;
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
int maxUnicode(const std::string &view)
|
||
{
|
||
int max = 1;
|
||
char sym;
|
||
|
||
for(size_t iter = 0; iter < view.size(); iter++)
|
||
{
|
||
char c = view[iter];
|
||
if((c & 0xC0) == 0xC0)
|
||
{
|
||
if(2 > max)
|
||
max = 2;
|
||
|
||
iter++;
|
||
} else if((c & 0xE0) == 0xE0)
|
||
{
|
||
if(3 > max)
|
||
max = 3;
|
||
|
||
iter += 2;
|
||
} else if((c & 0xF0) == 0xF0)
|
||
{
|
||
if(4 > max)
|
||
max = 4;
|
||
|
||
iter += 3;
|
||
}
|
||
}
|
||
|
||
return max;
|
||
}
|
||
|
||
std::string toLowerCase(const std::string &view)
|
||
{
|
||
std::u32string out = toUStr(view);
|
||
|
||
for(char32_t &sym : out)
|
||
{
|
||
sym = std::tolower(sym);
|
||
if(sym >= L'А' && sym <= L'Я')
|
||
sym += 32;
|
||
}
|
||
|
||
return toStr(out);
|
||
}
|
||
|
||
std::string toUpperCase(const std::string &view)
|
||
{
|
||
std::u32string out = toUStr(view);
|
||
|
||
for(char32_t &sym : out)
|
||
{
|
||
sym = std::toupper(sym);
|
||
if(sym >= L'а' && sym <= L'я')
|
||
sym -= 32;
|
||
}
|
||
|
||
return toStr(out);
|
||
}
|
||
|
||
float compareRelative(const std::string &left, const std::string &right)
|
||
{
|
||
size_t equals = 0, minSize = std::min(left.size(), right.size());
|
||
for(size_t iter = 0; iter < minSize; iter++)
|
||
if(left[iter] == right[iter])
|
||
equals++;
|
||
|
||
if(!minSize)
|
||
return left.size() == right.size();
|
||
|
||
return float(equals) / float(std::max(left.size(), right.size()));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
namespace Enc {
|
||
|
||
std::string toHex(const uint8_t *begin, size_t size)
|
||
{
|
||
std::string out(size*2, ' ');
|
||
char *data = out.data();
|
||
|
||
for(const uint8_t *end = begin + size; begin != end; begin++)
|
||
{
|
||
*(data++) = "0123456789abcdf"[(*begin >> 4) & 0xf];
|
||
*(data++) = "0123456789abcdf"[*begin & 0xf];
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
void fromHex(const std::string &in, uint8_t *data)
|
||
{
|
||
const char *begin = in.data(), *end = begin + in.size();
|
||
for(; begin != end;)
|
||
{
|
||
*data = 0;
|
||
if(*begin >= 'a')
|
||
*data |= *begin - 'a' + 10;
|
||
else
|
||
*data |= *begin - '0';
|
||
|
||
begin++;
|
||
|
||
if(*begin >= 'a')
|
||
*data |= (*begin - 'a' + 10) << 4;
|
||
else
|
||
*data |= (*begin - '0') << 4;
|
||
|
||
begin++;
|
||
data++;
|
||
}
|
||
}
|
||
|
||
std::string toBase64(const uint8_t *data, size_t size)
|
||
{
|
||
using namespace boost::archive::iterators;
|
||
using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
|
||
auto tmp = std::string(It((const char*) data), It((const char*) data+size));
|
||
return std::string(tmp.append((3 - size % 3) % 3, '=')); //.replace("/", "_").replace("+", "-");
|
||
}
|
||
|
||
ByteBuffer fromBase64(const std::string &view)
|
||
{
|
||
//std::string val = view.replace("_", "/").replace("-", "+").toStr();
|
||
using namespace boost::archive::iterators;
|
||
using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
|
||
std::string out(It(view.begin()), It(view.end()));
|
||
return {out.size(), (const uint8_t*) out.data()};
|
||
}
|
||
|
||
void base64UrlConvert(std::string &in)
|
||
{
|
||
for(char &sym : in)
|
||
{
|
||
if(sym == '_')
|
||
sym = '/';
|
||
else if(sym == '-')
|
||
sym = '+';
|
||
else if(sym == '/')
|
||
sym = '_';
|
||
else if(sym == '+')
|
||
sym = '-';
|
||
}
|
||
}
|
||
|
||
std::string md5(const uint8_t *data, size_t size)
|
||
{
|
||
boost::uuids::detail::md5 md5;
|
||
md5.process_bytes((const char*) data, size);
|
||
unsigned hash[4] = {0};
|
||
md5.get_digest((boost::uuids::detail::md5::digest_type&)hash);
|
||
|
||
char buf[33] = {0};
|
||
|
||
for (int i = 0; i < 4; i++)
|
||
std::sprintf(buf + (i << 3), "%08x", hash[i]);
|
||
|
||
return Str::toLowerCase(buf);
|
||
}
|
||
|
||
std::string sha1(const uint8_t *data, size_t size)
|
||
{
|
||
boost::uuids::detail::sha1 sha1;
|
||
sha1.process_bytes((const char*) data, size);
|
||
unsigned hash[5] = {0};
|
||
sha1.get_digest((boost::uuids::detail::sha1::digest_type&)hash);
|
||
|
||
char buf[41] = {0};
|
||
|
||
for (int i = 0; i < 5; i++)
|
||
std::sprintf(buf + (i << 3), "%08x", hash[i]);
|
||
|
||
return Str::toLowerCase(buf);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
namespace Time {
|
||
|
||
std::string getDateAsString()
|
||
{
|
||
auto time = boost::posix_time::second_clock::local_time().date();
|
||
std::stringstream out;
|
||
out << std::to_string(time.year());
|
||
std::string temp = std::to_string(time.month());
|
||
|
||
out << '.';
|
||
if(temp.size() == 1)
|
||
out << '0';
|
||
out << temp;
|
||
|
||
temp = std::to_string(time.day());
|
||
out << '.';
|
||
if(temp.size() == 1)
|
||
out << '0';
|
||
out << temp;
|
||
|
||
return out.str();
|
||
}
|
||
|
||
std::string getTimeAsString()
|
||
{
|
||
auto day = boost::posix_time::second_clock::local_time().time_of_day();
|
||
std::stringstream out;
|
||
std::string temp = std::to_string(day.hours());
|
||
|
||
if(temp.size() == 1)
|
||
out << '0';
|
||
out << temp;
|
||
|
||
out << ':';
|
||
temp = std::to_string(day.minutes());
|
||
if(temp.size() == 1)
|
||
out << '0';
|
||
out << temp;
|
||
|
||
out << ':';
|
||
temp = std::to_string(day.seconds());
|
||
if(temp.size() == 1)
|
||
out << '0';
|
||
out << temp;
|
||
|
||
return out.str();
|
||
}
|
||
|
||
}
|
||
|
||
std::string makeStacktrace(int stack_up)
|
||
{
|
||
std::vector<std::string> spl = Str::split(boost::stacktrace::to_string(boost::stacktrace::stacktrace()), "\n");
|
||
std::string out;
|
||
for(size_t i = 1+stack_up; i<spl.size(); i++)
|
||
{
|
||
std::stringstream line;
|
||
|
||
if(out.size())
|
||
line.str("\n");
|
||
|
||
if(spl[i].size() > 128)
|
||
line << spl[i].substr(0, 128);
|
||
else
|
||
line << spl[i];
|
||
|
||
if(Str::contains(line.str(), "boost::asio::asio_handler_invoke"))
|
||
break;
|
||
else {
|
||
out += line.str();
|
||
out += '\n';
|
||
}
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
void DynamicLibrary::symbolOut()
|
||
{
|
||
throw std::runtime_error("Символ не привязан");
|
||
}
|
||
|
||
bool DynamicLibrary::IsOverWine = DynamicLibrary::checkWine();
|
||
bool DynamicLibrary::checkWine()
|
||
{
|
||
try {
|
||
DynamicLibrary ntdll("ntdll.dll");
|
||
void *sym = ntdll.getSymbol("wine_get_version");
|
||
return sym;
|
||
} catch(...) {}
|
||
|
||
return false;
|
||
}
|
||
|
||
DynamicLibrary::DynamicLibrary(const std::string &name)
|
||
: Name(name)
|
||
{
|
||
#ifdef _WIN32
|
||
FD = (uint64_t) LoadLibrary(name.toWStr().c_str());
|
||
if (!FD)
|
||
{
|
||
uint64_t err = (uint64_t) GetLastError();
|
||
MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", код ошибки " << err;
|
||
}
|
||
|
||
wchar_t name2[256];
|
||
GetModuleFileName((HMODULE) FD, name2, 256);
|
||
Name = std::wstring(name2);
|
||
#else
|
||
const char* error_msg;
|
||
FD = uint64_t(dlopen(name.data(), RTLD_NOW | RTLD_GLOBAL));
|
||
if(!FD)
|
||
{
|
||
error_msg = dlerror();
|
||
|
||
std::stringstream info;
|
||
info << "Библиотека " << name << " не найдена";
|
||
if(error_msg)
|
||
info << ": " << error_msg;
|
||
|
||
throw std::runtime_error(info.str());
|
||
}
|
||
|
||
try {
|
||
std::ifstream r("/proc/self/maps");
|
||
std::string str;
|
||
char path[256] = "";
|
||
|
||
while (std::getline(r, str)) {
|
||
if (sscanf(str.c_str(), "%*llx-%*llx %*s %*s %*s %*s %s", path) == 1) {
|
||
if(Str::contains(path, name))
|
||
{
|
||
Path = path;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
} catch(...) {
|
||
Path = name;
|
||
}
|
||
|
||
if(Path.empty())
|
||
Path = name;
|
||
|
||
|
||
// if(!FD && (!error_msg || String(error_msg).contains("No such file or directory")))
|
||
// {
|
||
|
||
// auto lock = LD_LIBRARY_PATH.lockRead();
|
||
// for(int id = 0; id<3 && !FD; id++)
|
||
// for(const File &str : *lock)
|
||
// {
|
||
// if(str.isExist() && str.isDir())
|
||
// for(File f : str.getSubFiles())
|
||
// {
|
||
// if(f.isDir() || !f.isReal())
|
||
// continue;
|
||
|
||
// if((id == 0 && f.getFilename().starts_with("lib" << name << ".so"))
|
||
// || (id == 1 && TOS::REGEX::match("^lib" << name << ".*" << "\\.so", f.getFilename()))
|
||
// || (id == 2 && f.getFilename().starts_with(name) && f.getFilename().contains(".so"))
|
||
// )
|
||
// {
|
||
// FD = uint64_t(dlopen(f.getFullPathFile().getPath().toCStr(), RTLD_LAZY | RTLD_GLOBAL));
|
||
|
||
// if(FD)
|
||
// {
|
||
// loaded = f;
|
||
// Path = f.getFullPathFile().getPath();
|
||
// break;
|
||
// } else {
|
||
// error_msg = dlerror();
|
||
// MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", ошибка: " << error_msg;
|
||
// }
|
||
// }
|
||
// }
|
||
// if(FD)
|
||
// break;
|
||
// }
|
||
// }
|
||
|
||
// if(!FD)
|
||
// MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", ошибка: " << error_msg;
|
||
|
||
// Dl_info info;
|
||
// if(!Path.size())
|
||
// {
|
||
// if(dladdr((void*) FD, &info) && info.dli_fname && (!*info.dli_fname || *info.dli_fname == '/'))
|
||
// Path = info.dli_fname;
|
||
// else
|
||
// Path = File(name).getPath();
|
||
// }
|
||
|
||
// LOGGER.debug() << "Запрос " << name << "; найдено " << Path;
|
||
|
||
#endif
|
||
}
|
||
|
||
DynamicLibrary::~DynamicLibrary()
|
||
{
|
||
if(!FD)
|
||
return;
|
||
|
||
#ifdef _WIN32
|
||
FreeLibrary((HMODULE) FD);
|
||
#else
|
||
dlclose((void*) FD);
|
||
#endif
|
||
}
|
||
|
||
void* DynamicLibrary::getSymbol(const std::string &name) const
|
||
{
|
||
#ifdef _WIN32
|
||
void *sym = (void*) GetProcAddress((HMODULE) FD, name.toCStr());
|
||
if(!sym)
|
||
{
|
||
uint64_t error = (uint64_t) GetLastError();
|
||
MAKE_ERROR("Ошибка загрузки символа " << name << " в библиотеке " << Name << ", код ошибки " << error);
|
||
}
|
||
return sym;
|
||
#else
|
||
void *sym = dlsym((void*) FD, name.data());
|
||
if(!sym)
|
||
{
|
||
const char* str = dlerror();
|
||
MAKE_ERROR("Ошибка загрузки символа " << name << " в библиотеке " << Name << ", ошибка: " << str);
|
||
}
|
||
return sym;
|
||
#endif
|
||
}
|
||
|
||
void* DynamicLibrary::takeSymbol(const std::string &name) const
|
||
{
|
||
#ifdef _WIN32
|
||
void *sym = (void*) GetProcAddress((HMODULE) FD, name.toCStr());
|
||
if(!sym)
|
||
sym = (void*) &symbolOut;
|
||
return sym;
|
||
#else
|
||
void *sym = dlsym((void*) FD, name.data());
|
||
if(!sym)
|
||
sym = (void*) &symbolOut;
|
||
return sym;
|
||
#endif
|
||
}
|
||
|
||
void* DynamicLibrary::getDynamicSymbol(const std::string &name)
|
||
{
|
||
#ifdef _WIN32
|
||
void *sym = (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr());
|
||
if(!sym)
|
||
{
|
||
uint64_t error = (uint64_t) GetLastError();
|
||
MAKE_ERROR("Ошибка загрузки символа " << name << " в общем пространстве символов, код ошибки " << error);
|
||
}
|
||
return sym;
|
||
#else
|
||
void *sym = dlsym((void*) RTLD_DEFAULT, name.data());
|
||
if(!sym)
|
||
{
|
||
const char* str = dlerror();
|
||
MAKE_ERROR("Ошибка загрузки символа " << name << " в общем пространстве символов, ошибка: " << str);
|
||
}
|
||
return sym;
|
||
#endif
|
||
}
|
||
|
||
void* DynamicLibrary::takeDynamicSymbol(const std::string &name)
|
||
{
|
||
#ifdef _WIN32
|
||
void *sym = (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr());
|
||
if(!sym)
|
||
sym = (void*) &symbolOut;
|
||
return sym;
|
||
#else
|
||
void *sym = dlsym((void*) RTLD_DEFAULT, name.data());
|
||
if(!sym)
|
||
sym = (void*) &symbolOut;
|
||
return sym;
|
||
#endif
|
||
}
|
||
|
||
void* DynamicLibrary::hasDynamicSymbol(const std::string &name)
|
||
{
|
||
#ifdef _WIN32
|
||
return (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr());
|
||
#else
|
||
return dlsym((void*) RTLD_DEFAULT, name.data());
|
||
#endif
|
||
}
|
||
|
||
void DynamicLibrary::needGlobalLibraryTemplate(const std::string &name)
|
||
{
|
||
}
|
||
|
||
|
||
std::vector<std::filesystem::path> DynamicLibrary::getLdPaths()
|
||
{
|
||
std::vector<std::filesystem::path> paths;
|
||
#ifdef _WIN32
|
||
#else
|
||
const char *str = getenv("PATH");
|
||
|
||
if(str)
|
||
for(auto &iter : Str::split(str, ":"))
|
||
paths.push_back(iter);
|
||
|
||
str = getenv("LD_LIBRARY_PATH");
|
||
|
||
if(str)
|
||
for(auto &iter : Str::split(str, ":"))
|
||
paths.push_back(iter);
|
||
#endif
|
||
|
||
return paths;
|
||
}
|
||
|
||
struct LogFile {
|
||
boost::u32regex RegexForPath;
|
||
boost::nowide::ofstream Write;
|
||
EnumLogType Levels;
|
||
uint32_t LastLoggedDay = 0;
|
||
|
||
LogFile(const std::string ®ex_for_path, EnumLogType levels, const std::filesystem::path &path)
|
||
: RegexForPath(boost::make_u32regex(Str::toUStr(regex_for_path))),
|
||
Levels(levels),
|
||
Write(path, std::ios::out | std::ios::binary | std::ios::app)
|
||
{}
|
||
|
||
LogFile(const LogFile&) = delete;
|
||
LogFile(LogFile&&) = default;
|
||
LogFile& operator=(const LogFile&) = delete;
|
||
LogFile& operator=(LogFile&&) = default;
|
||
};
|
||
|
||
struct LogCmd {
|
||
boost::u32regex RegexForPath;
|
||
EnumLogType Levels;
|
||
|
||
LogCmd(const std::string &view, EnumLogType levels)
|
||
: RegexForPath(boost::make_u32regex(Str::toUStr(view))),
|
||
Levels(levels)
|
||
{}
|
||
|
||
LogCmd(const LogCmd&) = delete;
|
||
LogCmd(LogCmd&&) = default;
|
||
LogCmd& operator=(const LogCmd&) = delete;
|
||
LogCmd& operator=(LogCmd&&) = default;
|
||
};
|
||
|
||
static std::mutex LogFilesMtx;
|
||
static std::vector<LogFile> LogFiles;
|
||
static std::vector<LogCmd> LogRegexs;
|
||
static uint32_t LogCmdLastDay = Time::getDay();
|
||
|
||
LogSession::LogSession(const std::string &path, EnumLogType type)
|
||
: Path(path)
|
||
{
|
||
{
|
||
std::lock_guard lock(LogFilesMtx);
|
||
|
||
for(auto &iter : LogRegexs)
|
||
if(int(type) & int(iter.Levels) && boost::u32regex_match(path.data(), iter.RegexForPath))
|
||
{
|
||
NeedC = true;
|
||
break;
|
||
}
|
||
|
||
for(auto &iter : LogFiles)
|
||
if(int(type) & int(iter.Levels) && boost::u32regex_match(path.data(), iter.RegexForPath))
|
||
{
|
||
NeedF = true;
|
||
break;
|
||
}
|
||
|
||
if(!NeedF && !NeedC)
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
*this << char(27) << '[';
|
||
switch(type) {
|
||
case EnumLogType::Debug: *this << "37"; break;
|
||
case EnumLogType::Info: *this << "36"; break;
|
||
case EnumLogType::Warn: *this << "33"; break;
|
||
case EnumLogType::Error: *this << "31"; break;
|
||
case EnumLogType::All: *this << "35"; break;
|
||
default: break;
|
||
}
|
||
|
||
*this << "m[" << Time::getTimeAsString() << ' ' << path << '-';
|
||
switch(type) {
|
||
case EnumLogType::Debug: *this << 'D'; break;
|
||
case EnumLogType::Info: *this << 'I'; break;
|
||
case EnumLogType::Warn: *this << 'W'; break;
|
||
case EnumLogType::Error: *this << 'E'; break;
|
||
case EnumLogType::All: *this << '%'; break;
|
||
default: break;
|
||
}
|
||
|
||
*this << "]: " << char(27) << "[0m";
|
||
}
|
||
|
||
LogSession::~LogSession()
|
||
{
|
||
if(!NeedF && !NeedC)
|
||
return;
|
||
|
||
std::lock_guard lock(LogFilesMtx);
|
||
|
||
if(NeedF)
|
||
{
|
||
for(auto &iter : LogFiles)
|
||
if(boost::u32regex_match(Path.data(), iter.RegexForPath))
|
||
{
|
||
uint32_t day = Time::getDay();
|
||
if(iter.LastLoggedDay != day)
|
||
{
|
||
iter.LastLoggedDay = day;
|
||
std::stringstream date;
|
||
date << " -*[ " << Time::getDateAsString() << " ]*-\n";
|
||
iter.Write << date.str() << std::endl;
|
||
}
|
||
|
||
iter.Write << Str::replace(str(), "\n", "\n\t") << std::endl;
|
||
iter.Write.flush();
|
||
}
|
||
}
|
||
|
||
if(NeedC)
|
||
{
|
||
uint32_t day = Time::getDay();
|
||
if(LogCmdLastDay != day)
|
||
{
|
||
LogCmdLastDay = day;
|
||
std::stringstream date;
|
||
date << " -*[ " << Time::getDateAsString() << " ]*-\n";
|
||
std::cout << date.str() << std::endl;
|
||
}
|
||
|
||
std::cout << Str::replace(str(), "\n", "\n\t") << std::endl;
|
||
std::cout.flush();
|
||
}
|
||
}
|
||
|
||
void Logger::addLogFile(const std::string ®ex_for_path, EnumLogType levels, const std::filesystem::path &file, bool rewrite)
|
||
{
|
||
if(rewrite && std::filesystem::exists(file))
|
||
std::filesystem::remove(file);
|
||
|
||
std::lock_guard lock(LogFilesMtx);
|
||
LogFiles.emplace_back(regex_for_path, levels, file);
|
||
}
|
||
|
||
void Logger::addLogOutput(const std::string ®ex_for_path, EnumLogType levels)
|
||
{
|
||
std::lock_guard lock(LogFilesMtx);
|
||
LogRegexs.emplace_back(regex_for_path, levels);
|
||
}
|
||
|
||
static bool exec = [](){
|
||
std::cout.sync_with_stdio(false);
|
||
return false;
|
||
}();
|
||
|
||
namespace TIME {
|
||
|
||
size_t getSeconds()
|
||
{
|
||
static size_t val1 = 0, val2 = 0;
|
||
size_t time = boost::posix_time::second_clock::local_time().time_of_day().total_seconds();
|
||
if(time < val1)
|
||
val2++;
|
||
val1 = time;
|
||
return val2*86400+time;
|
||
}
|
||
|
||
}
|
||
|
||
} /* namespace TOS */
|