mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2025-12-05 11:44:53 +01:00
Update Nemirtingas overlay to latest.
This commit is contained in:
parent
df94c38b0f
commit
c17fb0c931
82 changed files with 48737 additions and 59872 deletions
116
overlay_experimental/System/ClassEnumUtils.hpp
Normal file
116
overlay_experimental/System/ClassEnumUtils.hpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace System {
|
||||
template<typename Enum>
|
||||
struct EnableBitMaskOperators
|
||||
{
|
||||
static constexpr bool enable = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr typename std::underlying_type<T>::type GetEnumValue(T enum_value)
|
||||
{
|
||||
return static_cast<typename std::underlying_type<T>::type>(enum_value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||
operator |(Enum lhs, Enum rhs)
|
||||
{
|
||||
using underlying = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<Enum> (
|
||||
static_cast<underlying>(lhs) |
|
||||
static_cast<underlying>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||
operator &(Enum lhs, Enum rhs)
|
||||
{
|
||||
using underlying = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<Enum> (
|
||||
static_cast<underlying>(lhs) &
|
||||
static_cast<underlying>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||
operator ^(Enum lhs, Enum rhs)
|
||||
{
|
||||
using underlying = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<Enum> (
|
||||
static_cast<underlying>(lhs) ^
|
||||
static_cast<underlying>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||
operator ~(Enum lhs)
|
||||
{
|
||||
using underlying = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<Enum> (~static_cast<underlying>(lhs));
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||
operator |=(Enum& lhs, Enum rhs)
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||
operator &=(Enum& lhs, Enum rhs)
|
||||
{
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||
operator ^=(Enum& lhs, Enum rhs)
|
||||
{
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename Enum>
|
||||
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, bool>::type
|
||||
operator !(Enum lhs)
|
||||
{
|
||||
using underlying = typename std::underlying_type<Enum>::type;
|
||||
return !static_cast<underlying>(lhs);
|
||||
}
|
||||
|
||||
#define UTILS_ENABLE_BITMASK_OPERATORS(T) \
|
||||
template<> \
|
||||
struct System::EnableBitMaskOperators<T> \
|
||||
{ \
|
||||
static constexpr bool enable = true; \
|
||||
}
|
||||
45
overlay_experimental/System/ConstExpressions.hpp
Normal file
45
overlay_experimental/System/ConstExpressions.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
|
||||
namespace System {
|
||||
namespace ConstExpr {
|
||||
template<typename T, size_t N>
|
||||
constexpr size_t CountOf(T(&)[N])
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
constexpr size_t StrLen(T(&)[N])
|
||||
{
|
||||
return N-1;
|
||||
}
|
||||
|
||||
// Sum of all parameter pack sizeof
|
||||
template <typename... Ts>
|
||||
constexpr size_t size_of = 0;
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
constexpr size_t size_of<T, Ts...> = sizeof(T) + size_of<Ts...>;
|
||||
}
|
||||
}
|
||||
127
overlay_experimental/System/Encoding.cpp
Normal file
127
overlay_experimental/System/Encoding.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "System_internals.h"
|
||||
|
||||
#include "Encoding.hpp"
|
||||
#include "utfcpp/utf8.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace System {
|
||||
namespace Encoding {
|
||||
|
||||
namespace details {
|
||||
template<typename T, size_t s = sizeof(typename T::value_type)>
|
||||
struct string_deducer
|
||||
{
|
||||
static std::string convert_string(T const& str) = delete;
|
||||
static std::wstring convert_wstring(T const& str) = delete;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct string_deducer<T, 1>
|
||||
{
|
||||
static std::string convert_string(T const& str)
|
||||
{
|
||||
return std::string(std::begin(str), std::end(str));
|
||||
}
|
||||
|
||||
static std::wstring convert_wstring(std::string const& str)
|
||||
{
|
||||
std::wstring r(std::begin(str), std::end(str));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct string_deducer<T, 2>
|
||||
{
|
||||
static std::string convert_string(T const& str)
|
||||
{
|
||||
std::string r;
|
||||
utf8::utf16to8(std::begin(str), std::end(str), std::back_inserter(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static std::wstring convert_wstring(std::string const& str)
|
||||
{
|
||||
std::wstring r;
|
||||
utf8::utf8to16(std::begin(str), std::end(str), std::back_inserter(r));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct string_deducer<T, 4>
|
||||
{
|
||||
static std::string convert_string(T const& str)
|
||||
{
|
||||
std::string r;
|
||||
utf8::utf32to8(std::begin(str), std::end(str), std::back_inserter(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static std::wstring convert_wstring(std::string const& str)
|
||||
{
|
||||
std::wstring r;
|
||||
utf8::utf8to32(std::begin(str), std::end(str), std::back_inserter(r));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::wstring Utf8ToWChar(std::string const& str)
|
||||
{
|
||||
return details::string_deducer<std::wstring>::convert_wstring(str);
|
||||
}
|
||||
|
||||
std::u16string Utf8ToUtf16(std::string const& str)
|
||||
{
|
||||
return utf8::utf8to16(str);
|
||||
}
|
||||
|
||||
std::u32string Utf8ToUtf32(std::string const& str)
|
||||
{
|
||||
return utf8::utf8to32(str);
|
||||
}
|
||||
|
||||
std::string WCharToUtf8(std::wstring const& str)
|
||||
{
|
||||
return details::string_deducer<std::wstring>::convert_string(str);
|
||||
}
|
||||
|
||||
std::string Utf16ToUtf8(std::u16string const& str)
|
||||
{
|
||||
return utf8::utf16to8(str);
|
||||
}
|
||||
|
||||
std::string Utf32ToUtf8(std::u32string const& str)
|
||||
{
|
||||
return utf8::utf32to8(str);
|
||||
}
|
||||
|
||||
size_t EncodedLength(std::string const& str)
|
||||
{
|
||||
return utf8::distance(str.begin(), str.end());
|
||||
}
|
||||
|
||||
}// namespace Encoding
|
||||
}// namespace System
|
||||
43
overlay_experimental/System/Encoding.hpp
Normal file
43
overlay_experimental/System/Encoding.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with the System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
namespace Encoding {
|
||||
|
||||
std::wstring Utf8ToWChar(std::string const& str);
|
||||
|
||||
std::u16string Utf8ToUtf16(std::string const& str);
|
||||
|
||||
std::u32string Utf8ToUtf32(std::string const& str);
|
||||
|
||||
std::string WCharToUtf8(std::wstring const& str);
|
||||
|
||||
std::string Utf16ToUtf8(std::u16string const& str);
|
||||
|
||||
std::string Utf32ToUtf8(std::u32string const& str);
|
||||
|
||||
// Size of UTF8 chars (not the size of the byte buffer).
|
||||
size_t EncodedLength(std::string const& str);
|
||||
|
||||
}
|
||||
}
|
||||
128
overlay_experimental/System/Endianness.hpp
Normal file
128
overlay_experimental/System/Endianness.hpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint*_t
|
||||
|
||||
namespace System {
|
||||
class Endian
|
||||
{
|
||||
private:
|
||||
template<typename T, size_t byte_count>
|
||||
struct ByteSwapImpl
|
||||
{
|
||||
constexpr static inline T swap(T v)
|
||||
{
|
||||
for (int i = 0; i < (byte_count/2); ++i)
|
||||
{
|
||||
uint8_t tmp = reinterpret_cast<uint8_t*>(&v)[i];
|
||||
reinterpret_cast<uint8_t*>(&v)[i] = reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1];
|
||||
reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1] = tmp;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteSwapImpl<T, 1>
|
||||
{
|
||||
constexpr static inline T swap(T v) { return v; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteSwapImpl<T, 2>
|
||||
{
|
||||
constexpr static inline T swap(T v)
|
||||
{
|
||||
uint16_t& tmp = *reinterpret_cast<uint16_t*>(&v);
|
||||
tmp = ((tmp & 0x00ffu) << 8)
|
||||
| ((tmp & 0xff00u) >> 8);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteSwapImpl<T, 4>
|
||||
{
|
||||
constexpr static inline T swap(T v)
|
||||
{
|
||||
uint32_t& tmp = *reinterpret_cast<uint32_t*>(&v);
|
||||
tmp = ((tmp & 0x000000fful) << 24)
|
||||
| ((tmp & 0x0000ff00ul) << 8)
|
||||
| ((tmp & 0x00ff0000ul) >> 8)
|
||||
| ((tmp & 0xff000000ul) >> 24);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteSwapImpl<T, 8>
|
||||
{
|
||||
constexpr static inline T swap(T v)
|
||||
{
|
||||
uint64_t& tmp = *reinterpret_cast<uint64_t*>(&v);
|
||||
tmp = ((tmp & 0x00000000000000ffull) << 56)
|
||||
| ((tmp & 0x000000000000ff00ull) << 40)
|
||||
| ((tmp & 0x0000000000ff0000ull) << 24)
|
||||
| ((tmp & 0x00000000ff000000ull) << 8)
|
||||
| ((tmp & 0x000000ff00000000ull) >> 8)
|
||||
| ((tmp & 0x0000ff0000000000ull) >> 24)
|
||||
| ((tmp & 0x00ff000000000000ull) >> 40)
|
||||
| ((tmp & 0xff00000000000000ull) >> 56);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static inline bool little()
|
||||
{
|
||||
const uint32_t endian_magic = 0x01020304;
|
||||
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x04;
|
||||
}
|
||||
|
||||
static inline bool big()
|
||||
{
|
||||
const uint32_t endian_magic = 0x01020304;
|
||||
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x01;
|
||||
}
|
||||
|
||||
template<typename T, size_t Size = sizeof(T)>
|
||||
constexpr static inline T net_swap(T v)
|
||||
{
|
||||
if(Endian::little())
|
||||
{
|
||||
return ByteSwapImpl<T, Size>::swap(v);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T, size_t Size = sizeof(T)>
|
||||
constexpr static inline T swap(T v)
|
||||
{
|
||||
return ByteSwapImpl<T, Size>::swap(v);
|
||||
}
|
||||
|
||||
private:
|
||||
Endian() = delete;
|
||||
};
|
||||
}
|
||||
562
overlay_experimental/System/Filesystem.cpp
Normal file
562
overlay_experimental/System/Filesystem.cpp
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Filesystem.h"
|
||||
#include "Encoding.hpp"
|
||||
#include "System_internals.h"
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
#ifdef CreateDirectory
|
||||
#undef CreateDirectory
|
||||
#endif
|
||||
#ifdef DeleteFile
|
||||
#undef DeleteFile
|
||||
#endif
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h> // get iface broadcast
|
||||
#include <sys/stat.h> // stats on a file (is directory, size, mtime)
|
||||
|
||||
#include <dirent.h> // to open directories
|
||||
#include <dlfcn.h> // dlopen (like dll for linux)
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h> // PATH_MAX
|
||||
#include <unistd.h>
|
||||
|
||||
#else
|
||||
#error "unknown arch"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
namespace System {
|
||||
namespace Filesystem {
|
||||
|
||||
static void _CleanSlashes(std::string& str);
|
||||
|
||||
std::string Filename(std::string const& path)
|
||||
{
|
||||
size_t pos = path.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
return path.substr(pos+1);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string Dirname(std::string const& path)
|
||||
{
|
||||
std::string r(path);
|
||||
_CleanSlashes(r);
|
||||
size_t pos = r.find_last_of("/\\");
|
||||
|
||||
if (pos == std::string::npos || (pos == 0 && r.length() == 1))
|
||||
return std::string();
|
||||
|
||||
if (pos == 0)
|
||||
++pos;
|
||||
|
||||
return r.substr(0, pos);
|
||||
}
|
||||
|
||||
std::string Join(StringView r, StringView l)
|
||||
{
|
||||
std::string result(r.to_string());
|
||||
|
||||
result += Separator;
|
||||
result += l.to_string();
|
||||
|
||||
_CleanSlashes(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string CanonicalPath(std::string const& path)
|
||||
{
|
||||
if (IsAbsolute(path))
|
||||
return CleanPath(path);
|
||||
|
||||
return CleanPath(Join(GetCwd(),path));
|
||||
}
|
||||
|
||||
size_t FileSize(std::string const& path)
|
||||
{
|
||||
std::ifstream in_file(path, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if (in_file)
|
||||
{
|
||||
return in_file.tellg();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point FileATime(std::string const& path)
|
||||
{
|
||||
struct stat file_stat = {};
|
||||
if (stat(path.c_str(), &file_stat) != 0)
|
||||
return std::chrono::system_clock::time_point{};
|
||||
|
||||
return std::chrono::system_clock::from_time_t(file_stat.st_atime);
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point FileMTime(std::string const& path)
|
||||
{
|
||||
struct stat file_stat = {};
|
||||
if (stat(path.c_str(), &file_stat) != 0)
|
||||
return std::chrono::system_clock::time_point{};
|
||||
|
||||
return std::chrono::system_clock::from_time_t(file_stat.st_mtime);
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point FileCTime(std::string const& path)
|
||||
{
|
||||
struct stat file_stat = {};
|
||||
if (stat(path.c_str(), &file_stat) != 0)
|
||||
return std::chrono::system_clock::time_point{};
|
||||
|
||||
return std::chrono::system_clock::from_time_t(file_stat.st_ctime);
|
||||
}
|
||||
|
||||
#ifdef SYSTEM_OS_WINDOWS
|
||||
|
||||
static void _CleanSlashes(std::string& str)
|
||||
{
|
||||
size_t pos;
|
||||
std::replace(str.begin(), str.end(), '/', '\\');
|
||||
|
||||
while ((pos = str.find("\\\\")) != std::string::npos)
|
||||
str.replace(pos, 2, "\\");
|
||||
|
||||
pos = 0;
|
||||
while ((pos = str.find("\\.", pos)) != std::string::npos)
|
||||
{
|
||||
if (str[pos + 2] == '\\' || (pos + 2) >= str.length())
|
||||
{
|
||||
str.replace(pos, 3, "\\");
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetCwd()
|
||||
{
|
||||
DWORD size = GetCurrentDirectoryW(0, nullptr);
|
||||
if (size == 0)
|
||||
return ".";
|
||||
|
||||
std::wstring wdirectory;
|
||||
++size;
|
||||
wdirectory.resize(size);
|
||||
wdirectory.resize(GetCurrentDirectoryW(size, &wdirectory[0]));
|
||||
wdirectory += L'\\';
|
||||
|
||||
return System::Encoding::WCharToUtf8(wdirectory);
|
||||
}
|
||||
|
||||
bool IsAbsolute(std::string const& path)
|
||||
{
|
||||
return path.length() >= 2 && (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':');
|
||||
}
|
||||
|
||||
std::string CleanPath(std::string const& path)
|
||||
{
|
||||
std::string cleaned_path(path);
|
||||
size_t pos;
|
||||
size_t size;
|
||||
|
||||
_CleanSlashes(cleaned_path);
|
||||
|
||||
pos = 0;
|
||||
while ((pos = cleaned_path.find("\\..", pos)) != std::string::npos )
|
||||
{
|
||||
if (cleaned_path[pos + 3] == '\\' || (pos+3) >= cleaned_path.length())
|
||||
{
|
||||
if (pos == 0)
|
||||
size = 3;
|
||||
else
|
||||
{
|
||||
size_t parent_pos = cleaned_path.rfind("\\", pos - 1);
|
||||
if (parent_pos == std::string::npos)
|
||||
{
|
||||
size = pos + 3;
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 3 + pos - parent_pos;
|
||||
pos = parent_pos;
|
||||
}
|
||||
}
|
||||
|
||||
cleaned_path.replace(pos, size, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned_path;
|
||||
}
|
||||
|
||||
bool IsDir(std::string const& path)
|
||||
{
|
||||
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||
|
||||
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||
return attrs != INVALID_FILE_ATTRIBUTES && attrs & FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
bool IsFile(std::string const& path)
|
||||
{
|
||||
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||
|
||||
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||
return attrs != INVALID_FILE_ATTRIBUTES && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
bool Exists(std::string const& path)
|
||||
{
|
||||
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||
|
||||
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||
return attrs != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool CreateDirectory(std::string const& directory, bool recursive)
|
||||
{
|
||||
size_t pos = 0;
|
||||
struct _stat sb;
|
||||
|
||||
std::wstring sub_dir;
|
||||
std::wstring wdirectory(System::Encoding::Utf8ToWChar(directory));
|
||||
|
||||
if (wdirectory.empty())
|
||||
return false;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
pos = 3;
|
||||
|
||||
do
|
||||
{
|
||||
pos = wdirectory.find_first_of(L"\\/", pos + 1);
|
||||
sub_dir = std::move(wdirectory.substr(0, pos));
|
||||
if (_wstat(sub_dir.c_str(), &sb) == 0)
|
||||
{
|
||||
if (!(sb.st_mode & _S_IFDIR))
|
||||
{// A subpath in the target is not a directory
|
||||
return false;
|
||||
}
|
||||
// Folder Exists
|
||||
}
|
||||
else if (CreateDirectoryW(wdirectory.substr(0, pos).c_str(), NULL) == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
{// Failed to create directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (pos != std::string::npos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return (CreateDirectoryW(wdirectory.c_str(), NULL) != FALSE || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
bool DeleteFile(std::string const& path)
|
||||
{
|
||||
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||
return DeleteFileW(wpath.c_str()) == TRUE || GetLastError() == ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
static std::vector<std::wstring> ListFiles(std::wstring const& path, bool files_only, bool recursive)
|
||||
{
|
||||
std::vector<std::wstring> files;
|
||||
WIN32_FIND_DATAW hfind_data;
|
||||
HANDLE hfind = INVALID_HANDLE_VALUE;
|
||||
|
||||
std::wstring search_path = path;
|
||||
|
||||
if (*path.rbegin() != L'\\')
|
||||
search_path += L'\\';
|
||||
|
||||
search_path += L'*';
|
||||
|
||||
// Start iterating over the files in the path directory.
|
||||
hfind = FindFirstFileW(search_path.c_str(), &hfind_data);
|
||||
if (hfind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
search_path.pop_back();
|
||||
do // Managed to locate and create an handle to that folder.
|
||||
{
|
||||
if (wcscmp(L".", hfind_data.cFileName) == 0
|
||||
|| wcscmp(L"..", hfind_data.cFileName) == 0)
|
||||
continue;
|
||||
|
||||
if (hfind_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (recursive)
|
||||
{
|
||||
std::wstring dir_name = hfind_data.cFileName;
|
||||
|
||||
std::vector<std::wstring> sub_files = std::move(ListFiles(search_path + dir_name, files_only, true));
|
||||
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::wstring& Filename)
|
||||
{
|
||||
return dir_name + L'\\' + Filename;
|
||||
});
|
||||
}
|
||||
if (!files_only)
|
||||
{
|
||||
files.emplace_back(hfind_data.cFileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
files.emplace_back(hfind_data.cFileName);
|
||||
}
|
||||
} while (FindNextFileW(hfind, &hfind_data) == TRUE);
|
||||
FindClose(hfind);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||
|
||||
std::vector<std::wstring> wfiles(std::move(ListFiles(wpath, files_only, recursive)));
|
||||
|
||||
files.reserve(wfiles.size());
|
||||
std::transform(wfiles.begin(), wfiles.end(), std::back_inserter(files), [](std::wstring const& wFilename)
|
||||
{
|
||||
return System::Encoding::WCharToUtf8(wFilename);
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void _CleanSlashes(std::string& str)
|
||||
{
|
||||
size_t pos;
|
||||
std::replace(str.begin(), str.end(), '\\', '/');
|
||||
|
||||
while ((pos = str.find("//")) != std::string::npos)
|
||||
str.replace(pos, 2, "/");
|
||||
|
||||
pos = 0;
|
||||
while ((pos = str.find("/.", pos)) != std::string::npos)
|
||||
{
|
||||
if (str[pos + 2] == '/' || (pos + 2) >= str.length())
|
||||
{
|
||||
str.replace(pos, 3, "/");
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetCwd()
|
||||
{
|
||||
char buff[4096];
|
||||
std::string tmp(getcwd(buff, 4096) == nullptr ? "." : buff);
|
||||
|
||||
tmp += '/';
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool IsAbsolute(std::string const& path)
|
||||
{
|
||||
return path[0] == '/';
|
||||
}
|
||||
|
||||
std::string CleanPath(std::string const& path)
|
||||
{
|
||||
std::string cleaned_path(path);
|
||||
size_t pos;
|
||||
size_t size;
|
||||
|
||||
std::replace(cleaned_path.begin(), cleaned_path.end(), '\\', '/');
|
||||
|
||||
_CleanSlashes(cleaned_path);
|
||||
|
||||
pos = 0;
|
||||
while ((pos = cleaned_path.find("/..", pos)) != std::string::npos)
|
||||
{
|
||||
if (cleaned_path[pos + 3] == '/' || (pos + 3) >= cleaned_path.length())
|
||||
{
|
||||
if (pos == 0)
|
||||
size = 3;
|
||||
else
|
||||
{
|
||||
size_t parent_pos = cleaned_path.rfind("/", pos - 1);
|
||||
if (parent_pos == std::string::npos)
|
||||
{
|
||||
size = pos + 3;
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 3 + pos - parent_pos;
|
||||
pos = parent_pos;
|
||||
}
|
||||
}
|
||||
|
||||
cleaned_path.replace(pos, size, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned_path;
|
||||
}
|
||||
|
||||
bool IsDir(std::string const& path)
|
||||
{
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb) == 0)
|
||||
{
|
||||
return S_ISDIR(sb.st_mode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsFile(std::string const& path)
|
||||
{
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb) == 0)
|
||||
{
|
||||
return S_ISREG(sb.st_mode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Exists(std::string const& path)
|
||||
{
|
||||
struct stat sb;
|
||||
return stat(path.c_str(), &sb) == 0;
|
||||
}
|
||||
|
||||
bool CreateDirectory(std::string const& directory, bool recursive)
|
||||
{
|
||||
size_t pos = 0;
|
||||
struct stat sb;
|
||||
|
||||
std::string sub_dir;
|
||||
|
||||
do
|
||||
{
|
||||
pos = directory.find("/", pos + 1);
|
||||
sub_dir = std::move(directory.substr(0, pos));
|
||||
if (stat(sub_dir.c_str(), &sb) == 0)
|
||||
{
|
||||
if (!S_ISDIR(sb.st_mode))
|
||||
{// A subpath in the target is not a directory
|
||||
return false;
|
||||
}
|
||||
// Folder Exists
|
||||
}
|
||||
else if (mkdir(sub_dir.c_str(), 0755) < 0 && errno != EEXIST)
|
||||
{// Failed to create directory (no permission?)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (pos != std::string::npos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeleteFile(std::string const& path)
|
||||
{
|
||||
return unlink(path.c_str()) == 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
std::string search_path = path;
|
||||
|
||||
if (*path.rbegin() != Separator)
|
||||
search_path += Separator;
|
||||
|
||||
DIR* dir = opendir(search_path.c_str());
|
||||
struct dirent* entry;
|
||||
|
||||
if (dir == nullptr)
|
||||
return files;
|
||||
|
||||
while ((entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (strcmp(entry->d_name, ".") == 0
|
||||
|| strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (entry->d_type == DT_DIR)
|
||||
{
|
||||
if (recursive)
|
||||
{
|
||||
std::string dir_name = entry->d_name;
|
||||
std::vector<std::string> sub_files = std::move(ListFiles(search_path + dir_name, true));
|
||||
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::string& Filename)
|
||||
{
|
||||
return dir_name + Separator + Filename;
|
||||
});
|
||||
}
|
||||
if (!files_only)
|
||||
{
|
||||
files.emplace_back(entry->d_name);
|
||||
}
|
||||
}
|
||||
else if (entry->d_type == DT_REG)
|
||||
{
|
||||
files.emplace_back(entry->d_name);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
77
overlay_experimental/System/Filesystem.h
Normal file
77
overlay_experimental/System/Filesystem.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
#include "StringView.hpp"
|
||||
|
||||
#ifdef CreateDirectory
|
||||
#undef CreateDirectory
|
||||
#endif
|
||||
#ifdef DeleteFile
|
||||
#undef DeleteFile
|
||||
#endif
|
||||
|
||||
namespace System {
|
||||
namespace Filesystem {
|
||||
|
||||
constexpr static char WindowsSeparator = '\\';
|
||||
constexpr static char UnixSeparator = '/';
|
||||
|
||||
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
|
||||
constexpr static char Separator = WindowsSeparator;
|
||||
#else
|
||||
constexpr static char Separator = UnixSeparator;
|
||||
#endif
|
||||
|
||||
std::string CleanPath(std::string const& path);
|
||||
std::string Filename(std::string const& path);
|
||||
std::string Dirname(std::string const& path);
|
||||
bool IsAbsolute(std::string const& path);
|
||||
|
||||
inline std::string Join(StringView s) { return s.to_string(); }
|
||||
std::string Join(StringView r, StringView l);
|
||||
|
||||
template<typename ...Args>
|
||||
std::string Join(StringView path, Args&& ...args)
|
||||
{
|
||||
return Join(path, StringView(Join(args...)));
|
||||
}
|
||||
|
||||
std::string GetCwd();
|
||||
std::string CanonicalPath(std::string const& path);
|
||||
|
||||
bool IsDir(std::string const& path);
|
||||
bool IsFile(std::string const& path);
|
||||
bool Exists(std::string const& path);
|
||||
size_t FileSize(std::string const& path);
|
||||
std::chrono::system_clock::time_point FileATime(std::string const& path);
|
||||
std::chrono::system_clock::time_point FileMTime(std::string const& path);
|
||||
std::chrono::system_clock::time_point FileCTime(std::string const& path);
|
||||
|
||||
bool CreateDirectory(std::string const& folder, bool recursive = true);
|
||||
bool DeleteFile(std::string const& path);
|
||||
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive = false);
|
||||
|
||||
}
|
||||
}
|
||||
418
overlay_experimental/System/Library.cpp
Normal file
418
overlay_experimental/System/Library.cpp
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Library.h"
|
||||
#include "Encoding.hpp"
|
||||
#include "System_internals.h"
|
||||
#include <memory>
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
constexpr char library_suffix[] = ".dll";
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
#include <dlfcn.h>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(SYSTEM_OS_LINUX)
|
||||
#include <dirent.h> // to open directories
|
||||
#include <unistd.h>
|
||||
|
||||
constexpr char library_suffix[] = ".so";
|
||||
#else
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
constexpr char library_suffix[] = ".dylib";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace System {
|
||||
|
||||
namespace Library {
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
|
||||
void* OpenLibrary(const char* library_name)
|
||||
{
|
||||
if (library_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
|
||||
return LoadLibraryW(wide.c_str());
|
||||
}
|
||||
|
||||
void CloseLibrary(void* handle)
|
||||
{
|
||||
if(handle != nullptr)
|
||||
FreeLibrary((HMODULE)handle);
|
||||
}
|
||||
|
||||
void* GetSymbol(void* handle, const char* symbol_name)
|
||||
{
|
||||
if (symbol_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return GetProcAddress((HMODULE)handle, symbol_name);
|
||||
}
|
||||
|
||||
void* GetLibraryHandle(const char* library_name)
|
||||
{
|
||||
if (library_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
|
||||
return GetModuleHandleW(wide.c_str());
|
||||
}
|
||||
|
||||
std::string GetLibraryPath(void* handle)
|
||||
{
|
||||
if (handle == nullptr)
|
||||
return std::string();
|
||||
|
||||
std::wstring wpath(1024, L'\0');
|
||||
|
||||
DWORD size;
|
||||
while ((size = GetModuleFileNameW((HMODULE)handle, &wpath[0], wpath.length())) == wpath.length())
|
||||
{
|
||||
wpath.resize(wpath.length() * 2);
|
||||
}
|
||||
|
||||
wpath.resize(size);
|
||||
return System::Encoding::WCharToUtf8(wpath);
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
|
||||
void* OpenLibrary(const char* library_name)
|
||||
{
|
||||
if (library_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return dlopen(library_name, RTLD_NOW);
|
||||
}
|
||||
|
||||
void CloseLibrary(void* handle)
|
||||
{
|
||||
if(handle != nullptr)
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void* GetSymbol(void* handle, const char* symbol_name)
|
||||
{
|
||||
if (handle == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return dlsym(handle, symbol_name);
|
||||
}
|
||||
|
||||
#if defined(SYSTEM_OS_LINUX)
|
||||
std::string GetLibraryPath(void* handle)
|
||||
{
|
||||
if (handle == nullptr)
|
||||
return std::string();
|
||||
|
||||
std::string const self("/proc/self/map_files/");
|
||||
DIR* dir;
|
||||
struct dirent* dir_entry;
|
||||
std::string file_path;
|
||||
std::string res;
|
||||
|
||||
dir = opendir(self.c_str());
|
||||
if (dir != nullptr)
|
||||
{
|
||||
while ((dir_entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
file_path = (self + dir_entry->d_name);
|
||||
if (dir_entry->d_type != DT_LNK)
|
||||
{// Not a link
|
||||
continue;
|
||||
}
|
||||
|
||||
file_path = System::ExpandSymlink(file_path);
|
||||
|
||||
void* lib_handle = dlopen(file_path.c_str(), RTLD_NOW);
|
||||
if (lib_handle != nullptr)
|
||||
{// Don't increment ref_counter.
|
||||
dlclose(lib_handle);
|
||||
if (handle == lib_handle)
|
||||
{
|
||||
res = std::move(file_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void* GetLibraryHandle(const char* library_name)
|
||||
{
|
||||
if (library_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
std::string const self("/proc/self/map_files/");
|
||||
DIR* dir;
|
||||
struct dirent* dir_entry;
|
||||
void* res = nullptr;
|
||||
size_t library_name_len = strlen(library_name);
|
||||
|
||||
dir = opendir(self.c_str());
|
||||
if (dir != nullptr)
|
||||
{
|
||||
std::string file_path;
|
||||
while ((dir_entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
file_path = (self + dir_entry->d_name);
|
||||
if (dir_entry->d_type != DT_LNK)
|
||||
{// Not a link
|
||||
continue;
|
||||
}
|
||||
|
||||
file_path = System::ExpandSymlink(file_path);
|
||||
|
||||
auto pos = file_path.rfind('/');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
++pos;
|
||||
if (strncmp(file_path.c_str() + pos, library_name, library_name_len) == 0)
|
||||
{
|
||||
res = dlopen(file_path.c_str(), RTLD_NOW);
|
||||
if (res != nullptr)
|
||||
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
|
||||
dlclose(res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
|
||||
std::string GetLibraryPath(void* handle)
|
||||
{
|
||||
if (handle == nullptr)
|
||||
return std::string();
|
||||
|
||||
task_dyld_info dyld_info;
|
||||
task_t t;
|
||||
pid_t pid = getpid();
|
||||
task_for_pid(mach_task_self(), pid, &t);
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||
{
|
||||
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||
if (res != nullptr)
|
||||
{
|
||||
dlclose(res);
|
||||
if(res == handle)
|
||||
return std::string(dyld_img_infos->infoArray[i].imageFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void* GetLibraryHandle(const char* library_name)
|
||||
{
|
||||
if (library_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
void* res = nullptr;
|
||||
|
||||
size_t library_name_len = strlen(library_name);
|
||||
|
||||
task_dyld_info dyld_info;
|
||||
task_t t;
|
||||
pid_t pid = getpid();
|
||||
task_for_pid(mach_task_self(), pid, &t);
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||
{
|
||||
const char* pos;
|
||||
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
pos = strrchr(dyld_img_infos->infoArray[i].imageFilePath, '/');
|
||||
if (pos != nullptr)
|
||||
{
|
||||
++pos;
|
||||
if (strncmp(pos, library_name, library_name_len) == 0)
|
||||
{
|
||||
res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||
if (res != nullptr)
|
||||
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
|
||||
dlclose(res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
std::string GetLibraryExtension()
|
||||
{
|
||||
return std::string{ library_suffix };
|
||||
}
|
||||
|
||||
class LibraryImpl
|
||||
{
|
||||
std::shared_ptr<void> _Handle;
|
||||
|
||||
struct LibraryHandleDestructor
|
||||
{
|
||||
void operator()(void* h)
|
||||
{
|
||||
System::Library::CloseLibrary(h);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
inline bool OpenLibrary(std::string const& library_name, bool append_extension)
|
||||
{
|
||||
std::string lib_name = (append_extension ? library_name + library_suffix : library_name);
|
||||
|
||||
void* lib = System::Library::OpenLibrary(lib_name.c_str());
|
||||
|
||||
if (lib == nullptr)
|
||||
{
|
||||
lib_name = "lib" + lib_name;
|
||||
lib = System::Library::OpenLibrary(lib_name.c_str());
|
||||
|
||||
if (lib == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
_Handle = std::shared_ptr<void>(lib, LibraryHandleDestructor());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void CloseLibrary()
|
||||
{
|
||||
_Handle.reset();
|
||||
}
|
||||
|
||||
inline void* GetVSymbol(std::string const& symbol_name) const
|
||||
{
|
||||
return System::Library::GetSymbol(_Handle.get(), symbol_name.c_str());
|
||||
}
|
||||
|
||||
inline std::string GetLibraryPath() const
|
||||
{
|
||||
return System::Library::GetLibraryPath(_Handle.get());
|
||||
}
|
||||
|
||||
inline void* GetLibraryNativeHandle() const
|
||||
{
|
||||
return _Handle.get();
|
||||
}
|
||||
|
||||
inline bool IsLoaded() const
|
||||
{
|
||||
return _Handle != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
Library::Library():
|
||||
_Impl(new LibraryImpl)
|
||||
{}
|
||||
|
||||
Library::Library(Library const& other):
|
||||
_Impl(new LibraryImpl(*other._Impl))
|
||||
{}
|
||||
|
||||
Library::Library(Library&& other) noexcept:
|
||||
_Impl(other._Impl)
|
||||
{
|
||||
other._Impl = nullptr;
|
||||
}
|
||||
|
||||
Library& Library::operator=(Library const& other)
|
||||
{
|
||||
*_Impl = *other._Impl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Library& Library::operator=(Library&& other) noexcept
|
||||
{
|
||||
std::swap(_Impl, other._Impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Library::~Library()
|
||||
{
|
||||
delete _Impl; _Impl = nullptr;
|
||||
}
|
||||
|
||||
bool Library::OpenLibrary(std::string const& library_name, bool append_extension)
|
||||
{
|
||||
return _Impl->OpenLibrary(library_name, append_extension);
|
||||
}
|
||||
|
||||
void Library::CloseLibrary()
|
||||
{
|
||||
_Impl->CloseLibrary();
|
||||
}
|
||||
|
||||
void* Library::GetVSymbol(std::string const& symbol_name) const
|
||||
{
|
||||
return _Impl->GetVSymbol(symbol_name);
|
||||
}
|
||||
|
||||
std::string Library::GetLibraryPath() const
|
||||
{
|
||||
return _Impl->GetLibraryPath();
|
||||
}
|
||||
|
||||
void* Library::GetLibraryNativeHandle() const
|
||||
{
|
||||
return _Impl->GetLibraryNativeHandle();
|
||||
}
|
||||
|
||||
bool Library::IsLoaded() const
|
||||
{
|
||||
return _Impl->IsLoaded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
80
overlay_experimental/System/Library.h
Normal file
80
overlay_experimental/System/Library.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
|
||||
namespace Library {
|
||||
|
||||
class Library
|
||||
{
|
||||
class LibraryImpl* _Impl;
|
||||
|
||||
public:
|
||||
Library();
|
||||
|
||||
Library(Library const& other);
|
||||
|
||||
Library(Library&& other) noexcept;
|
||||
|
||||
Library& operator=(Library const& other);
|
||||
|
||||
Library& operator=(Library&& other) noexcept;
|
||||
|
||||
~Library();
|
||||
|
||||
bool OpenLibrary(std::string const& library_name, bool append_extension);
|
||||
|
||||
void CloseLibrary();
|
||||
|
||||
void* GetVSymbol(std::string const& symbol_name) const;
|
||||
|
||||
template<typename T>
|
||||
inline T* GetSymbol(std::string const& symbol_name) const
|
||||
{
|
||||
return reinterpret_cast<T*>(GetVSymbol(symbol_name));
|
||||
}
|
||||
|
||||
std::string GetLibraryPath() const;
|
||||
|
||||
void* GetLibraryNativeHandle() const;
|
||||
|
||||
bool IsLoaded() const;
|
||||
};
|
||||
|
||||
// Triies to load the library, I suggest that you use a Library instance instead
|
||||
void* OpenLibrary(const char* library_name);
|
||||
// Will decrease the OS' ref counter on the library, use it to close a handle opened by open_library.
|
||||
// A Library instance will automatically call this in the destructor
|
||||
void CloseLibrary(void* handle);
|
||||
// Will try to retrieve a symbol address from the library handle
|
||||
void* GetSymbol(void* handle, const char* symbol_name);
|
||||
// Get a pointer to the library, if it is not loaded, will return nullptr. This doesn't increment the OS' internal ref counter
|
||||
void* GetLibraryHandle(const char* library_name);
|
||||
// Get the library path of a module handle
|
||||
std::string GetLibraryPath(void* handle);
|
||||
// Get the native extension representing a shared library.
|
||||
std::string GetLibraryExtension();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
96
overlay_experimental/System/ScopedLock.hpp
Normal file
96
overlay_experimental/System/ScopedLock.hpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <mutex>
|
||||
|
||||
namespace System {
|
||||
|
||||
class scoped_lock {
|
||||
struct value_holder
|
||||
{
|
||||
virtual ~value_holder() noexcept {}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
struct templated_value_holder : value_holder
|
||||
{
|
||||
template<std::size_t I = 0, typename... Tp>
|
||||
inline typename std::enable_if<I == sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t) { }
|
||||
|
||||
template<std::size_t I = 0, typename... Tp>
|
||||
inline typename std::enable_if<I < sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t)
|
||||
{
|
||||
std::get<I>(t).unlock();
|
||||
unlock<I + 1, Tp...>(t);
|
||||
}
|
||||
|
||||
explicit templated_value_holder(Args&... mutexes) : _mutexes(mutexes...) { std::lock(mutexes...); }
|
||||
explicit templated_value_holder(std::adopt_lock_t, Args&... mutexes) : _mutexes(mutexes...) {} // construct but don't lock
|
||||
|
||||
virtual ~templated_value_holder() noexcept { unlock(_mutexes); }
|
||||
|
||||
std::tuple<Args&...> _mutexes;
|
||||
};
|
||||
|
||||
template<typename Arg>
|
||||
struct templated_value_holder<Arg> : value_holder
|
||||
{
|
||||
explicit templated_value_holder(Arg& mutex) : _mutex(mutex) { _mutex.lock(); }
|
||||
explicit templated_value_holder(std::adopt_lock_t, Arg& mutex) : _mutex(mutex) {} // construct but don't lock
|
||||
|
||||
virtual ~templated_value_holder() noexcept { _mutex.unlock(); }
|
||||
|
||||
Arg& _mutex;
|
||||
};
|
||||
|
||||
value_holder* _val;
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
explicit scoped_lock(Args&... mutexes) : _val(new templated_value_holder<Args&...>(mutexes...)) { }
|
||||
|
||||
template<typename... Args>
|
||||
explicit scoped_lock(std::adopt_lock_t, Args&... mutexes) : _val(new templated_value_holder<Args&...>(std::adopt_lock, mutexes...)) { }
|
||||
|
||||
explicit scoped_lock(scoped_lock && other):
|
||||
_val(other._val)
|
||||
{
|
||||
other._val = nullptr;
|
||||
}
|
||||
|
||||
scoped_lock() noexcept:
|
||||
_val(nullptr)
|
||||
{}
|
||||
~scoped_lock() noexcept { delete _val; }
|
||||
|
||||
scoped_lock& operator=(scoped_lock && other)
|
||||
{
|
||||
_val = other._val;
|
||||
other._val = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_lock(const scoped_lock&) = delete;
|
||||
scoped_lock& operator=(const scoped_lock&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
89
overlay_experimental/System/String.cpp
Normal file
89
overlay_experimental/System/String.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "System_internals.h"
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace System {
|
||||
namespace String {
|
||||
namespace details {
|
||||
|
||||
void LeftTrim(std::string& str)
|
||||
{
|
||||
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const char c)
|
||||
{
|
||||
return !std::isspace((unsigned char)c);
|
||||
}));
|
||||
}
|
||||
|
||||
void RightTrim(std::string& str)
|
||||
{
|
||||
str.erase(std::find_if(str.rbegin(), str.rend(), [](const char c)
|
||||
{
|
||||
return !std::isspace((unsigned char)c);
|
||||
}).base(), str.end());
|
||||
}
|
||||
|
||||
void ToUpper(char* str, size_t len)
|
||||
{
|
||||
while(len--)
|
||||
{
|
||||
unsigned char c = (unsigned char)*str;
|
||||
*str++ = std::toupper(c);
|
||||
}
|
||||
}
|
||||
|
||||
void ToLower(char* str, size_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
unsigned char c = (unsigned char)*str;
|
||||
*str++ = std::tolower(c);
|
||||
}
|
||||
}
|
||||
|
||||
char* CloneString(System::StringView src)
|
||||
{
|
||||
size_t len = src.length() + 1;
|
||||
char* res = new char[len];
|
||||
memcpy(res, src.data(), len);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t CopyString(System::StringView src, char* dst, size_t dst_size)
|
||||
{
|
||||
size_t written = 0;
|
||||
if (dst != nullptr && dst_size > 0)
|
||||
{
|
||||
written = src.length() > dst_size ? dst_size - 1 : src.length();
|
||||
memcpy(dst, src.data(), written);
|
||||
dst[written] = '\0';
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
}// namespace details
|
||||
|
||||
}// namespace String
|
||||
}// namespace System
|
||||
290
overlay_experimental/System/String.hpp
Normal file
290
overlay_experimental/System/String.hpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with the System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
#include "StringView.hpp"
|
||||
#include "StringSwitch.hpp"
|
||||
|
||||
namespace System {
|
||||
namespace String {
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Implementations
|
||||
|
||||
namespace details {
|
||||
void LeftTrim(std::string& str);
|
||||
|
||||
void RightTrim(std::string& str);
|
||||
|
||||
void ToUpper(char* str, size_t len);
|
||||
|
||||
void ToLower(char* str, size_t len);
|
||||
|
||||
char* CloneString(System::StringView src);
|
||||
|
||||
size_t CopyString(System::StringView src, char *dst, size_t dst_size);
|
||||
}
|
||||
|
||||
|
||||
inline void LeftTrim(std::string& str)
|
||||
{
|
||||
details::LeftTrim(str);
|
||||
}
|
||||
|
||||
inline void RightTrim(std::string& str)
|
||||
{
|
||||
details::RightTrim(str);
|
||||
}
|
||||
|
||||
inline void Trim(std::string& str)
|
||||
{
|
||||
LeftTrim(str);
|
||||
RightTrim(str);
|
||||
}
|
||||
|
||||
inline std::string CopyLeftTrim(const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return std::string();
|
||||
|
||||
std::string r(str);
|
||||
LeftTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyLeftTrim(System::StringView str)
|
||||
{
|
||||
std::string r(str.to_string());
|
||||
LeftTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyLeftTrim(std::string const& str)
|
||||
{
|
||||
std::string r(str);
|
||||
LeftTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyRightTrim(const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return std::string();
|
||||
|
||||
std::string r(str);
|
||||
RightTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyRightTrim(System::StringView str)
|
||||
{
|
||||
std::string r(str.to_string());
|
||||
RightTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyRightTrim(std::string const& str)
|
||||
{
|
||||
std::string r(str);
|
||||
RightTrim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyTrim(const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return std::string();
|
||||
|
||||
std::string r(str);
|
||||
Trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyTrim(System::StringView str)
|
||||
{
|
||||
std::string r(str.to_string());
|
||||
Trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyTrim(std::string const& str)
|
||||
{
|
||||
std::string r(str);
|
||||
Trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void ToLower(std::string& str)
|
||||
{
|
||||
details::ToLower(&str[0], str.length());
|
||||
}
|
||||
|
||||
inline void ToLower(char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return;
|
||||
|
||||
details::ToLower(str, strlen(str));
|
||||
}
|
||||
|
||||
inline std::string CopyLower(std::string const& str)
|
||||
{
|
||||
std::string r(str);
|
||||
details::ToLower(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyLower(const char* str)
|
||||
{
|
||||
std::string r(str == nullptr ? "" : str);
|
||||
details::ToLower(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyLower(System::StringView str)
|
||||
{
|
||||
std::string r = str.to_string();
|
||||
details::ToLower(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void ToUpper(std::string& str)
|
||||
{
|
||||
details::ToUpper(&str[0], str.length());
|
||||
}
|
||||
|
||||
inline void ToUpper(char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return;
|
||||
|
||||
details::ToUpper(str, strlen(str));
|
||||
}
|
||||
|
||||
inline std::string CopyUpper(std::string const& str)
|
||||
{
|
||||
std::string r(str);
|
||||
details::ToUpper(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyUpper(const char* str)
|
||||
{
|
||||
std::string r(str == nullptr ? "" : str);
|
||||
details::ToUpper(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline std::string CopyUpper(System::StringView str)
|
||||
{
|
||||
std::string r = str.to_string();
|
||||
details::ToUpper(&r[0], r.length());
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename IteratorType>
|
||||
inline std::string Join(IteratorType begin, IteratorType end, const std::string& sep)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
if (begin != end)
|
||||
res = *begin++;
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
res += sep;
|
||||
res += *begin++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::string Join(T const& container, const std::string& sep)
|
||||
{
|
||||
return Join(std::begin(container), std::end(container), sep);
|
||||
}
|
||||
|
||||
// Clone a string allocated with the "new" operator, if str is nullptr, an empty string ("") will be returned, NOT nullptr !
|
||||
inline char* CloneString(const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return details::CloneString(System::StringView(""));
|
||||
|
||||
return details::CloneString(System::StringView(str, strlen(str)));
|
||||
}
|
||||
|
||||
inline char* CloneString(std::string const& str)
|
||||
{
|
||||
return details::CloneString(System::StringView(str));
|
||||
}
|
||||
|
||||
inline char* CloneString(System::StringView str)
|
||||
{
|
||||
return details::CloneString(str);
|
||||
}
|
||||
|
||||
// Will always end the C-String with a null char.
|
||||
inline size_t CopyString(const char* src, char* dst, size_t dst_size)
|
||||
{
|
||||
if (src == nullptr)
|
||||
return details::CopyString(System::StringView(""), dst, dst_size);
|
||||
|
||||
return details::CopyString(System::StringView(src, strlen(src)), dst, dst_size);
|
||||
}
|
||||
|
||||
inline size_t CopyString(System::StringView src, char* dst, size_t dst_size)
|
||||
{
|
||||
return details::CopyString(src, dst, dst_size);
|
||||
}
|
||||
|
||||
inline size_t CopyString(std::string const& src, char* dst, size_t dst_size)
|
||||
{
|
||||
return details::CopyString(System::StringView(src), dst, dst_size);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline size_t CopyString(const char* src, char(&dst)[N])
|
||||
{
|
||||
if (src == nullptr)
|
||||
return details::CopyString(System::StringView(""), dst, N);
|
||||
|
||||
return details::CopyString(System::StringView(src, strlen(src)), dst, N);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline size_t CopyString(System::StringView src, char(&dst)[N])
|
||||
{
|
||||
return details::CopyString(src, dst, N);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline size_t CopyString(std::string const& src, char(&dst)[N])
|
||||
{
|
||||
return details::CopyString(System::StringView(src), dst, N);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
64
overlay_experimental/System/StringSwitch.hpp
Normal file
64
overlay_experimental/System/StringSwitch.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "SystemDetector.h"
|
||||
#include "StringView.hpp"
|
||||
|
||||
namespace System {
|
||||
|
||||
namespace StringSwitch {
|
||||
|
||||
#if defined(SYSTEM_ARCH_X86)
|
||||
using hash_type = uint32_t;
|
||||
#else
|
||||
using hash_type = uint64_t;
|
||||
#endif
|
||||
|
||||
namespace Detail {
|
||||
constexpr char lower_char(char c) { return ((c >= 'A' && c <= 'Z') ? c + 32 : c); }
|
||||
}
|
||||
|
||||
// switch case on a string
|
||||
constexpr hash_type Hash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(*input) + 33 * Hash(input + 1, len - 1) : 5381); }
|
||||
|
||||
template<size_t N>
|
||||
constexpr hash_type Hash(const char(&input)[N]) { return Hash(input, N-1); }
|
||||
|
||||
constexpr hash_type Hash(System::StringView sv) { return Hash(sv.data(), sv.length()); }
|
||||
|
||||
inline hash_type Hash(const std::string& input) { return Hash(input.c_str(), input.length()); }
|
||||
|
||||
|
||||
|
||||
constexpr hash_type IHash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(Detail::lower_char(*input)) + 33 * IHash(input + 1, len - 1) : 5381); }
|
||||
|
||||
template<size_t N>
|
||||
constexpr inline hash_type IHash(const char(&input)[N]) { return IHash(input, N - 1); }
|
||||
|
||||
constexpr hash_type IHash(System::StringView sv) { return IHash(sv.data(), sv.length()); }
|
||||
|
||||
inline hash_type IHash(const std::string& input) { return IHash(input.c_str(), input.length()); }
|
||||
|
||||
}
|
||||
}
|
||||
256
overlay_experimental/System/StringView.hpp
Normal file
256
overlay_experimental/System/StringView.hpp
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
namespace System {
|
||||
|
||||
template<typename char_type>
|
||||
class BasicStringView {
|
||||
const char_type* _string;
|
||||
size_t _length;
|
||||
|
||||
using type = BasicStringView<char_type>;
|
||||
|
||||
public:
|
||||
class iterator {
|
||||
const char_type* _value;
|
||||
|
||||
public:
|
||||
constexpr iterator(const iterator& o) : _value(o._value) {}
|
||||
constexpr iterator(const char_type* value) : _value(value) {}
|
||||
|
||||
constexpr iterator& operator++() { ++_value; return *this; }
|
||||
constexpr iterator operator++(int) { iterator retval = *this; ++(*this); return retval; }
|
||||
constexpr iterator& operator--() { --_value; return *this; }
|
||||
constexpr iterator operator--(int) { iterator retval = *this; --(*this); return retval; }
|
||||
constexpr bool operator==(iterator other) const { return _value == other._value; }
|
||||
constexpr bool operator!=(iterator other) const { return !(*this == other); }
|
||||
constexpr const char_type& operator*() const { return *_value; }
|
||||
|
||||
// iterator traits
|
||||
using difference_type = long;
|
||||
using value_type = char_type;
|
||||
using pointer = const char_type*;
|
||||
using reference = const char_type&;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
};
|
||||
|
||||
constexpr BasicStringView() : _string(nullptr), _length(0)
|
||||
{}
|
||||
|
||||
constexpr BasicStringView(const char_type* str, size_t length) : _string(str), _length(length)
|
||||
{}
|
||||
|
||||
constexpr BasicStringView(std::basic_string<char_type, std::char_traits<char_type>, std::allocator<char_type>> const& str) : _string(str.data()), _length(str.length())
|
||||
{}
|
||||
|
||||
template<size_t N>
|
||||
constexpr BasicStringView(const char_type(&str)[N]) : _string(str), _length(N - 1)
|
||||
{}
|
||||
|
||||
template<size_t N>
|
||||
constexpr BasicStringView(std::array<char_type, N> const& str) : _string(&str.at[0]), _length(N)
|
||||
{}
|
||||
|
||||
constexpr BasicStringView(type const& other) : _string(other._string), _length(other._length)
|
||||
{}
|
||||
|
||||
constexpr BasicStringView(type&& other) : _string(other._string), _length(other._length)
|
||||
{}
|
||||
|
||||
constexpr type& operator=(type const& other)
|
||||
{
|
||||
_string = other._string;
|
||||
_length = other._length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr type& operator=(type&& other)
|
||||
{
|
||||
_string = other._string;
|
||||
_length = other._length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr const char_type* data() const { return _string; }
|
||||
|
||||
constexpr bool empty() const { return _length == 0; }
|
||||
|
||||
constexpr size_t size() const { return _length; }
|
||||
|
||||
constexpr size_t length() const { return _length; }
|
||||
|
||||
constexpr const char_type& operator[](size_t index) const { return _string[index]; }
|
||||
|
||||
constexpr size_t find_first_of(type const& string, const size_t offset = 0) const
|
||||
{
|
||||
if(_length == 0)
|
||||
return std::string::npos;
|
||||
|
||||
for (size_t i = offset; i < _length; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < string._length; ++j)
|
||||
{
|
||||
if (_string[i] == string[j])
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
constexpr size_t find_first_not_of(type const& string, const size_t offset = 0) const
|
||||
{
|
||||
if(_length == 0)
|
||||
return std::string::npos;
|
||||
|
||||
for (size_t i = offset; i < _length; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < string._length; ++j)
|
||||
{
|
||||
if (_string[i] == string[j])
|
||||
break;
|
||||
|
||||
if (j == (string._length - 1))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
constexpr size_t find(type const& string, const size_t offset = 0) const
|
||||
{
|
||||
if (_length < string._length)
|
||||
return std::string::npos;
|
||||
|
||||
for (size_t i = offset; i < (_length - string._length + 1); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < string._length; ++j)
|
||||
{
|
||||
if (_string[i + j] != string[j])
|
||||
break;
|
||||
|
||||
if (j == (string._length - 1))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
constexpr size_t find_not(type const& string, const size_t offset = 0) const
|
||||
{
|
||||
if (_length < string._length)
|
||||
return std::string::npos;
|
||||
|
||||
for (size_t i = offset; i < (_length - string._length + 1); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < string._length; ++j)
|
||||
{
|
||||
if (_string[i + j] == string[j])
|
||||
break;
|
||||
|
||||
if (j == (string._length - 1))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
constexpr size_t count(char_type const c) const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < _length; ++i)
|
||||
if (_string[i] == c)
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr type substr(size_t offset, size_t length = std::string::npos) const
|
||||
{
|
||||
if (offset >= _length)
|
||||
return type();
|
||||
|
||||
return type(_string + offset, (_length - offset) > length ? length : _length - offset);
|
||||
}
|
||||
|
||||
constexpr iterator begin() const
|
||||
{
|
||||
return iterator(_string);
|
||||
}
|
||||
|
||||
constexpr iterator end() const
|
||||
{
|
||||
return iterator(_string + _length);
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
return std::string(_string, _string + _length);
|
||||
}
|
||||
|
||||
size_t copy(char_type* p, size_t p_size) const
|
||||
{
|
||||
size_t written = 0;
|
||||
if (p != nullptr)
|
||||
{
|
||||
size_t to_write = (_length > p_size ? p_size : _length);
|
||||
char_type* b = _string;
|
||||
while (to_write--)
|
||||
{
|
||||
*p++ = *b++;
|
||||
++written;
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
};
|
||||
|
||||
using StringView = BasicStringView<char>;
|
||||
|
||||
}
|
||||
|
||||
template<typename char_type>
|
||||
std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, System::BasicStringView<char_type> const& sv)
|
||||
{
|
||||
return os.write(sv.data(), sv.length());
|
||||
}
|
||||
|
||||
template<typename char_type>
|
||||
std::basic_string<char_type> operator+(std::basic_string<char_type> const& str, System::BasicStringView<char_type> const& sv)
|
||||
{
|
||||
std::string r(str);
|
||||
return r.append(sv.data(), sv.data() + sv.length());
|
||||
}
|
||||
|
||||
template<typename char_type>
|
||||
std::basic_string<char_type>& operator+=(std::basic_string<char_type>& str, System::BasicStringView<char_type> const& sv)
|
||||
{
|
||||
return str.append(sv.data(), sv.data() + sv.length());
|
||||
}
|
||||
593
overlay_experimental/System/System.cpp
Normal file
593
overlay_experimental/System/System.cpp
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "System.h"
|
||||
#include "Filesystem.h"
|
||||
#include "Encoding.hpp"
|
||||
#include "System_internals.h"
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h> // (shell32.lib) Infos about current user folders
|
||||
|
||||
inline bool handle_is_valid(HANDLE h)
|
||||
{
|
||||
return (h != (HANDLE)0 && h != (HANDLE)-1);
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
#if defined(SYSTEM_OS_LINUX)
|
||||
#include <sys/sysinfo.h> // Get uptime (second resolution)
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#else
|
||||
#error "unknown arch"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::chrono::microseconds GetUpTime()
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - GetBootTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace System {
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
|
||||
std::chrono::system_clock::time_point GetBootTime()
|
||||
{
|
||||
static std::chrono::system_clock::time_point boottime(std::chrono::system_clock::now() - std::chrono::milliseconds(GetTickCount64()));
|
||||
return boottime;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetProcArgs()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
LPWSTR* szArglist;
|
||||
int nArgs;
|
||||
|
||||
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||
|
||||
res.reserve(nArgs);
|
||||
for (int i = 0; i < nArgs; ++i)
|
||||
{
|
||||
res.emplace_back(System::Encoding::WCharToUtf8(szArglist[i]));
|
||||
}
|
||||
|
||||
LocalFree(szArglist);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string GetEnvVar(std::string const& var)
|
||||
{
|
||||
std::wstring wide(System::Encoding::Utf8ToWChar(var));
|
||||
std::wstring wVar;
|
||||
|
||||
DWORD size = GetEnvironmentVariableW(wide.c_str(), nullptr, 0);
|
||||
// Size can be 0, and the size includes the null char, so resize to size - 1
|
||||
if (size < 2)
|
||||
return std::string();
|
||||
|
||||
wVar.resize(size - 1);
|
||||
GetEnvironmentVariableW(wide.c_str(), &wVar[0], size);
|
||||
|
||||
return System::Encoding::WCharToUtf8(wVar);
|
||||
}
|
||||
|
||||
std::string GetUserdataPath()
|
||||
{
|
||||
WCHAR szPath[4096] = {};
|
||||
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath);
|
||||
|
||||
if (FAILED(hr))
|
||||
return std::string();
|
||||
|
||||
return System::Encoding::WCharToUtf8(std::wstring(szPath));
|
||||
}
|
||||
|
||||
std::string GetExecutablePath()
|
||||
{
|
||||
std::string path;
|
||||
std::wstring wpath(4096, L'\0');
|
||||
|
||||
wpath.resize(GetModuleFileNameW(nullptr, &wpath[0], wpath.length()));
|
||||
return System::Encoding::WCharToUtf8(wpath);
|
||||
}
|
||||
|
||||
std::string GetModulePath()
|
||||
{
|
||||
std::string path;
|
||||
std::wstring wpath(4096, L'\0');
|
||||
HMODULE hModule;
|
||||
|
||||
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&GetModulePath, &hModule) != FALSE)
|
||||
{
|
||||
DWORD size = GetModuleFileNameW((HINSTANCE)hModule, &wpath[0], wpath.length());
|
||||
wpath.resize(size);
|
||||
}
|
||||
return System::Encoding::WCharToUtf8(wpath);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetModules()
|
||||
{
|
||||
std::vector<std::string> paths;
|
||||
std::wstring wpath;
|
||||
DWORD size;
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(GetCurrentProcess()));
|
||||
if (handle_is_valid(hSnap))
|
||||
{
|
||||
MODULEENTRY32W entry{};
|
||||
entry.dwSize = sizeof(entry);
|
||||
if (Module32FirstW(hSnap, &entry) != FALSE)
|
||||
{
|
||||
wpath.resize(4096);
|
||||
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
|
||||
wpath.resize(size);
|
||||
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
|
||||
|
||||
while (Module32NextW(hSnap, &entry) != FALSE)
|
||||
{
|
||||
wpath.resize(4096);
|
||||
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
|
||||
wpath.resize(size);
|
||||
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hSnap);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
#ifdef SYSTEM_OS_LINUX
|
||||
|
||||
std::chrono::system_clock::time_point GetBootTime()
|
||||
{
|
||||
static std::chrono::system_clock::time_point boottime(std::chrono::seconds(0));
|
||||
if (boottime == std::chrono::system_clock::time_point{})
|
||||
{
|
||||
std::ifstream uptime_file("/proc/uptime");
|
||||
|
||||
double uptime;
|
||||
if (uptime_file)
|
||||
{// Get uptime (millisecond resolution)
|
||||
uptime_file >> uptime;
|
||||
uptime_file.close();
|
||||
}
|
||||
else
|
||||
{// If we can't open /proc/uptime, fallback to sysinfo (second resolution)
|
||||
struct sysinfo infos;
|
||||
if (sysinfo(&infos) != 0)
|
||||
return boottime;
|
||||
|
||||
uptime = infos.uptime;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point now_tp = std::chrono::system_clock::now();
|
||||
std::chrono::system_clock::time_point uptime_tp(std::chrono::milliseconds(static_cast<uint64_t>(uptime * 1000)));
|
||||
|
||||
boottime = std::chrono::system_clock::time_point(now_tp - uptime_tp);
|
||||
}
|
||||
|
||||
return boottime;
|
||||
}
|
||||
|
||||
std::string GetExecutablePath()
|
||||
{
|
||||
std::string exec_path("./");
|
||||
|
||||
char link[2048] = {};
|
||||
if (readlink("/proc/self/exe", link, sizeof(link)) > 0)
|
||||
{
|
||||
exec_path = link;
|
||||
}
|
||||
|
||||
return exec_path;
|
||||
}
|
||||
|
||||
std::string GetModulePath()
|
||||
{
|
||||
std::string const self("/proc/self/map_files/");
|
||||
DIR* dir;
|
||||
struct dirent* dir_entry;
|
||||
std::string file_path;
|
||||
std::string res;
|
||||
uint64_t handle = (uint64_t)&GetModulePath;
|
||||
uint64_t low, high;
|
||||
char* tmp;
|
||||
|
||||
dir = opendir(self.c_str());
|
||||
if (dir != nullptr)
|
||||
{
|
||||
while ((dir_entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
file_path = dir_entry->d_name;
|
||||
if (dir_entry->d_type != DT_LNK)
|
||||
{// Not a link
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = &file_path[0];
|
||||
low = strtoull(tmp, &tmp, 16);
|
||||
if ((tmp - file_path.c_str()) < file_path.length())
|
||||
{
|
||||
high = strtoull(tmp+1, nullptr, 16);
|
||||
if (low != 0 && high > low && low <= handle && handle <= high)
|
||||
{
|
||||
res = System::ExpandSymlink(self + file_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetModules()
|
||||
{
|
||||
std::string const self("/proc/self/map_files/");
|
||||
std::vector<std::string> paths;
|
||||
|
||||
DIR* dir;
|
||||
struct dirent* dir_entry;
|
||||
std::string path;
|
||||
bool found;
|
||||
|
||||
dir = opendir(self.c_str());
|
||||
if (dir != nullptr)
|
||||
{
|
||||
while ((dir_entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (dir_entry->d_type != DT_LNK)
|
||||
{// Not a link
|
||||
continue;
|
||||
}
|
||||
|
||||
found = false;
|
||||
path = System::ExpandSymlink(self + dir_entry->d_name);
|
||||
for (auto const& item : paths)
|
||||
{
|
||||
if (item == path)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
paths.emplace_back(std::move(path));
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetProcArgs()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
std::ifstream fcmdline("/proc/self/cmdline", std::ios::in | std::ios::binary);
|
||||
|
||||
if (fcmdline)
|
||||
{
|
||||
for (std::string line; std::getline(fcmdline, line, '\0');)
|
||||
{
|
||||
res.emplace_back(std::move(line));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int IsProcessTranslated()
|
||||
{
|
||||
int ret = 0;
|
||||
size_t size = sizeof(ret);
|
||||
|
||||
// Call the sysctl and if successful return the result
|
||||
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) != -1)
|
||||
return ret;
|
||||
|
||||
// If "sysctl.proc_translated" is not present then must be native
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point GetBootTime()
|
||||
{
|
||||
static std::chrono::system_clock::time_point boottime{};
|
||||
if (boottime == std::chrono::system_clock::time_point{})
|
||||
{
|
||||
struct timeval boottime_tv;
|
||||
size_t len = sizeof(boottime_tv);
|
||||
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(*mib), &boottime_tv, &len, nullptr, 0) < 0)
|
||||
return boottime;
|
||||
|
||||
boottime = std::chrono::system_clock::time_point(
|
||||
std::chrono::seconds(boottime_tv.tv_sec) +
|
||||
std::chrono::microseconds(boottime_tv.tv_usec));
|
||||
}
|
||||
|
||||
return boottime;
|
||||
}
|
||||
|
||||
std::string GetExecutablePath()
|
||||
{
|
||||
std::string exec_path("./");
|
||||
|
||||
task_dyld_info dyld_info;
|
||||
task_t t;
|
||||
pid_t pid = getpid();
|
||||
task_for_pid(mach_task_self(), pid, &t);
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||
{
|
||||
dyld_all_image_infos *dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||
if (IsProcessTranslated() == 1)
|
||||
{
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||
if (strcasestr(exec_path.c_str(), "rosetta") != nullptr)
|
||||
continue;
|
||||
|
||||
// In case of a translated process (Rosetta maybe ?), the executable path is not the first entry.
|
||||
size_t pos;
|
||||
while ((pos = exec_path.find("/./")) != std::string::npos)
|
||||
{
|
||||
exec_path.replace(pos, 3, "/");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
// For now I don't know how to be sure to get the executable path
|
||||
// but looks like the 1st entry is the executable path
|
||||
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||
size_t pos;
|
||||
while ((pos = exec_path.find("/./")) != std::string::npos)
|
||||
{
|
||||
exec_path.replace(pos, 3, "/");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exec_path;
|
||||
}
|
||||
|
||||
// Workaround for MacOS, I don't know how to get module path from address.
|
||||
SYSTEM_EXPORT_API(SYSTEM_EXTERN_C, void, SYSTEM_MODE_EXPORT, SYSTEM_CALL_DEFAULT) GetModulePathPlaceholder() {}
|
||||
|
||||
std::string GetModulePath()
|
||||
{
|
||||
task_dyld_info dyld_info;
|
||||
task_t t;
|
||||
pid_t pid = getpid();
|
||||
task_for_pid(mach_task_self(), pid, &t);
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||
{
|
||||
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||
if (res != nullptr)
|
||||
{
|
||||
void* placeholder = dlsym(res, "GetModulePathPlaceholder");
|
||||
dlclose(res);
|
||||
if(placeholder == (void*)&GetModulePathPlaceholder)
|
||||
{
|
||||
std::string res(dyld_img_infos->infoArray[i].imageFilePath);
|
||||
size_t pos;
|
||||
while((pos = res.find("/./")) != std::string::npos)
|
||||
{
|
||||
res.replace(pos, 3, "/");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::vector<std::string> GetModules()
|
||||
{
|
||||
std::vector<std::string> paths;
|
||||
std::string path;
|
||||
size_t pos;
|
||||
task_dyld_info dyld_info;
|
||||
task_t t;
|
||||
pid_t pid = getpid();
|
||||
task_for_pid(mach_task_self(), pid, &t);
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||
{
|
||||
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||
{
|
||||
path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||
while ((pos = path.find("/./")) != std::string::npos)
|
||||
{
|
||||
path.replace(pos, 3, "/");
|
||||
}
|
||||
paths.emplace_back(std::move(path));
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetProcArgs()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
int mib[3];
|
||||
int argmax;
|
||||
size_t size;
|
||||
int nargs;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARGMAX;
|
||||
|
||||
size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> procargs(new char[argmax]);
|
||||
if (procargs == nullptr)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = getpid();
|
||||
|
||||
size = (size_t)argmax;
|
||||
if (sysctl(mib, 3, procargs.get(), &size, NULL, 0) == -1)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
memcpy(&nargs, procargs.get(), sizeof(nargs));
|
||||
if (nargs <= 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
char* args_end = procargs.get() + size;
|
||||
char* arg_iterator = procargs.get() + sizeof(nargs);
|
||||
// Skip saved exec path
|
||||
while (*arg_iterator != '\0' && arg_iterator < args_end)
|
||||
{
|
||||
++arg_iterator;
|
||||
}
|
||||
// Skip trailing(s) '\0'
|
||||
while (*arg_iterator == '\0' && arg_iterator < args_end)
|
||||
{
|
||||
++arg_iterator;
|
||||
}
|
||||
|
||||
res.reserve(nargs);
|
||||
char* arg = arg_iterator;
|
||||
for (int i = 0; i < nargs && arg_iterator < args_end; ++arg_iterator)
|
||||
{
|
||||
if (*arg_iterator == '\0')
|
||||
{
|
||||
++i;
|
||||
res.emplace_back(arg);
|
||||
arg = arg_iterator + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string GetUserdataPath()
|
||||
{
|
||||
std::string user_appdata_path;
|
||||
/*
|
||||
~/Library/Application Support/<application name>
|
||||
~/Library/Preferences/<application name>
|
||||
~/Library/<application name>/
|
||||
*/
|
||||
|
||||
struct passwd* user_entry = getpwuid(getuid());
|
||||
if (user_entry == nullptr || user_entry->pw_dir == nullptr)
|
||||
{
|
||||
char* env_var = getenv("HOME");
|
||||
if (env_var != nullptr)
|
||||
{
|
||||
user_appdata_path = env_var;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user_appdata_path = user_entry->pw_dir;
|
||||
}
|
||||
|
||||
if (!user_appdata_path.empty())
|
||||
{
|
||||
#ifdef SYSTEM_OS_LINUX
|
||||
user_appdata_path = System::Filesystem::Join(user_appdata_path, ".config");
|
||||
#else
|
||||
user_appdata_path = System::Filesystem::Join(user_appdata_path, "Library", "Application Support");
|
||||
#endif
|
||||
}
|
||||
|
||||
return user_appdata_path;
|
||||
}
|
||||
|
||||
std::string GetEnvVar(std::string const& var)
|
||||
{
|
||||
char* env = getenv(var.c_str());
|
||||
if (env == nullptr)
|
||||
return std::string();
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
44
overlay_experimental/System/System.h
Normal file
44
overlay_experimental/System/System.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with the System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::chrono::system_clock::time_point GetBootTime();
|
||||
std::chrono::microseconds GetUpTime();
|
||||
|
||||
// Get the current process argv
|
||||
std::vector<std::string> GetProcArgs();
|
||||
// Get User env variable
|
||||
std::string GetEnvVar(std::string const& var);
|
||||
// User appdata full path
|
||||
std::string GetUserdataPath();
|
||||
// Executable full path
|
||||
std::string GetExecutablePath();
|
||||
// .dll, .so or .dylib full path
|
||||
std::string GetModulePath();
|
||||
// List all loaded modules
|
||||
std::vector<std::string> GetModules();
|
||||
|
||||
}
|
||||
105
overlay_experimental/System/SystemDetector.h
Normal file
105
overlay_experimental/System/SystemDetector.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
|
||||
#define SYSTEM_OS_WINDOWS
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#define SYSTEM_ARCH_X86
|
||||
#elif defined(_M_AMD64)
|
||||
#define SYSTEM_ARCH_X64
|
||||
#elif defined(_M_ARM)
|
||||
#define SYSTEM_ARCH_ARM
|
||||
#elif defined(_M_ARM64)
|
||||
#define SYSTEM_ARCH_ARM64
|
||||
#else
|
||||
#error "Unhandled arch"
|
||||
#endif
|
||||
#elif defined(__linux__) || defined(linux)
|
||||
#define SYSTEM_OS_LINUX
|
||||
|
||||
#if defined(__i386__) || defined(__i386) || defined(i386)
|
||||
#define SYSTEM_ARCH_X86
|
||||
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
|
||||
#define SYSTEM_ARCH_X64
|
||||
#elif defined(__arm__)
|
||||
#define SYSTEM_ARCH_ARM
|
||||
#elif defined(__aarch64__)
|
||||
#define SYSTEM_ARCH_ARM64
|
||||
#else
|
||||
#error "Unhandled arch"
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#define SYSTEM_OS_APPLE
|
||||
|
||||
#if defined(__i386__) || defined(__i386) || defined(i386)
|
||||
#define SYSTEM_ARCH_X86
|
||||
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
|
||||
#define SYSTEM_ARCH_X64
|
||||
#elif defined(__arm__)
|
||||
#define SYSTEM_ARCH_ARM
|
||||
#elif defined(__aarch64__)
|
||||
#define SYSTEM_ARCH_ARM64
|
||||
#else
|
||||
#error "Unhandled arch"
|
||||
#endif
|
||||
#else
|
||||
//#error "Unknown OS"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Some constexpr for C++17 constexpr if.
|
||||
namespace System {
|
||||
enum class OperatingSystem {
|
||||
Windows = 0,
|
||||
Linux = 1,
|
||||
Apple = 2,
|
||||
};
|
||||
|
||||
enum class Arch {
|
||||
x86 = 0,
|
||||
x64 = 1,
|
||||
arm = 2,
|
||||
aarch64 = 3,
|
||||
};
|
||||
|
||||
static constexpr OperatingSystem os =
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
OperatingSystem::Windows;
|
||||
#elif defined(SYSTEM_OS_LINUX)
|
||||
OperatingSystem::Linux;
|
||||
#elif defined(SYSTEM_OS_APPLE)
|
||||
OperatingSystem::Apple;
|
||||
#endif
|
||||
|
||||
static constexpr Arch arch =
|
||||
#if defined(SYSTEM_ARCH_X86)
|
||||
Arch::x86;
|
||||
#elif defined(SYSTEM_ARCH_X64)
|
||||
Arch::x64;
|
||||
#elif defined(SYSTEM_ARCH_ARM)
|
||||
Arch::arm;
|
||||
#elif defined(SYSTEM_ARCH_ARM64)
|
||||
Arch::aarch64;
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
125
overlay_experimental/System/SystemExports.h
Normal file
125
overlay_experimental/System/SystemExports.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SystemDetector.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define SYSTEM_EXTERN_NONE
|
||||
#define SYSTEM_EXTERN_C extern "C"
|
||||
#define SYSTEM_EXTERN_CXX extern
|
||||
#else
|
||||
#define SYSTEM_EXTERN_NONE
|
||||
#define SYSTEM_EXTERN_C extern
|
||||
#define SYSTEM_EXTERN_CXX #error "No C++ export in C"
|
||||
#endif
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
#if defined(__clang__)
|
||||
#define SYSTEM_CALL_DEFAULT
|
||||
#define SYSTEM_CALL_STDL __stdcall
|
||||
#define SYSTEM_CALL_CDECL __cdecl
|
||||
#define SYSTEM_CALL_FAST __fastcall
|
||||
#define SYSTEM_CALL_THIS __thiscall
|
||||
|
||||
#define SYSTEM_MODE_DEFAULT
|
||||
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
|
||||
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
|
||||
#define SYSTEM_MODE_HIDDEN
|
||||
|
||||
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
|
||||
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||
#else
|
||||
#define SYSTEM_CALL_DEFAULT
|
||||
#define SYSTEM_CALL_STDL __stdcall
|
||||
#define SYSTEM_CALL_CDECL __cdecl
|
||||
#define SYSTEM_CALL_FAST __fastcall
|
||||
#define SYSTEM_CALL_THIS __thiscall
|
||||
|
||||
#define SYSTEM_MODE_DEFAULT
|
||||
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
|
||||
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
|
||||
#define SYSTEM_MODE_HIDDEN
|
||||
|
||||
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
|
||||
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||
#endif
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
#define SYSTEM_CALL_DEFAULT
|
||||
#define SYSTEM_CALL_STD __attribute__((stdcall))
|
||||
#define SYSTEM_CALL_CDECL __attribute__((cdecl))
|
||||
#define SYSTEM_CALL_FAST __attribute__((fastcall))
|
||||
#define SYSTEM_CALL_THIS __attribute__((thiscall))
|
||||
|
||||
#define SYSTEM_MODE_DEFAULT
|
||||
#define SYSTEM_MODE_EXPORT __attribute__((visibility("default")))
|
||||
#define SYSTEM_MODE_IMPORT __attribute__((visibility("default")))
|
||||
#define SYSTEM_MODE_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE keyword SYSTEM_MODE_HIDDEN
|
||||
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||
|
||||
//#define LOCAL_API __attribute__((visibility ("internal")))
|
||||
#endif
|
||||
|
||||
/*
|
||||
Copy/Paste this code in some source file if you want to call a function when the shared_library is loaded/unloaded.
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
|
||||
#define VC_EXTRALEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
shared_library_load();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
shared_library_unload();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||
|
||||
__attribute__((constructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_constructor()
|
||||
{
|
||||
shared_library_load();
|
||||
}
|
||||
|
||||
__attribute__((destructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_destructor()
|
||||
{
|
||||
shared_library_unload();
|
||||
}
|
||||
|
||||
#endif
|
||||
*/
|
||||
60
overlay_experimental/System/System_internals.cpp
Normal file
60
overlay_experimental/System/System_internals.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "System_internals.h"
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
namespace System {
|
||||
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX)
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace System {
|
||||
SYSTEM_HIDE_API(std::string, SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path)
|
||||
{
|
||||
struct stat file_stat;
|
||||
std::string link_target;
|
||||
ssize_t name_len = 128;
|
||||
while(lstat(file_path.c_str(), &file_stat) >= 0 && S_ISLNK(file_stat.st_mode) == 1)
|
||||
{
|
||||
do
|
||||
{
|
||||
name_len *= 2;
|
||||
link_target.resize(name_len);
|
||||
name_len = readlink(file_path.c_str(), &link_target[0], link_target.length());
|
||||
} while (name_len == link_target.length());
|
||||
link_target.resize(name_len);
|
||||
file_path = std::move(link_target);
|
||||
}
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
37
overlay_experimental/System/System_internals.h
Normal file
37
overlay_experimental/System/System_internals.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SystemExports.h"
|
||||
|
||||
#if defined(SYSTEM_OS_WINDOWS)
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
}
|
||||
|
||||
#elif defined(SYSTEM_OS_LINUX)
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
SYSTEM_HIDE_API(std::string , SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path);
|
||||
}
|
||||
|
||||
#endif
|
||||
164
overlay_experimental/System/ThreadPool.hpp
Normal file
164
overlay_experimental/System/ThreadPool.hpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (C) Nemirtingas
|
||||
* This file is part of System.
|
||||
*
|
||||
* System is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* System is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with the System; if not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace System {
|
||||
class ThreadPool
|
||||
{
|
||||
using task_t = std::function<void()>;
|
||||
|
||||
std::atomic<bool> _StopWorkers;
|
||||
std::atomic<std::size_t> _ActiveCount;
|
||||
|
||||
std::condition_variable _WorkerNotifier;
|
||||
std::mutex _Mutex;
|
||||
|
||||
std::vector<std::thread> _Workers;
|
||||
std::queue<task_t> _Tasks;
|
||||
|
||||
public:
|
||||
explicit ThreadPool():
|
||||
_ActiveCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
~ThreadPool()
|
||||
{
|
||||
Join();
|
||||
}
|
||||
|
||||
ThreadPool(ThreadPool const &) = delete;
|
||||
ThreadPool(ThreadPool&&) = default;
|
||||
|
||||
ThreadPool&operator=(ThreadPool const &) = delete;
|
||||
ThreadPool&operator=(ThreadPool&&) = default;
|
||||
|
||||
template <class Func, class... Args>
|
||||
auto Push(Func &&fn, Args &&...args)
|
||||
{
|
||||
using return_type = typename std::result_of<Func(Args...)>::type;
|
||||
|
||||
auto task{ std::make_shared<std::packaged_task<return_type()>>(
|
||||
std::bind(std::forward<Func>(fn), std::forward<Args>(args)...)
|
||||
) };
|
||||
|
||||
auto future{ task->get_future() };
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_Mutex);
|
||||
|
||||
_Tasks.emplace([task]()
|
||||
{
|
||||
(*task)();
|
||||
});
|
||||
}
|
||||
|
||||
_WorkerNotifier.notify_one();
|
||||
return future;
|
||||
}
|
||||
|
||||
// Remove all pending tasks from the queue
|
||||
void Clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_Mutex);
|
||||
_Tasks = {};
|
||||
}
|
||||
|
||||
// Stops all previous and creates new worker threads.
|
||||
void Start(std::size_t worker_count = std::thread::hardware_concurrency())
|
||||
{
|
||||
Join();
|
||||
|
||||
_StopWorkers = false;
|
||||
for (std::size_t i = 0; i < worker_count; ++i)
|
||||
_Workers.emplace_back(std::bind(&ThreadPool::_WorkerLoop, this));
|
||||
}
|
||||
|
||||
// Wait all workers to finish
|
||||
void Join()
|
||||
{
|
||||
_StopWorkers = true;
|
||||
_WorkerNotifier.notify_all();
|
||||
|
||||
for (auto &thread : _Workers)
|
||||
{
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
}
|
||||
|
||||
_Workers.clear();
|
||||
}
|
||||
|
||||
std::size_t WorkerCount() const
|
||||
{
|
||||
return _Workers.size();
|
||||
}
|
||||
|
||||
// Get the number of active workers
|
||||
std::size_t ActiveCount() const
|
||||
{
|
||||
return _ActiveCount;
|
||||
}
|
||||
|
||||
private:
|
||||
void _WorkerLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
auto task{ _NextTask() };
|
||||
|
||||
if (task)
|
||||
{
|
||||
++_ActiveCount;
|
||||
task();
|
||||
--_ActiveCount;
|
||||
}
|
||||
else if (_StopWorkers)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task_t _NextTask()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{ _Mutex };
|
||||
|
||||
_WorkerNotifier.wait(lock, [this]() { return !_Tasks.empty() || _StopWorkers; });
|
||||
|
||||
if (_Tasks.empty())
|
||||
return {};
|
||||
|
||||
auto task{ _Tasks.front() };
|
||||
_Tasks.pop();
|
||||
return task;
|
||||
}
|
||||
};
|
||||
}
|
||||
34
overlay_experimental/System/utfcpp/utf8.h
Normal file
34
overlay_experimental/System/utfcpp/utf8.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "utf8/checked.h"
|
||||
#include "utf8/unchecked.h"
|
||||
|
||||
#endif // header guard
|
||||
336
overlay_experimental/System/utfcpp/utf8/checked.h
Normal file
336
overlay_experimental/System/utfcpp/utf8/checked.h
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
// Copyright 2006-2016 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// Base for the exceptions that may be thrown from the library
|
||||
class exception : public ::std::exception {
|
||||
};
|
||||
|
||||
// Exceptions that may be thrown from the library functions.
|
||||
class invalid_code_point : public exception {
|
||||
uint32_t cp;
|
||||
public:
|
||||
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
|
||||
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
|
||||
uint32_t code_point() const {return cp;}
|
||||
};
|
||||
|
||||
class invalid_utf8 : public exception {
|
||||
uint8_t u8;
|
||||
public:
|
||||
invalid_utf8 (uint8_t u) : u8(u) {}
|
||||
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
|
||||
uint8_t utf8_octet() const {return u8;}
|
||||
};
|
||||
|
||||
class invalid_utf16 : public exception {
|
||||
uint16_t u16;
|
||||
public:
|
||||
invalid_utf16 (uint16_t u) : u16(u) {}
|
||||
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
|
||||
uint16_t utf16_word() const {return u16;}
|
||||
};
|
||||
|
||||
class not_enough_room : public exception {
|
||||
public:
|
||||
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
|
||||
};
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (!utf8::internal::is_code_point_valid(cp))
|
||||
throw invalid_code_point(cp);
|
||||
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||
{
|
||||
while (start != end) {
|
||||
octet_iterator sequence_start = start;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||
*out++ = *it;
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM:
|
||||
out = utf8::append (replacement, out);
|
||||
start = end;
|
||||
break;
|
||||
case internal::INVALID_LEAD:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
break;
|
||||
case internal::INCOMPLETE_SEQUENCE:
|
||||
case internal::OVERLONG_SEQUENCE:
|
||||
case internal::INVALID_CODE_POINT:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
// just one replacement mark for the sequence
|
||||
while (start != end && utf8::internal::is_trail(*start))
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||
{
|
||||
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||
return utf8::replace_invalid(start, end, out, replacement_marker);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
uint32_t cp = 0;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM :
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD :
|
||||
case internal::INCOMPLETE_SEQUENCE :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
throw invalid_utf8(*it);
|
||||
case internal::INVALID_CODE_POINT :
|
||||
throw invalid_code_point(cp);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it, octet_iterator start)
|
||||
{
|
||||
// can't do much if it == start
|
||||
if (it == start)
|
||||
throw not_enough_room();
|
||||
|
||||
octet_iterator end = it;
|
||||
// Go back until we hit either a lead octet or start
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
return utf8::peek_next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n, octet_iterator end)
|
||||
{
|
||||
const distance_type zero(0);
|
||||
if (n < zero) {
|
||||
// backward
|
||||
for (distance_type i = n; i < zero; ++i)
|
||||
utf8::prior(it, end);
|
||||
} else {
|
||||
// forward
|
||||
for (distance_type i = zero; i < n; ++i)
|
||||
utf8::next(it, end);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::next(first, last);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
if (start != end) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
if (utf8::internal::is_trail_surrogate(trail_surrogate))
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
|
||||
}
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
}
|
||||
// Lone trail surrogate
|
||||
else if (utf8::internal::is_trail_surrogate(cp))
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
result = utf8::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::next(start, end);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::next(start, end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator {
|
||||
octet_iterator it;
|
||||
octet_iterator range_start;
|
||||
octet_iterator range_end;
|
||||
public:
|
||||
typedef uint32_t value_type;
|
||||
typedef uint32_t* pointer;
|
||||
typedef uint32_t& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it,
|
||||
const octet_iterator& rangestart,
|
||||
const octet_iterator& rangeend) :
|
||||
it(octet_it), range_start(rangestart), range_end(rangeend)
|
||||
{
|
||||
if (it < range_start || it > range_end)
|
||||
throw std::out_of_range("Invalid utf-8 iterator position");
|
||||
}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, range_end);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
if (range_start != rhs.range_start || range_end != rhs.range_end)
|
||||
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
utf8::next(it, range_end);
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::next(it, range_end);
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::prior(it, range_start);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::prior(it, range_start);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
|
||||
#include "cpp17.h"
|
||||
//#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
|
||||
#else
|
||||
#include "cpp11.h"
|
||||
#endif // C++ 11 or later
|
||||
|
||||
#endif //header guard
|
||||
|
||||
338
overlay_experimental/System/utfcpp/utf8/core.h
Normal file
338
overlay_experimental/System/utfcpp/utf8/core.h
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include <iterator>
|
||||
|
||||
// Determine the C++ standard version.
|
||||
// If the user defines UTF_CPP_CPLUSPLUS, use that.
|
||||
// Otherwise, trust the unreliable predefined macro __cplusplus
|
||||
|
||||
#if !defined UTF_CPP_CPLUSPLUS
|
||||
#define UTF_CPP_CPLUSPLUS __cplusplus
|
||||
#endif
|
||||
|
||||
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
|
||||
#define UTF_CPP_OVERRIDE override
|
||||
#define UTF_CPP_NOEXCEPT noexcept
|
||||
#else // C++ 98/03
|
||||
#define UTF_CPP_OVERRIDE
|
||||
#define UTF_CPP_NOEXCEPT throw()
|
||||
#endif // C++ 11 or later
|
||||
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||
// You may need to change them to match your system.
|
||||
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||
namespace internal
|
||||
{
|
||||
// Unicode constants
|
||||
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||
const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
|
||||
const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
|
||||
|
||||
// Maximum valid value for a Unicode code point
|
||||
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||
|
||||
template<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||
sequence_length(octet_iterator lead_it)
|
||||
{
|
||||
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||
if (lead < 0x80)
|
||||
return 1;
|
||||
else if ((lead >> 5) == 0x6)
|
||||
return 2;
|
||||
else if ((lead >> 4) == 0xe)
|
||||
return 3;
|
||||
else if ((lead >> 3) == 0x1e)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename octet_difference_type>
|
||||
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
if (length != 1)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
if (length != 2)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x10000) {
|
||||
if (length != 3)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||
|
||||
/// Helper for get_sequence_x
|
||||
template <typename octet_iterator>
|
||||
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
if (++it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
if (!utf8::internal::is_trail(*it))
|
||||
return INCOMPLETE_SEQUENCE;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
// Save the original value of it so we can go back in case of failure
|
||||
// Of course, it does not make much sense with i.e. stream iterators
|
||||
octet_iterator original_it = it;
|
||||
|
||||
uint32_t cp = 0;
|
||||
// Determine the sequence length based on the lead octet
|
||||
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||
|
||||
// Get trail octets and calculate the code point
|
||||
utf_error err = UTF8_OK;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return INVALID_LEAD;
|
||||
case 1:
|
||||
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||
break;
|
||||
case 2:
|
||||
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||
break;
|
||||
case 3:
|
||||
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||
break;
|
||||
case 4:
|
||||
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||
uint32_t ignored;
|
||||
return utf8::internal::validate_next(it, end, ignored);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
// Byte order mark
|
||||
constexpr uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
octet_iterator result = start;
|
||||
while (result != end) {
|
||||
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||
if (err_code != internal::UTF8_OK)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return (
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||
);
|
||||
}
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
||||
103
overlay_experimental/System/utfcpp/utf8/cpp11.h
Normal file
103
overlay_experimental/System/utfcpp/utf8/cpp11.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2018 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
|
||||
#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
|
||||
|
||||
#include "checked.h"
|
||||
#include <string>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
|
||||
inline void append(char32_t cp, std::string& s)
|
||||
{
|
||||
append(uint32_t(cp), std::back_inserter(s));
|
||||
}
|
||||
|
||||
inline std::string utf16to8(const std::u16string& s)
|
||||
{
|
||||
std::string result;
|
||||
utf16to8(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::u16string utf8to16(const std::string& s)
|
||||
{
|
||||
std::u16string result;
|
||||
utf8to16(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string utf32to8(const std::u32string& s)
|
||||
{
|
||||
std::string result;
|
||||
utf32to8(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::u32string utf8to32(const std::string& s)
|
||||
{
|
||||
std::u32string result;
|
||||
utf8to32(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::size_t find_invalid(const std::string& s)
|
||||
{
|
||||
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
|
||||
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
|
||||
}
|
||||
|
||||
inline bool is_valid(const std::string& s)
|
||||
{
|
||||
return is_valid(s.begin(), s.end());
|
||||
}
|
||||
|
||||
inline std::string replace_invalid(const std::string& s, char32_t replacement)
|
||||
{
|
||||
std::string result;
|
||||
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string replace_invalid(const std::string& s)
|
||||
{
|
||||
std::string result;
|
||||
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool starts_with_bom(const std::string& s)
|
||||
{
|
||||
return starts_with_bom(s.begin(), s.end());
|
||||
}
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
103
overlay_experimental/System/utfcpp/utf8/cpp17.h
Normal file
103
overlay_experimental/System/utfcpp/utf8/cpp17.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2018 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
|
||||
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
|
||||
|
||||
#include "checked.h"
|
||||
#include <string>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
|
||||
inline void append(char32_t cp, std::string& s)
|
||||
{
|
||||
append(uint32_t(cp), std::back_inserter(s));
|
||||
}
|
||||
|
||||
inline std::string utf16to8(std::u16string_view s)
|
||||
{
|
||||
std::string result;
|
||||
utf16to8(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::u16string utf8to16(std::string_view s)
|
||||
{
|
||||
std::u16string result;
|
||||
utf8to16(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string utf32to8(std::u32string_view s)
|
||||
{
|
||||
std::string result;
|
||||
utf32to8(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::u32string utf8to32(std::string_view s)
|
||||
{
|
||||
std::u32string result;
|
||||
utf8to32(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::size_t find_invalid(std::string_view s)
|
||||
{
|
||||
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
|
||||
return (invalid == s.end()) ? std::string_view::npos : (invalid - s.begin());
|
||||
}
|
||||
|
||||
inline bool is_valid(std::string_view s)
|
||||
{
|
||||
return is_valid(s.begin(), s.end());
|
||||
}
|
||||
|
||||
inline std::string replace_invalid(std::string_view s, char32_t replacement)
|
||||
{
|
||||
std::string result;
|
||||
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string replace_invalid(std::string_view s)
|
||||
{
|
||||
std::string result;
|
||||
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool starts_with_bom(std::string_view s)
|
||||
{
|
||||
return starts_with_bom(s.begin(), s.end());
|
||||
}
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
274
overlay_experimental/System/utfcpp/utf8/unchecked.h
Normal file
274
overlay_experimental/System/utfcpp/utf8/unchecked.h
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
namespace unchecked
|
||||
{
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||
{
|
||||
while (start != end) {
|
||||
octet_iterator sequence_start = start;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||
*out++ = *it;
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM:
|
||||
out = utf8::unchecked::append (replacement, out);
|
||||
start = end;
|
||||
break;
|
||||
case internal::INVALID_LEAD:
|
||||
out = utf8::unchecked::append (replacement, out);
|
||||
++start;
|
||||
break;
|
||||
case internal::INCOMPLETE_SEQUENCE:
|
||||
case internal::OVERLONG_SEQUENCE:
|
||||
case internal::INVALID_CODE_POINT:
|
||||
out = utf8::unchecked::append (replacement, out);
|
||||
++start;
|
||||
// just one replacement mark for the sequence
|
||||
while (start != end && utf8::internal::is_trail(*start))
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||
{
|
||||
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||
return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it)
|
||||
{
|
||||
uint32_t cp = utf8::internal::mask8(*it);
|
||||
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
|
||||
switch (length) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
it++;
|
||||
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
break;
|
||||
case 3:
|
||||
++it;
|
||||
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
case 4:
|
||||
++it;
|
||||
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
++it;
|
||||
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it)
|
||||
{
|
||||
return utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it)
|
||||
{
|
||||
while (utf8::internal::is_trail(*(--it))) ;
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n)
|
||||
{
|
||||
const distance_type zero(0);
|
||||
if (n < zero) {
|
||||
// backward
|
||||
for (distance_type i = n; i < zero; ++i)
|
||||
utf8::unchecked::prior(it);
|
||||
} else {
|
||||
// forward
|
||||
for (distance_type i = zero; i < n; ++i)
|
||||
utf8::unchecked::next(it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::unchecked::next(first);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
}
|
||||
result = utf8::unchecked::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::unchecked::next(start);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::unchecked::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::unchecked::next(start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator {
|
||||
octet_iterator it;
|
||||
public:
|
||||
typedef uint32_t value_type;
|
||||
typedef uint32_t* pointer;
|
||||
typedef uint32_t& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::unchecked::prior(it);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::unchecked::prior(it);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8::unchecked
|
||||
} // namespace utf8
|
||||
|
||||
|
||||
#endif // header guard
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue