From d69ddc723498aa7a7006bd85b9ad3805dc52495e Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:40:19 +0100 Subject: [PATCH] VFS: Add LibrarySys class helper --- amxmodx/CLibrarySys.cpp | 559 ++++++++++++++++++++++++++++++++++++++++ amxmodx/CLibrarySys.h | 175 +++++++++++++ amxmodx/modules.cpp | 24 -- amxmodx/modules.h | 1 - 4 files changed, 734 insertions(+), 25 deletions(-) create mode 100644 amxmodx/CLibrarySys.cpp create mode 100644 amxmodx/CLibrarySys.h diff --git a/amxmodx/CLibrarySys.cpp b/amxmodx/CLibrarySys.cpp new file mode 100644 index 00000000..03b2892d --- /dev/null +++ b/amxmodx/CLibrarySys.cpp @@ -0,0 +1,559 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#include "CLibrarySys.h" +#include + +LibrarySystem g_LibSys; + +/******************/ +/* Directory Code */ +/******************/ + +CDirectory::CDirectory(const char *path) +{ +#if defined PLATFORM_WINDOWS + + char newpath[PLATFORM_MAX_PATH]; + UTIL_Format(newpath, sizeof(newpath) - 1, "%s\\*.*", path); + + m_dir = FindFirstFile(newpath, &m_fd); + + if (!IsValid()) + { + m_fd.cFileName[0] = '\0'; + } + +#elif defined PLATFORM_POSIX + + m_dir = opendir(path); + + if (IsValid()) + { + m_ep = readdir(m_dir); // TODO: we need to read past "." and ".."! + UTIL_Format(m_origpath, sizeof(m_origpath) - 1, "%s", path); + } + else + { + m_ep = nullptr; + } +#endif +} + +CDirectory::~CDirectory() +{ + if (IsValid()) + { +#if defined PLATFORM_WINDOWS + + FindClose(m_dir); + +#elif defined PLATFORM_POSIX + + closedir(m_dir); +#endif + } +} + +void CDirectory::NextEntry(cell* offset) +{ +#if defined PLATFORM_WINDOWS + + if (offset) + { + // Should be declared after loop so entry starts to '.' and not '..' + // But old code did that, so keep this for compatibility. + ++*offset; + + for (cell i = 0; i < *offset; ++i) + { + if (FindNextFile(m_dir, &m_fd) == 0) + { + *offset = 0; + FindClose(m_dir); + m_dir = INVALID_HANDLE_VALUE; + return; + } + } + } + else if (FindNextFile(m_dir, &m_fd) == 0) + { + FindClose(m_dir); + m_dir = INVALID_HANDLE_VALUE; + } + +#elif defined PLATFORM_POSIX + + if (offset) + { + seekdir(m_dir, *offset); + + if (!(m_ep = readdir(m_dir))) + { + *offset = 0; + closedir(m_dir); + m_dir = nullptr; + } + else + { + *offset = telldir(m_dir); + } + } + else if (!(m_ep = readdir(m_dir))) + { + closedir(m_dir); + m_dir = nullptr; + } +#endif +} + +bool CDirectory::IsEntryValid() +{ + return IsValid(); +} + +bool CDirectory::IsEntryDirectory() +{ +#if defined PLATFORM_WINDOWS + + return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); + +#elif defined PLATFORM_POSIX + + char temppath[PLATFORM_MAX_PATH]; + UTIL_Format(temppath, sizeof(temppath) - 1, "%s/%s", m_origpath, GetEntryName()); + + return g_LibSys.IsPathDirectory(temppath); + +#endif +} + +bool CDirectory::IsEntryFile() +{ +#if defined PLATFORM_WINDOWS + + return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); + +#elif defined PLATFORM_POSIX + + char temppath[PLATFORM_MAX_PATH]; + UTIL_Format(temppath, sizeof(temppath) - 1, "%s/%s", m_origpath, GetEntryName()); + + return g_LibSys.IsPathFile(temppath); + +#endif +} + +const char* CDirectory::GetEntryName() +{ +#if defined PLATFORM_WINDOWS + + return m_fd.cFileName; + +#elif defined PLATFORM_POSIX + + return m_ep ? m_ep->d_name : ""; + +#endif +} + +bool CDirectory::MoreFiles() +{ + return IsValid(); +} + +bool CDirectory::IsValid() +{ +#if defined PLATFORM_WINDOWS + + return (m_dir != INVALID_HANDLE_VALUE); + +#elif defined PLATFORM_POSIX + + return (m_dir != nullptr); +#endif +} + + +/****************/ +/* Library Code */ +/****************/ + +CLibrary::~CLibrary() +{ + if (m_lib) + { +#if defined PLATFORM_WINDOWS + + FreeLibrary(m_lib); + +#elif defined PLATFORM_POSIX + + dlclose(m_lib); +#endif + m_lib = nullptr; + } +} + +CLibrary::CLibrary(LibraryHandle me) +{ + m_lib = me; +} + +void CLibrary::CloseLibrary() +{ + delete this; +} + +void *CLibrary::GetSymbolAddress(const char* symname) +{ +#if defined PLATFORM_WINDOWS + + return GetProcAddress(m_lib, symname); + +#elif defined PLATFORM_POSIX + + return dlsym(m_lib, symname); +#endif +} + + +/***********************/ +/* Library System Code */ +/***********************/ + +bool LibrarySystem::PathExists(const char *path) +{ +#if defined PLATFORM_WINDOWS + + DWORD attr = GetFileAttributesA(path); + + return (attr != INVALID_FILE_ATTRIBUTES); + +#elif defined PLATFORM_POSIX + + struct stat s; + + return (stat(path, &s) == 0); +#endif +} + +bool LibrarySystem::IsPathFile(const char* path) +{ +#if defined PLATFORM_WINDOWS + + DWORD attr = GetFileAttributes(path); + + if (attr == INVALID_FILE_ATTRIBUTES) + { + return false; + } + + if (attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) + { + return false; + } + + return true; + +#elif defined PLATFORM_POSIX + + struct stat s; + + if (stat(path, &s) != 0) + { + return false; + } + + return S_ISREG(s.st_mode) ? true : false; +#endif +} + +bool LibrarySystem::IsPathDirectory(const char* path) +{ +#if defined PLATFORM_WINDOWS + + DWORD attr = GetFileAttributes(path); + + if (attr == INVALID_FILE_ATTRIBUTES) + { + return false; + } + + if (attr & FILE_ATTRIBUTE_DIRECTORY) + { + return true; + } + +#elif defined PLATFORM_POSIX + + struct stat s; + + if (stat(path, &s) != 0) + { + return false; + } + + if (S_ISDIR(s.st_mode)) + { + return true; + } +#endif + + return false; +} + +CDirectory *LibrarySystem::OpenDirectory(const char* path) +{ + CDirectory* dir = new CDirectory(path); + + if (!dir->IsValid()) + { + delete dir; + return nullptr; + } + + return dir; +} + +CLibrary* LibrarySystem::OpenLibrary(const char* path, char* error, size_t maxlength) +{ +#if defined PLATFORM_WINDOWS + + LibraryHandle lib = LoadLibrary(path); + +#elif defined PLATFORM_POSIX + + LibraryHandle lib = dlopen(path, RTLD_NOW); +#endif + + if (!lib) + { + if (error && maxlength) + { + GetLoaderError(error, maxlength); + } + + return nullptr; + } + + return new CLibrary(lib); +} + +void LibrarySystem::GetPlatformError(char* error, size_t maxlength) +{ +#if defined PLATFORM_WINDOWS + + return GetPlatformErrorEx(GetLastError(), error, maxlength); + +#elif defined PLATFORM_POSIX + + return GetPlatformErrorEx(errno, error, maxlength); +#endif +} + +void LibrarySystem::GetPlatformErrorEx(int code, char* error, size_t maxlength) +{ + if (error && maxlength) + { +#if defined PLATFORM_WINDOWS + + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + (DWORD)code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)error, + maxlength, + nullptr) == 0) + { + UTIL_Format(error, maxlength, "error code %08x", code); + } + +#elif defined PLATFORM_LINUX + + const char *ae = strerror_r(code, error, maxlength); + + if (ae != error) + { + UTIL_Format(error, maxlength, "%s", ae); + } + +#elif defined PLATFORM_POSIX + + strerror_r(code, error, maxlength); +#endif + } +} + +void LibrarySystem::GetLoaderError(char* buffer, size_t maxlength) +{ +#if defined PLATFORM_WINDOWS + + GetPlatformError(buffer, maxlength); + +#elif defined PLATFORM_POSIX + + if (buffer && maxlength) + { + strncopy(buffer, dlerror(), maxlength); + } +#endif +} + +void LibrarySystem::CloseDirectory(CDirectory *dir) +{ + delete dir; +} + +size_t LibrarySystem::PathFormat(char* buffer, size_t len, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + size_t mylen = vsnprintf(buffer, len, fmt, ap); + va_end(ap); + + if (mylen >= len) + { + mylen = len - 1; + buffer[mylen] = '\0'; + } + + for (size_t i = 0; i < mylen; i++) + { + if (buffer[i] == PLATFORM_SEP_ALTCHAR) + { + buffer[i] = PLATFORM_SEP_CHAR; + } + } + + return mylen; +} + +char* LibrarySystem::PathFormat(const char* fmt, ...) +{ + static char buffer[PLATFORM_MAX_PATH]; + + va_list ap; + va_start(ap, fmt); + size_t mylen = vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + if (mylen >= sizeof(buffer)) + { + mylen = sizeof(buffer) - 1; + buffer[mylen] = '\0'; + } + + for (size_t i = 0; i < mylen; i++) + { + if (buffer[i] == PLATFORM_SEP_ALTCHAR) + { + buffer[i] = PLATFORM_SEP_CHAR; + } + } + + return buffer; +} + +const char* LibrarySystem::GetFileExtension(const char* filename) +{ + size_t len, end; + + len = strlen(filename); + + /* Minimum string length for filename with ext would be 3; example: a.a */ + if (len < 3) + { + return nullptr; + } + + end = len - 1; + + for (size_t i = end; i <= end; i--) + { + if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR) + { + break; + } + + if (filename[i] == '.' && i != end && i != 0) + { + return &filename[++i]; + } + } + + return nullptr; +} + +bool LibrarySystem::CreateFolder(const char* path) +{ +#if defined PLATFORM_WINDOWS + + return (mkdir(path) != -1); + +#elif defined PLATFORM_POSIX + + return (mkdir(path, 0775) != -1); +#endif +} + +size_t LibrarySystem::GetFileFromPath(char* buffer, size_t maxlength, const char* path) +{ + size_t length = strlen(path); + + for (size_t i = length - 1; i <= length - 1; i--) + { + if (path[i] == '/' +#if defined PLATFORM_WINDOWS + || path[i] == '\\' +#endif + ) + { + return UTIL_Format(buffer, maxlength, "%s", &path[i + 1]); + } + } + + /* We scanned and found no path separator */ + return UTIL_Format(buffer, maxlength, "%s", path); +} + +bool LibrarySystem::FileTime(const char* path, FileTimeType type, time_t* pTime) +{ + struct stat s; + + if (stat(path, &s) != 0) + { + return false; + } + + switch (type) + { + case FileTime_LastAccess: + { + *pTime = s.st_atime; + break; + } + case FileTime_Created: + { + *pTime = s.st_ctime; + break; + } + case FileTime_LastChange: + { + *pTime = s.st_mtime; + break; + } + default: + { + return false; + } + } + + return true; +} diff --git a/amxmodx/CLibrarySys.h b/amxmodx/CLibrarySys.h new file mode 100644 index 00000000..1ce8f37b --- /dev/null +++ b/amxmodx/CLibrarySys.h @@ -0,0 +1,175 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#ifndef _INCLUDE_LIBRARY_SYS_H_ +#define _INCLUDE_LIBRARY_SYS_H_ + +#include "amx.h" // cell +#include // Interface (HLSDK) +#include // AutoPtr + +#if defined(WIN32) +# ifndef PLATFORM_WINDOWS +# define PLATFORM_WINDOWS 1 +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +# define PLATFORM_LIB_EXT "dll" +# define PLATFORM_SEP_CHAR '\\' +# define PLATFORM_SEP_ALTCHAR '/' +# define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) +#elif defined(__linux__) || defined(__APPLE__) +# if defined(__linux__) +# define PLATFORM_LINUX 1 +# define PLATFORM_LIB_EXT "so" +# elif defined(__APPLE__) +# define PLATFORM_APPLE 1 +# define PLATFORM_LIB_EXT "dylib" +# endif +# ifndef PLATFORM_POSIX +# define PLATFORM_POSIX 1 +# endif +# include +# include +# include +# include +# include +# include +# include +# if defined(PLATFORM_APPLE) +# include +# endif +# define PLATFORM_SEP_CHAR '/' +# define PLATFORM_SEP_ALTCHAR '\\' +# define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) +# define WINAPI +#endif + +#define PLATFORM_MAX_PATH 260 + +#if defined PLATFORM_WINDOWS + typedef HMODULE LibraryHandle; +#elif defined PLATFORM_POSIX + typedef void* LibraryHandle; +#endif + +enum FileTimeType +{ + FileTime_LastAccess = 0, /* Last access (not available on FAT) */ + FileTime_Created = 1, /* Creation (not available on FAT) */ + FileTime_LastChange = 2, /* Last modification */ +}; + +class CDirectory +{ + public: + + CDirectory(const char* path); + ~CDirectory(); + + public: + + bool MoreFiles(); + void NextEntry(cell* offset = nullptr); + const char* GetEntryName(); + bool IsEntryDirectory(); + bool IsEntryFile(); + bool IsEntryValid(); + + public: + + bool IsValid(); + + private: + +#if defined PLATFORM_WINDOWS + + HANDLE m_dir; + WIN32_FIND_DATAA m_fd; + +#elif defined PLATFORM_POSIX + + DIR* m_dir; + struct dirent* m_ep; + char m_origpath[PLATFORM_MAX_PATH]; +#endif +}; + +class CLibrary +{ + public: + + CLibrary(LibraryHandle me); + ~CLibrary(); + + public: + + void CloseLibrary(); + void *GetSymbolAddress(const char* symname); + + private: + + LibraryHandle m_lib; +}; + +class LibrarySystem +{ + public: + + CLibrary* OpenLibrary(const char* path, char* error = nullptr, size_t maxlength = 0); + CDirectory* OpenDirectory(const char* path); + void CloseDirectory(CDirectory *dir); + + bool PathExists(const char* path); + bool IsPathFile(const char* path); + bool IsPathDirectory(const char* path); + + void GetPlatformError(char* error, size_t maxlength); + void GetPlatformErrorEx(int code, char* error, size_t maxlength); + + size_t PathFormat(char* buffer, size_t len, const char* fmt, ...); + char* PathFormat(const char* fmt, ...); + + const char* GetFileExtension(const char* filename); + bool CreateFolder(const char* path); + size_t GetFileFromPath(char* buffer, size_t maxlength, const char* path); + + bool FileTime(const char* path, FileTimeType type, time_t* pTime); + void GetLoaderError(char* buffer, size_t maxlength); +}; + +extern LibrarySystem g_LibSys; + +template +bool GET_IFACE(const char* library, T*& var, const char* version) +{ + const char* path = g_LibSys.PathFormat("%s.%s", library, PLATFORM_LIB_EXT); + + ke::AutoPtr lib(g_LibSys.OpenLibrary(path)); + + if (lib) + { + CreateInterfaceFn factory = reinterpret_cast(lib->GetSymbolAddress(CREATEINTERFACE_PROCNAME)); + + if (factory) + { + var = reinterpret_cast(factory(version, nullptr)); + return true; + } + } + + var = nullptr; + return false; +} + +#endif // _INCLUDE_LIBRARY_SYS_H_ diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 4b065c32..d0863898 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -43,30 +43,6 @@ ModuleCallReason g_ModuleCallReason; extern const char* no_function; // stupid work around -bool DirExists(const char *dir) -{ -#if defined WIN32 || defined _WIN32 - DWORD attr = GetFileAttributes(dir); - - if (attr == INVALID_FILE_ATTRIBUTES) - return false; - - if (attr & FILE_ATTRIBUTE_DIRECTORY) - return true; - -#else - struct stat s; - - if (stat(dir, &s) != 0) - return false; - - if (S_ISDIR(s.st_mode)) - return true; -#endif - - return false; -} - void report_error(int code, const char* fmt, ...) { va_list argptr; diff --git a/amxmodx/modules.h b/amxmodx/modules.h index 769ccdb7..ab72ea42 100755 --- a/amxmodx/modules.h +++ b/amxmodx/modules.h @@ -57,7 +57,6 @@ class Debugger; Debugger *DisableDebugHandler(AMX *amx); void EnableDebugHandler(AMX *amx, Debugger *pd); -bool DirExists(const char *dir); const char* GetFileName(AMX *amx); inline cell FloatToCell(float input)