From d69ddc723498aa7a7006bd85b9ad3805dc52495e Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:40:19 +0100 Subject: [PATCH 01/10] 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) From 553963295f71df94b38694c2972e3a59b81a23cc Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:43:30 +0100 Subject: [PATCH 02/10] VFS: Add Valve file system interface --- amxmodx/meta_api.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 41507cbb..9e4a60d4 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -8,13 +8,6 @@ // https://alliedmods.net/amxmodx-license #include - -#if defined WIN32 -#include -#else -#include -#endif - #include "amxmodx.h" #include "fakemeta.h" #include "CMenu.h" @@ -32,6 +25,8 @@ #include "CDataPack.h" #include "textparse.h" #include "CvarManager.h" +#include "CLibrarySys.h" +#include "CFileSystem.h" plugin_info_t Plugin_info = { @@ -143,6 +138,8 @@ int FF_InconsistentFile = -1; int FF_ClientAuthorized = -1; int FF_ChangeLevel = -1; +IFileSystem* g_FileSystem; + bool ColoredMenus(String & ModName) { const char * pModNames[] = { "cstrike", "czero", "dmc", "dod", "tfc", "valve" }; @@ -1493,7 +1490,9 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m FlagMan.SetFile("cmdaccess.ini"); g_CvarManager.CreateCvarHook(); - + + GET_IFACE("filesystem_stdio", g_FileSystem, FILESYSTEM_INTERFACE_VERSION); + return (TRUE); } From 4f4e322ad4ad590aa8f95db0e6ce040e2e6775f2 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:44:49 +0100 Subject: [PATCH 03/10] VFS: Add helpers to wrap default and valve system file --- amxmodx/CFileSystem.h | 256 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 amxmodx/CFileSystem.h diff --git a/amxmodx/CFileSystem.h b/amxmodx/CFileSystem.h new file mode 100644 index 00000000..a7c2cc8c --- /dev/null +++ b/amxmodx/CFileSystem.h @@ -0,0 +1,256 @@ +// 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_CFILESYSTEM_H_ +#define _INCLUDE_CFILESYSTEM_H_ + +#include // IFileSystem, FileSystemSeek_t, FileHandle_t (HLSDK) +#include // FILE* +#include // KE_OVERRIDE + +extern IFileSystem* g_FileSystem; + +class ValveFile; +class SystemFile; + +class FileObject +{ + public: + + virtual ~FileObject() {}; + + virtual size_t Read(void* pOut, size_t size) = 0; + virtual char* ReadLine(char* pOut, size_t size) = 0; + virtual size_t Write(const void* pData, size_t size) = 0; + + virtual bool Seek(int pos, int seek_type) = 0; + virtual int Tell() = 0; + virtual int Flush() = 0; + + virtual bool HasError() = 0; + + virtual bool EndOfFile() = 0; + virtual void Close() = 0; + + virtual ValveFile *AsValveFile() + { + return nullptr; + } + + virtual SystemFile *AsSystemFile() + { + return nullptr; + } +}; + +class ValveFile : public FileObject +{ + public: + + ValveFile(FileHandle_t handle) : handle_(handle) {} + + ~ValveFile() + { + Close(); + } + + static bool Exists(const char* file) + { + return g_FileSystem->FileExists(file); + } + + static ValveFile* Open(const char* filename, const char* mode, const char* pathID) + { + FileHandle_t handle = g_FileSystem->OpenFromCacheForRead(filename, mode, pathID); + + if (!handle) + { + return nullptr; + } + + return new ValveFile(handle); + } + + static bool Delete(const char* filename, const char* pathID) + { + if (!g_FileSystem->FileExists(filename)) + { + return false; + } + + g_FileSystem->RemoveFile(filename, pathID); + + if (g_FileSystem->FileExists(filename)) + { + return false; + } + + return true; + } + + size_t Read(void* pOut, size_t size) KE_OVERRIDE + { + return static_cast(g_FileSystem->Read(pOut, size, handle_)); + } + + char* ReadLine(char* pOut, size_t size) KE_OVERRIDE + { + return g_FileSystem->ReadLine(pOut, size, handle_); + } + + size_t Write(const void* pData, size_t size) KE_OVERRIDE + { + return static_cast(g_FileSystem->Write(pData, size, handle_)); + } + + bool Seek(int pos, int seek_type) KE_OVERRIDE + { + g_FileSystem->Seek(handle_, pos, static_cast(seek_type)); + return !HasError(); + } + + int Tell() KE_OVERRIDE + { + return g_FileSystem->Tell(handle_); + } + + bool HasError() KE_OVERRIDE + { + return !handle_ || !g_FileSystem->IsOk(handle_); + } + + int Flush() KE_OVERRIDE + { + g_FileSystem->Flush(handle_); + return 0; + } + + bool EndOfFile() KE_OVERRIDE + { + return g_FileSystem->EndOfFile(handle_); + } + + void Close() KE_OVERRIDE + { + if (handle_) + { + g_FileSystem->Close(handle_); + handle_ = nullptr;; + } + } + + virtual ValveFile* AsValveFile() + { + return this; + } + + FileHandle_t handle() const + { + return handle_; + } + + private: + + FileHandle_t handle_; +}; + + +class SystemFile : public FileObject +{ + public: + + SystemFile(FILE* fp) : fp_(fp) {} + + ~SystemFile() + { + Close(); + } + + static SystemFile* Open(const char* path, const char* mode) + { + FILE* fp = fopen(path, mode); + + if (!fp) + { + return nullptr; + } + + return new SystemFile(fp); + } + + static bool Delete(const char* path) + { + return unlink(path) == 0; + } + + size_t Read(void* pOut, size_t size) KE_OVERRIDE + { + return fread(pOut, 1, size, fp_); + } + + char* ReadLine(char* pOut, size_t size) KE_OVERRIDE + { + return fgets(pOut, size, fp_); + } + + size_t Write(const void* pData, size_t size) KE_OVERRIDE + { + return fwrite(pData, 1, size, fp_); + } + + bool Seek(int pos, int seek_type) KE_OVERRIDE + { + return fseek(fp_, pos, seek_type) == 0; + } + + int Tell() KE_OVERRIDE + { + return ftell(fp_); + } + + bool HasError() KE_OVERRIDE + { + return ferror(fp_) != 0; + } + + int Flush() KE_OVERRIDE + { + return fflush(fp_); + } + + bool EndOfFile() KE_OVERRIDE + { + return feof(fp_) != 0; + } + + void Close() KE_OVERRIDE + { + if (fp_) + { + fclose(fp_); + fp_ = nullptr; + } + } + + virtual SystemFile* AsSystemFile() + { + return this; + } + + FILE* handle() const + { + return fp_; + } + + private: + + FILE* fp_; +}; + +#endif // _INCLUDE_CFILESYSTEM_H_ From 6434c4db770e50840f59832c0f027fbe37e9d7e5 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:45:27 +0100 Subject: [PATCH 04/10] VFS: Update AMbuild and VS project files --- amxmodx/AMBuilder | 1 + amxmodx/msvc12/amxmodx_mm.vcxproj | 3 +++ amxmodx/msvc12/amxmodx_mm.vcxproj.filters | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/amxmodx/AMBuilder b/amxmodx/AMBuilder index aa5f4127..6f1bd3b0 100644 --- a/amxmodx/AMBuilder +++ b/amxmodx/AMBuilder @@ -93,6 +93,7 @@ binary.sources = [ 'cvars.cpp', '../public/memtools/CDetour/detours.cpp', '../public/memtools/CDetour/asm/asm.c', + 'CLibrarySys.cpp', ] if builder.target_platform == 'windows': diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj b/amxmodx/msvc12/amxmodx_mm.vcxproj index 3378a72a..4cdb7d2d 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj @@ -256,6 +256,7 @@ + @@ -334,9 +335,11 @@ + + diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters index 7c34bc41..7270a8b4 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters @@ -277,6 +277,9 @@ Third Party\Hashing\hashers + Source Files + + Source Files @@ -475,6 +478,12 @@ Third Party\Hashing\hashers + + + Header Files + + + Header Files From 0eeb5942a170cee6a1991451f2bc8b87dd43a7ab Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 8 Mar 2015 23:46:33 +0100 Subject: [PATCH 05/10] VFS: Reflect changes in natives and documentation --- amxmodx/CLang.cpp | 2 + amxmodx/amxmodx.cpp | 14 - amxmodx/file.cpp | 1464 ++++++++++++++++++++++---------------- plugins/include/file.inc | 657 +++++++++++++---- 4 files changed, 1376 insertions(+), 761 deletions(-) diff --git a/amxmodx/CLang.cpp b/amxmodx/CLang.cpp index e01cf76c..31da9576 100755 --- a/amxmodx/CLang.cpp +++ b/amxmodx/CLang.cpp @@ -12,6 +12,8 @@ #include "CLang.h" #include "format.h" +CVector FileList; + #define LITIDX_NONE 0 #define LITIDX_BRACKET 1 #define LITIDX_DEFINITION 2 diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index c50595ca..321a991f 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -3784,19 +3784,6 @@ cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params) return 1; } -static cell AMX_NATIVE_CALL amx_mkdir(AMX *amx, cell *params) -{ - int len = 0; - char *path = get_amxstring(amx, params[1], 0, len); - char *realpath = build_pathname("%s", path); - -#if defined(__linux__) || defined(__APPLE__) - return mkdir(realpath, 0700); -#else - return mkdir(realpath); -#endif -} - static cell AMX_NATIVE_CALL find_plugin_byfile(AMX *amx, cell *params) { typedef int (*STRCOMPARE)(const char*, const char*); @@ -4561,7 +4548,6 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"hash_string", amx_hash_string}, {"hash_file", amx_hash_file}, {"module_exists", module_exists}, - {"mkdir", amx_mkdir}, {"next_hudchannel", next_hudchannel}, {"num_to_word", num_to_word}, {"parse_loguser", parse_loguser}, diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index 39ba4ab4..1341851b 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -7,484 +7,503 @@ // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license -// intptr_t -#ifdef _MSC_VER - typedef int intptr_t; - #define _INTPTR_T_DEFINED -#endif - -#ifdef __GNUC__ -#include -#include -#include -#include -#endif - -// header file for unlink() -#if defined(__linux__) || defined(__APPLE__) -#include -#else -#define WINDOWS_LEAN_AND_MEAN -#include -#include -#endif - #include "amxmodx.h" +#include "CFileSystem.h" +#include "CLibrarySys.h" -CVector FileList; - -class AutoFilePtr -{ - FILE *m_FP; -public: - AutoFilePtr(FILE *fp) : m_FP(fp) - {} - - ~AutoFilePtr() - { - if (m_FP) - fclose(m_FP); - } - - operator FILE* () - { - return m_FP; - } -}; - -enum FileTimeType -{ - FileTime_LastAccess = 0, /* Last access (not available on FAT) */ - FileTime_Created = 1, /* Creation (not available on FAT) */ - FileTime_LastChange = 2, /* Last modification */ -}; +using namespace ke; +// native read_dir(const dirname[], pos, output[], len, &outlen = 0); static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params) { -#ifdef __GNUC__ - int a; - struct dirent *ep; - DIR *dp; - char* dirname = build_pathname("%s", get_amxstring(amx, params[1], 0, a)); - a = params[2]; - - if ((dp = opendir (dirname)) == NULL) - return 0; - - seekdir(dp, a); - - if ((ep = readdir (dp)) != NULL) + int length; + const char* path = get_amxstring(amx, params[1], 0, length); + const char* realpath = build_pathname("%s", path); + + AutoPtr dir(g_LibSys.OpenDirectory(realpath)); + + if (!dir) { - cell *length = get_amxaddr(amx, params[5]); - *length = set_amxstring(amx, params[3], ep->d_name, params[4]); - a = telldir(dp); - } else - a = 0; - - closedir (dp); - - return a; - -#else - int tmp; - char *dirname = build_pathname("%s/*", get_amxstring(amx, params[1], 0, tmp)); - tmp = params[2]; - - _finddata_t fd; - intptr_t handle = _findfirst(dirname, &fd); - - if (handle < 0) return 0; - - ++tmp; - - for (int i = 0; i < tmp; ++i) - { - if (_findnext(handle, &fd) < 0) - { - tmp = 0; - break; - } } - - // current data in fd - cell *length = get_amxaddr(amx, params[5]); // pointer to the outLen parameter - *length = set_amxstring(amx, params[3], fd.name, params[4]); // set output and outLen parameters - _findclose(handle); - return tmp; -#endif // __GNUC__ + cell offset = Max(0, params[2]); + + dir->NextEntry(&offset); + + if (!dir->IsValid()) + { + return 0; + } + + const char* entry = dir->GetEntryName(); + + size_t entrylen = set_amxstring_utf8(amx, params[3], entry, strlen(entry), params[4] + 1); + *get_amxaddr(amx, params[5]) = entrylen; + + return offset; } -static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params) /* 5 param */ +// native read_file(const file[], line, text[], len, &txtlen = 0); +static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params) { - int iLen; - char* szFile = get_amxstring(amx, params[1], 0, iLen); - FILE *fp; - - if ((fp =fopen(build_pathname("%s", szFile), "r")) == NULL) + int length; + const char* path = get_amxstring(amx, params[1], 0, length); + const char* realpath = build_pathname("%s", path); + + AutoPtr fp(SystemFile::Open(realpath, "r")); + + if (!fp) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't read file \"%s\"", szFile); + LogError(amx, AMX_ERR_NATIVE, "Couldn't read file \"%s\"", path); return 0; } - char buffor[1024]; - int i = 0, iLine = params[2]; - - while ((i <= iLine) && fgets(buffor, 1023, fp)) - i++; - - fclose(fp); + static char buffer[2048]; - if (i > iLine) + size_t currentLine = 0; + size_t targetLine = Max(0, params[2]); + + while (currentLine <= targetLine && fp->ReadLine(buffer, sizeof(buffer) - 1)) { - int len = strlen(buffor); - - if (buffor[len - 1] == '\n') - buffor[--len] = 0; - - if (buffor[len - 1] == '\r') - buffor[--len] = 0; - - cell *length = get_amxaddr(amx, params[5]); - *length = set_amxstring_utf8(amx, params[3], buffor, len, params[4] + 1); // + EOS - - return i; + ++currentLine; } - + + if (currentLine > targetLine) + { + length = strlen(buffer); + + if (buffer[length - 1] == '\n') + buffer[--length] = '\0'; + + if (buffer[length - 1] == '\r') + buffer[--length] = '\0'; + + length = set_amxstring_utf8(amx, params[3], buffer, length, params[4] + 1); // + EOS + *get_amxaddr(amx, params[5]) = length; + + return currentLine; + } + return 0; } -static cell AMX_NATIVE_CALL write_file(AMX *amx, cell *params) /* 3 param */ +// native write_file(const file[], const text[], line = -1); +static cell AMX_NATIVE_CALL write_file(AMX *amx, cell *params) { - int i; - char* sFile = build_pathname("%s", get_amxstring(amx, params[1], 0, i)); - char* sText = get_amxstring(amx, params[2], 0, i); - FILE* pFile; - int iLine = params[3]; + int length; + const char* path = get_amxstring(amx, params[1], 0, length); + const char* text = get_amxstring(amx, params[2], 1, length); + int targetLine = params[3]; - // apending to the end - if (iLine < 0) + const char* realpath = build_pathname("%s", path); + + AutoPtrfp; + + if (targetLine < 0) { - if ((pFile = fopen(sFile, "a")) == NULL) + if (!(fp = SystemFile::Open(realpath, "a"))) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); + LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath); return 0; } - - fputs(sText, pFile); - fputc('\n', pFile); - fclose(pFile); - + + fp->Write(text, length); + fp->Write("\n", 1); + return 1; } - // creating a new file with a line in a middle - if ((pFile = fopen(sFile, "r")) == NULL) + if (!(fp = SystemFile::Open(realpath, "r"))) { - if ((pFile = fopen(sFile, "w")) == NULL) + if (!(fp = SystemFile::Open(realpath, "w"))) { - LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); + LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath); return 0; } - - for (i = 0; i < iLine; ++i) - fputc('\n', pFile); - fputs(sText, pFile); - fputc('\n', pFile); - fclose(pFile); - + for (int i = 0; i < targetLine; ++i) + { + fp->Write("\n", 1); + } + + fp->Write(text, length); + fp->Write("\n", 1); + return 1; } - // adding a new line in a middle of already existing file - FILE* pTemp; - char buffor[2048]; + SystemFile fptemp(tmpfile()); - if ((pTemp = tmpfile()) == NULL) + if (!fptemp.handle()) { LogError(amx, AMX_ERR_NATIVE, "Couldn't create temp file"); return 0; } - for (i = 0; ; ++i) + static char buffer[2048]; + + for (int i = 0;; ++i) { - if (i == iLine) + if (i == targetLine) { - fgets(buffor, 2047, pFile); - fputs(sText, pTemp); - fputc('\n', pTemp); + fp->ReadLine(buffer, sizeof(buffer) - 1); + + fptemp.Write(text, length); + fptemp.Write("\n", 1); } - else if (fgets(buffor, 2047, pFile)) + else if (fp->ReadLine(buffer, sizeof(buffer) - 1)) { - fputs(buffor, pTemp); + fptemp.Write(buffer, strlen(buffer)); } - else if (i < iLine) + else if (i < targetLine) { - fputc('\n', pTemp); + fptemp.Write("\n", 1); } else + { break; - } - - fclose(pFile); - rewind(pTemp); - - // now rewrite because file can be now smaller... - if ((pFile = fopen(sFile, "w")) == NULL) - { - LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); - return 0; - } - - while (fgets(buffor, 2047, pTemp)) - fputs(buffor, pFile); - - fclose(pTemp); - fclose(pFile); - - return 1; -} - -static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params) /* 1 param */ -{ - int iLen; - char* sFile = get_amxstring(amx, params[1], 0, iLen); - - return (unlink(build_pathname("%s", sFile)) ? 0 : 1); -} - -static cell AMX_NATIVE_CALL file_exists(AMX *amx, cell *params) /* 1 param */ -{ - int iLen; - char *sFile = get_amxstring(amx, params[1], 0, iLen); - char *file = build_pathname("%s", sFile); - -#if defined WIN32 || defined _WIN32 - DWORD attr = GetFileAttributes(file); - - if (attr == INVALID_FILE_ATTRIBUTES) - return 0; - - if (attr == FILE_ATTRIBUTE_DIRECTORY) - return 0; - - return 1; -#else - struct stat s; - - if (stat(file, &s) != 0) - return 0; - - if (S_ISDIR(s.st_mode)) - return 0; - - return 1; -#endif -} - -static cell AMX_NATIVE_CALL dir_exists(AMX *amx, cell *params) /* 1 param */ -{ - int iLen; - char *sFile = get_amxstring(amx, params[1], 0, iLen); - char *file = build_pathname("%s", sFile); - - return DirExists(file) ? 1 : 0; -} - -static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) /* 1 param */ -{ - int iLen; - char* sFile = get_amxstring(amx, params[1], 0, iLen); - AutoFilePtr fp(fopen(build_pathname("%s", sFile), "r")); - - if (fp != NULL) - { - if (params[0] < 2 || params[2] == 0) - { - fseek(fp, 0, SEEK_END); - int size = ftell(fp); - - return size; } - else if (params[2] == 1) + } + + rewind(fptemp.handle()); + + if (!(fp = AutoPtr(SystemFile::Open(realpath, "w")))) + { + LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath); + return 0; + } + + while (fptemp.ReadLine(buffer, sizeof(buffer) - 1)) + { + fp->Write(buffer, strlen(buffer)); + } + + return 1; +} + +// native delete_file(const file[], bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG"); +static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params) +{ + int length; + const char* file = get_amxstring(amx, params[1], 0, length); + + if (*params / sizeof(cell) >= 2 && params[2] > 0) + { + const char* pathID = get_amxstring(amx, params[3], 1, length); + + if (!strcmp(pathID, "ALL")) { - int a = 0,lines = 0; - - while (a != EOF) + pathID = nullptr; + } + + return ValveFile::Delete(file, pathID); + } + + return SystemFile::Delete(build_pathname("%s", file)); +} + +// native file_exists(const file[], bool:use_valve_fs = false); +static cell AMX_NATIVE_CALL file_exists(AMX *amx, cell *params) +{ + int length; + const char* file = get_amxstring(amx, params[1], 0, length); + + if (*params / sizeof(cell) >= 2 && params[2] > 0) + { + return g_FileSystem->FileExists(file); + } + + return g_LibSys.IsPathFile(build_pathname("%s", file)); +} + +// native dir_exists(const dir[], bool:use_valve_fs = false); +static cell AMX_NATIVE_CALL dir_exists(AMX *amx, cell *params) +{ + int length; + const char *path = get_amxstring(amx, params[1], 0, length); + + if (*params / sizeof(cell) >= 2 && params[2] > 0) + { + return g_FileSystem->IsDirectory(path); + } + + return g_LibSys.IsPathDirectory(build_pathname("%s", path)); +} + +#define FSOPT_BYTES_COUNT 0 +#define FSOPT_LINES_COUNT 1 +#define FSOPT_END_WITH_LF 2 + +// native file_size(const file[], flag = 0, bool:use_valve_fs = false, const valve_path_id[] = "GAME"); +static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) +{ + int length; + const char* path = get_amxstring(amx, params[1], 0, length); + int flag = params[2]; + + AutoPtr fp; + + size_t numParams = *params / sizeof(cell); + + if (numParams >= 3 && params[3] > 0) + { + const char* pathID = get_amxstring(amx, params[4], 1, length); + + if (!strcmp(pathID, "ALL")) + { + pathID = nullptr; + } + + fp = ValveFile::Open(path, "r", pathID); + } + else + { + fp = SystemFile::Open(build_pathname("%s", path), "r"); + } + + if (!fp) + { + return -1; + } + + switch (flag) + { + default: + case FSOPT_BYTES_COUNT: + { + fp->Seek(0, SEEK_END); + + return fp->Tell(); + } + case FSOPT_LINES_COUNT: + { + int8_t ch = 0; + size_t lines = 0; + + while (!fp->EndOfFile() && !fp->HasError()) { ++lines; - while ((a = fgetc(fp)) != '\n' && a != EOF); + while (fp->Read(&ch, 1) == 1 && ch != '\n' && ch != EOF); } - //int a, b = '\n'; - //while( (a = fgetc(fp)) != EOF ){ - // if ( a == '\n') - // ++lines; - // b = a; - //} - //if ( b != '\n' ) - // ++lines; + return lines; } - else if (params[2] == 2) + case FSOPT_END_WITH_LF: { - fseek(fp, -1, SEEK_END); - - if (fgetc(fp) == '\n') - return 1; - - return 0; + int8_t ch = 0; + + fp->Seek(-1, SEEK_END); + fp->Read(&ch, 1); + + return ch == '\n'; } } - + return -1; } +// native fopen(const filename[], const mode[], bool:use_valve_fs = false, const valve_path_id[] = "GAME"); static cell AMX_NATIVE_CALL amx_fopen(AMX *amx, cell *params) { - int len; - char *file = build_pathname("%s", get_amxstring(amx, params[1], 1, len)); - char *flags = get_amxstring(amx, params[2], 0, len); + int length; + const char* file = get_amxstring(amx, params[1], 0, length); + const char* flags = get_amxstring(amx, params[2], 1, length); - FILE *fp = fopen(file, flags); + FileObject* fp = nullptr; - return (cell)fp; + if (*params / sizeof(cell) >= 3 && params[3] > 0) + { + const char* pathID = get_amxstring(amx, params[4], 2, length); + + if (!strcmp(pathID, "ALL")) + { + pathID = nullptr; + } + + fp = ValveFile::Open(file, flags, pathID); + } + else + { + fp = SystemFile::Open(build_pathname("%s", file), flags); + } + + if (!fp) + { + return 0; + } + + return reinterpret_cast(fp); } +#define BLOCK_INT 4 +#define BLOCK_SHORT 2 +#define BLOCK_CHAR 1 + +// native fwrite_blocks(file, const data[], blocks, mode); static cell AMX_NATIVE_CALL amx_fwrite_blocks(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) - return 0; - - cell *addr = get_amxaddr(amx, params[2]); - size_t blocks = params[3]; - size_t btmp = blocks; - cell mode = params[4]; - switch (mode) { - case 1: + return 0; + } + + cell* data = get_amxaddr(amx, params[2]); + cell blocks = params[3]; + cell size = params[4]; + + size_t read = 0; + + switch (size) + { + case BLOCK_CHAR: { - char *a = new char[blocks]; - char *ptr = a; - while (btmp--) - *ptr++ = static_cast(*addr++); - size_t res = fwrite(a, sizeof(char), blocks, fp); - delete [] a; - return res; + for (cell i = 0; i < blocks; ++i) + { + char value = data[i]; + + if (fp->Write(&value, sizeof(value)) != sizeof(value)) + { + break; + } + + read += sizeof(value); + } + break; } - case 2: + case BLOCK_SHORT: { - short *a = new short[blocks]; - short *ptr = a; - while (btmp--) - *ptr++ = static_cast(*addr++); - size_t res = fwrite(a, sizeof(short), blocks, fp); - delete [] a; - return res; + for (cell i = 0; i < blocks; ++i) + { + short value = data[i]; + + if (fp->Write(&value, sizeof(value)) != sizeof(value)) + { + break; + } + + read += sizeof(value); + } + break; } - case 4: + default: { - int *a = new int[blocks]; - int *ptr = a; - while (btmp--) - *ptr++ = static_cast(*addr++); - size_t res = fwrite(a, sizeof(int), blocks, fp); - delete [] a; - return res; + if (size != BLOCK_INT) + { + size = BLOCK_INT; + } + } + case BLOCK_INT: + { + read = fp->Write(data, sizeof(cell) * blocks); } } - return 0; + return read / size; } +// native fwrite(file, data, mode); static cell AMX_NATIVE_CALL amx_fwrite(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) - return 0; - - size_t mode = params[3]; - switch (mode) { - case 1: + return 0; + } + + cell data = params[2]; + size_t size = params[3]; + + switch (size) + { + case BLOCK_CHAR: { - char a = static_cast(params[2]); - return fwrite(&a, sizeof(char), 1, fp); + char value = static_cast(data); + return fp->Write(&value, sizeof(value)); } - case 2: + case BLOCK_SHORT: { - short b = static_cast(params[2]); - return fwrite(&b, sizeof(short), 1, fp); + short value = static_cast(data); + return fp->Write(&value, sizeof(value)); } - case 4: + default: + case BLOCK_INT: { - int c = static_cast(params[2]); - return fwrite(&c, sizeof(int), 1, fp); + int value = static_cast(data); + return fp->Write(&value, sizeof(value)); } } return 0; } +// native fwrite_raw(file, const stream[], blocksize, mode); static cell AMX_NATIVE_CALL amx_fwrite_raw(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } - cell *addr = get_amxaddr(amx, params[2]); - return fwrite(addr, params[3], params[4], fp); + cell* data = get_amxaddr(amx, params[2]); + + return fp->Write(&data, params[3] * params[4]); } +// native fread_raw(file, stream[], blocksize, blocks); static cell AMX_NATIVE_CALL amx_fread_raw(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } - cell *addr = get_amxaddr(amx, params[2]); - size_t size = static_cast(params[3]); - size_t blocks = static_cast(params[4]); - - return fread(addr, size, blocks, fp); + cell* data = get_amxaddr(amx, params[2]); + + return fp->Read(data, params[3] * params[4]); } +// native fread(file, &data, mode); static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } + + cell *data = get_amxaddr(amx, params[2]); - cell *addr = get_amxaddr(amx, params[2]); switch (params[3]) { - case 1: //char + case BLOCK_CHAR: { - char a; - size_t res = fread(&a, sizeof(char), 1, fp); - *addr = static_cast(a); + char value; + size_t res = fp->Read(&value, sizeof(value)); + *data = static_cast(value); return res; } - case 2: //short + case BLOCK_SHORT: { - short a; - size_t res = fread(&a, sizeof(short), 1, fp); - *addr = static_cast(a); + short value; + size_t res = fp->Read(&value, sizeof(value)); + *data = static_cast(value); return res; } - case 4: //int - default: + case BLOCK_INT: + default: { - int a; - size_t res = fread(&a, sizeof(int), 1, fp); - *addr = static_cast(a); + int value; + size_t res = fp->Read(&value, sizeof(value)); + *data = static_cast(value); return res; } } @@ -492,333 +511,545 @@ static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) return 0; } +// native fread_blocks(file, data[], blocks, mode); static cell AMX_NATIVE_CALL amx_fread_blocks(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) - return 0; - - cell *addr = get_amxaddr(amx, params[2]); - size_t blocks = params[3]; - switch (params[4]) { - case 1: //char + return 0; + } + + cell *data = get_amxaddr(amx, params[2]); + cell blocks = params[3]; + cell size = params[4]; + + size_t read = 0; + + switch (size) + { + case BLOCK_CHAR: { - char *a = new char[blocks]; - char *ptr = a; - size_t res = fread(a, sizeof(char), blocks, fp); - while (blocks--) - *addr++ = static_cast(*ptr++); - delete [] a; - return res; + for (cell i = 0; i < blocks; ++i) + { + char value; + + if (fp->Read(&value, sizeof(value)) != sizeof(value)) + { + break; + } + + read += sizeof(value); + *data++ = value; + } + break; } - case 2: //short + case BLOCK_SHORT: { - short *a = new short[blocks]; - short *ptr = a; - size_t res = fread(a, sizeof(short), blocks, fp); - while (blocks--) - *addr++ = static_cast(*ptr++); - delete [] a; - return res; + for (cell i = 0; i < blocks; ++i) + { + short value; + + if (fp->Read(&value, sizeof(value)) != sizeof(value)) + { + break; + } + + read += sizeof(value); + *data++ = value; + } + break; } - case 4: //int - default: + default: { - int *a = new int[blocks]; - int *ptr = a; - size_t res = fread(a, sizeof(int), blocks, fp); - while (blocks--) - *addr++ = static_cast(*ptr++); - delete [] a; - return res; + if (size != BLOCK_INT) + { + size = BLOCK_INT; + } } + case BLOCK_INT: + { + read = fp->Read(data, sizeof(cell) * blocks); + break; + } + } + + return read / size; +} + +// native fputs(file, const text[], bool:null_term = false); +static cell AMX_NATIVE_CALL amx_fputs(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + int length; + char *string = get_amxstring(amx, params[2], 0, length); + + if (*params / sizeof(cell) >= 3 && params[3] > 0) + { + ++length; + } + + if (fp->Write(string, length) != length) + { + return -1; } return 0; } -static cell AMX_NATIVE_CALL amx_fputs(AMX *amx, cell *params) -{ - FILE *fp = (FILE *)params[1]; - - if (!fp) - return 0; - - int len; - char *str = get_amxstring(amx, params[2], 0, len); - return fputs(str, fp); -} - +// native fgets(file, buffer[], maxlength); static cell AMX_NATIVE_CALL amx_fgets(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } static char buffer[4096]; buffer[0] = '\0'; - fgets(buffer, sizeof(buffer)-1, fp); + + if (!fp->ReadLine(buffer, sizeof(buffer) - 1)) + { + return 0; + } + return set_amxstring_utf8(amx, params[2], buffer, strlen(buffer), params[3] + 1); // + EOS } +// native fseek(file, position, start); static cell AMX_NATIVE_CALL amx_fseek(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } - return fseek(fp, params[2], params[3]); + return !fp->Seek(params[2], params[3]); } +// native ftell(file); static cell AMX_NATIVE_CALL amx_ftell(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } - return ftell(fp); + return fp->Tell(); } +// native fprintf(file, const fmt[], any:...); static cell AMX_NATIVE_CALL amx_fprintf(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); if (!fp) + { return 0; + } - int len; - char *str = format_amxstring(amx, params, 2, len); - return fprintf(fp, "%s", str); + int length; + const char* string = format_amxstring(amx, params, 2, length); + + if (ValveFile *vfile = fp->AsValveFile()) + { + return g_FileSystem->FPrintf(vfile->handle(), const_cast("%s"), string); + } + else if (SystemFile *sysfile = fp->AsSystemFile()) + { + return fprintf(sysfile->handle(), "%s", string); + } + else + { + assert(false); + } + + return 0; } +// native feof(file); static cell AMX_NATIVE_CALL amx_feof(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); - if (!fp) - return 1; - - return feof(fp); -} - -static cell AMX_NATIVE_CALL amx_fclose(AMX *amx, cell *params) -{ - FILE *fp = (FILE *)params[1]; - - if (!fp) - return 1; - - fclose(fp); + if (fp) + { + return fp->EndOfFile(); + } return 1; } -static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params) +// native fclose(file); +static cell AMX_NATIVE_CALL amx_fclose(AMX *amx, cell *params) { - int len; - char *file = build_pathname("%s", format_amxstring(amx, params, 1, len)); - long size; - - AutoFilePtr fp(fopen(file, "rb")); - + FileObject* fp = reinterpret_cast(params[1]); + if (fp) { - fseek(fp, 0, SEEK_END); - size = ftell(fp); - - return size; + fp->Close(); } - + + return 1; +} + +// native filesize(const filename[], any:...); +static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params) +{ + int length; + const char *realpath = build_pathname("%s", format_amxstring(amx, params, 1, length)); + + AutoPtr fp(SystemFile::Open(realpath, "rb")); + + if (fp) + { + fp->Seek(0, SEEK_END); + + return fp->Tell(); + } + return -1; } +// Undocumented. static cell AMX_NATIVE_CALL amx_build_pathname(AMX *amx, cell *params) { - int len; - char *szPath = get_amxstring(amx, params[1], 0, len); - - return set_amxstring(amx, params[2], build_pathname("%s", szPath), params[3]); + int length; + const char* path = get_amxstring(amx, params[1], 0, length); + + return set_amxstring(amx, params[2], build_pathname("%s", path), params[3]); } +enum FileType +{ + FileType_Unknown, /* Unknown file type (device/socket) */ + FileType_Directory, /* File is a directory */ + FileType_File, /* File is a file */ +}; + +struct DirectoryHandle +{ + DirectoryHandle(void* handle_, bool valvefs_) : handle(handle_), valvefs(valvefs_) {} + + void* handle; + bool valvefs; +}; + +// native open_dir(dir[], firstfile[], length, &FileType:type = FileType_Unknown, bool:use_valve_fs=false, const valve_path_id[] = "GAME"); static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) { - int len; - char *path = get_amxstring(amx, params[1], 0, len); + int length; + const char* path = get_amxstring(amx, params[1], 0, length); -#if defined WIN32 || defined _WIN32 - char *dirname = build_pathname("%s\\*", path); - - WIN32_FIND_DATA fd; - HANDLE hFile = FindFirstFile(dirname, &fd); - - if (hFile == INVALID_HANDLE_VALUE) - return 0; - - set_amxstring(amx, params[2], fd.cFileName, params[3]); - - return (DWORD)hFile; -#else - char *dirname = build_pathname("%s", path); - DIR *dp = opendir(dirname); - - if (!dp) - return 0; - struct dirent *ep = readdir(dp); - - if (!ep) + if (!*path) { - closedir(dp); return 0; } - - set_amxstring(amx, params[2], ep->d_name, params[3]); - - return (cell)dp; -#endif + + size_t numParams = *params / sizeof(cell); + + if (*params / sizeof(cell) >= 4 && params[5] > 0) + { + const char* wildcardedPath = g_LibSys.PathFormat("%s%s*", path, (path[length - 1] != '/' && path[length - 1] != '\\') ? "/" : ""); + const char* pathID = get_amxstring(amx, params[6], 1, length); + + if (!strcmp(pathID, "ALL")) + { + pathID = nullptr; + } + + static FileFindHandle_t handle; + const char* pFirst = g_FileSystem->FindFirst(wildcardedPath, &handle, pathID); + + if (!pFirst) + { + return 0; + } + + set_amxstring_utf8(amx, params[2], pFirst, strlen(pFirst), params[3] + 1); + + *get_amxaddr(amx, params[4]) = g_FileSystem->FindIsDirectory(handle) ? FileType_Directory : FileType_File; + + return reinterpret_cast(new DirectoryHandle(reinterpret_cast(&handle), true)); + } + + CDirectory* dir = g_LibSys.OpenDirectory(build_pathname("%s", path)); + + if (!dir) + { + return 0; + } + + if (numParams >= 4) + { + *get_amxaddr(amx, params[4]) = dir->IsEntryDirectory() ? FileType_Directory : FileType_File; + } + + const char* entry = dir->GetEntryName(); + set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1); + + return reinterpret_cast(new DirectoryHandle(reinterpret_cast(dir), false)); } +// native close_dir(dirh); static cell AMX_NATIVE_CALL amx_close_dir(AMX *amx, cell *params) { -#if defined WIN32 || defined _WIN32 - HANDLE hFile = (HANDLE)((DWORD)params[1]); - - if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) - return 0; - - FindClose(hFile); - - return 1; -#else - DIR *dp = (DIR *)params[1]; - - if (!dp) - return 0; - - closedir(dp); - return 1; -#endif -} + AutoPtr p(reinterpret_cast(params[1])); -static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params) -{ -#if defined WIN32 || defined _WIN32 - HANDLE hFile = (HANDLE)((DWORD)params[1]); - - if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) - return 0; - - WIN32_FIND_DATA fd; - - if (!FindNextFile(hFile, &fd)) - return 0; - - set_amxstring(amx, params[2], fd.cFileName, params[3]); - - return 1; -#else - DIR *dp = (DIR *)params[1]; - - if (!dp) - return 0; - struct dirent *ep = readdir(dp); - - if (!ep) - return 0; - - set_amxstring(amx, params[2], ep->d_name, params[3]); - - return 1; -#endif -} - -//native fgetc( file ); -static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params) -{ - FILE *fp = (FILE *)params[1]; - - if (!fp) - return 0; - - return fgetc(fp); -} - -//native fputc( file, data ); -static cell AMX_NATIVE_CALL amx_fputc(AMX *amx, cell *params) -{ - FILE *fp = (FILE *)params[1]; - - if (!fp) - return 0; - - return fputc(static_cast(params[2]), fp); -} - -//native ungetc( file, data ); -static cell AMX_NATIVE_CALL amx_ungetc(AMX *amx, cell *params) -{ - FILE *fp = (FILE *)params[1]; - - if (!fp) - return 0; - - return ungetc(static_cast(params[2]), fp); -} - -#if defined(__linux__) || defined(__APPLE__) -#define _rmdir rmdir -#endif - -static cell AMX_NATIVE_CALL amx_rmdir(AMX *amx, cell *params) -{ - int len; - char* sFile = build_pathname("%s", get_amxstring(amx, params[1], 0, len)); - - if (_rmdir(sFile) != 0) - return 0; - - return 1; -} - -static cell AMX_NATIVE_CALL amx_rename(AMX *amx, cell *params) -{ - int len; - char f_old_r[260]; - char f_new_r[260]; - - char *fold = get_amxstring(amx, params[1], 0, len); - char *fnew = get_amxstring(amx, params[2], 1, len); - - if (params[0] / sizeof(cell) == 3 && params[3]) + if (!p) { - build_pathname_r(f_old_r, sizeof(f_old_r)-1, "%s", fold); - build_pathname_r(f_new_r, sizeof(f_new_r)-1, "%s", fnew); - } else { - UTIL_Format(f_old_r, sizeof(f_old_r)-1, "%s", fold); - UTIL_Format(f_new_r, sizeof(f_new_r)-1, "%s", fnew); + return 0; } -#if defined(__linux__) || defined(__APPLE__) - return (rename(f_old_r, f_new_r) == 0); -#elif defined WIN32 - return MoveFileA(f_old_r, f_new_r); + if (p->valvefs) + { + FileFindHandle_t* handle = reinterpret_cast(p->handle); + g_FileSystem->FindClose(*handle); + } + else + { + CDirectory* handle = reinterpret_cast(p->handle); + g_LibSys.CloseDirectory(handle); + } + + return 1; +} + +// native next_file(dirh, buffer[], length, &FileType:type = FileType_Unknown); +static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params) +{ + DirectoryHandle* p = reinterpret_cast(params[1]); + + if (!p) + { + return 0; + } + + size_t numParams = *params / sizeof(cell); + + if (p->valvefs) + { + FileFindHandle_t* handle = reinterpret_cast(p->handle); + + if (!handle) + { + return 0; + } + + const char* entry = g_FileSystem->FindNext(*handle); + + if (!entry) + { + return 0; + } + + if (numParams >= 4) + { + *get_amxaddr(amx, params[4]) = g_FileSystem->FindIsDirectory(*handle) ? FileType_Directory : FileType_File; + } + + set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1); + } + else + { + CDirectory* handle = reinterpret_cast(p->handle); + + if (!handle) + { + return 0; + } + + handle->NextEntry(); + + if (!handle->MoreFiles()) + { + return 0; + } + + if (numParams >= 4) + { + *get_amxaddr(amx, params[4]) = handle->IsEntryDirectory() ? FileType_Directory : FileType_File; + } + + const char* entry = handle->GetEntryName(); + + set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1); + } + + return 1; +} + +//native fgetc(file); +static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + uint8_t val; + + if (fp->Read(&val, sizeof(val)) != sizeof(val)) + { + return -1; + } + + return static_cast(val); +} + +//native fputc(file, data); +static cell AMX_NATIVE_CALL amx_fputc(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + uint8_t val = static_cast(params[2]); + + if (fp->Write(&val, sizeof(val)) != sizeof(val)) + { + return -1; + } + + return val; +} + +//native ungetc(file, data); +static cell AMX_NATIVE_CALL amx_ungetc(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + SystemFile* sysfile = fp->AsSystemFile(); + + if (!sysfile) + { + LogError(amx, AMX_ERR_NATIVE, "Can not ungetc to file in the Valve file system"); + return 0; + } + + return ungetc(static_cast(params[2]), sysfile->handle()); +} + +// native rmdir(const path[]); +static cell AMX_NATIVE_CALL amx_rmdir(AMX *amx, cell *params) +{ + int length; + const char* realpath = build_pathname("%s", get_amxstring(amx, params[1], 0, length)); + + return rmdir(realpath) == 0; +} + +// native mkdir(const dirname[], mode, bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG"); +static cell AMX_NATIVE_CALL amx_mkdir(AMX *amx, cell *params) +{ + int length; + char *path = get_amxstring(amx, params[1], 0, length); + + size_t numParams = *params / sizeof(cell); + + if (numParams >= 3 && params[3] > 0) + { + const char* pathID = get_amxstring(amx, params[4], 1, length); + + if (g_FileSystem->IsDirectory(path)) + { + return -1; + } + + if (!strcmp(pathID, "ALL")) + { + pathID = nullptr; + } + + g_FileSystem->CreateDirHierarchy(path, pathID); + + if (g_FileSystem->IsDirectory(path)) + { + return 0; + } + } + + const char* realpath = build_pathname("%s", path); + +#if defined PLATFORM_WINDOWS + + return mkdir(realpath); +#else + if (numParams >= 2) + { + return mkdir(realpath, params[2]); + } + + return mkdir(realpath, 0755); #endif } +// native rename_file(const oldname[], const newname[], relative = 0); +static cell AMX_NATIVE_CALL rename_file(AMX *amx, cell *params) +{ + int length; + char file_old_r[PLATFORM_MAX_PATH]; + char file_new_r[PLATFORM_MAX_PATH]; + + const char* file_old = get_amxstring(amx, params[1], 0, length); + const char* file_new = get_amxstring(amx, params[2], 1, length); + + if (params[0] / sizeof(cell) >= 3 && params[3] > 0) + { + build_pathname_r(file_old_r, sizeof(file_old_r) - 1, "%s", file_old); + build_pathname_r(file_new_r, sizeof(file_new_r) - 1, "%s", file_new); + } + else + { + g_LibSys.PathFormat(file_old_r, sizeof(file_old_r) - 1, "%s", file_old); + g_LibSys.PathFormat(file_new_r, sizeof(file_new_r) - 1, "%s", file_new); + } + +#if defined PLATFORM_POSIX + + return (rename(file_old_r, file_new_r) == 0); + +#elif defined PLATFORM_WINDOWS + + return MoveFileA(file_old_r, file_new_r); +#endif +} + +// native LoadFileForMe(const file[], buffer[], maxlength, &length = 0); static cell LoadFileForMe(AMX *amx, cell *params) { - int len; - char *file = get_amxstring(amx, params[1], 0, len); - char path[256]; + int length; + char *file = get_amxstring(amx, params[1], 0, length); + char path[PLATFORM_MAX_PATH]; build_pathname_r(path, sizeof(path), "%s", file); - byte *addr = LOAD_FILE_FOR_ME(path, &len); - if (addr == NULL) + byte* addr = LOAD_FILE_FOR_ME(path, &length); + + if (!addr) { return -1; } @@ -827,10 +1058,11 @@ static cell LoadFileForMe(AMX *amx, cell *params) cell maxlength = params[3]; cell *bytes_avail = get_amxaddr(amx, params[4]); - *bytes_avail = len; + *bytes_avail = length; cell count; - for (count = 0; count < len && count < maxlength; count++) + + for (count = 0; count < length && count < maxlength; count++) { buffer[count] = addr[count]; } @@ -840,81 +1072,81 @@ static cell LoadFileForMe(AMX *amx, cell *params) return count; } +// native fflush(file); static cell AMX_NATIVE_CALL amx_fflush(AMX *amx, cell *params) { - FILE *fp = (FILE *)params[1]; + FileObject* fp = reinterpret_cast(params[1]); - return fflush(fp); + if (fp) + { + return fp->Flush(); + } + + return -1; } +// native GetFileTime(const file[], FileTimeType:tmode); static cell AMX_NATIVE_CALL GetFileTime(AMX *amx, cell *params) { - int len; - char *file = get_amxstring(amx, params[1], 0, len); + int length; + const char* file = get_amxstring(amx, params[1], 0, length); - char path[256]; - build_pathname_r(path, sizeof(path), "%s", file); + time_t time_val; -#if defined(WIN32) - struct _stat s; - if (_stat(path, &s) != 0) -#elif defined(__linux__) || defined(__APPLE__) - struct stat s; - if (stat(path, &s) != 0) -#endif + if (!g_LibSys.FileTime(build_pathname("%s", file), static_cast(params[2]), &time_val)) { return -1; } - time_t time_val = -1; - - switch( params[2] ) - { - case FileTime_LastAccess : time_val = s.st_atime; break; - case FileTime_Created : time_val = s.st_ctime; break; - case FileTime_LastChange : time_val = s.st_mtime; break; - } - - return (cell)time_val; + return static_cast(time_val); } AMX_NATIVE_INFO file_Natives[] = { - {"delete_file", delete_file}, - {"file_exists", file_exists}, - {"file_size", file_size}, {"read_dir", read_dir}, {"read_file", read_file}, {"write_file", write_file}, - //new, sane file natives + {"rename_file", rename_file}, + {"delete_file", delete_file}, + {"unlink", delete_file}, + + {"file_exists", file_exists}, + {"file_size", file_size}, + {"filesize", amx_filesize}, + {"fopen", amx_fopen}, {"fclose", amx_fclose}, + {"fread", amx_fread}, {"fread_blocks", amx_fread_blocks}, {"fread_raw", amx_fread_raw}, + {"fwrite", amx_fwrite}, {"fwrite_blocks", amx_fwrite_blocks}, {"fwrite_raw", amx_fwrite_raw}, + {"feof", amx_feof}, {"fprintf", amx_fprintf}, {"fgets", amx_fgets}, {"fseek", amx_fseek}, {"ftell", amx_ftell}, - {"filesize", amx_filesize}, - {"unlink", delete_file}, + {"fgetc", amx_fgetc}, + {"fputc", amx_fputc}, + {"fungetc", amx_ungetc}, + {"fputs", amx_fputs}, + {"fflush", amx_fflush}, + {"build_pathname", amx_build_pathname}, + {"dir_exists", dir_exists}, {"open_dir", amx_open_dir}, {"close_dir", amx_close_dir}, {"next_file", amx_get_dir}, - {"fgetc", amx_fgetc}, - {"fputc", amx_fputc}, - {"fungetc", amx_ungetc}, {"rmdir", amx_rmdir}, - {"fputs", amx_fputs}, - {"rename_file", amx_rename}, + {"mkdir", amx_mkdir}, + {"LoadFileForMe", LoadFileForMe}, - {"fflush", amx_fflush}, {"GetFileTime", GetFileTime}, {NULL, NULL} }; + diff --git a/plugins/include/file.inc b/plugins/include/file.inc index cd509a68..c617538a 100755 --- a/plugins/include/file.inc +++ b/plugins/include/file.inc @@ -12,140 +12,23 @@ // #if defined _file_included - #endinput + #endinput #endif #define _file_included -/* Reads content from directory. -* Returns index of next element or 0 when end of dir. is reached. */ -native read_dir(const dirname[],pos,output[],len,&outlen); - -/* Reads line from file. Returns index of next line or 0 when end of file is reached. */ -native read_file(const file[],line,text[],len,&txtlen); - -/* Writes text to file. Function returns 0 on failure. -* When line is set to -1, the text is added at the end of file. */ -native write_file(const file[],const text[],line = -1); - -/* Deletes file. Function returns 1 on success, 0 on failure. */ -native delete_file(const file[]); - -/* Checks for file. If file exists function returns 1, in other case 0. */ -native file_exists(const file[]); - -/* renames a file. returns 0 on failure, 1 on success. - * if relative true, rename_file will act like other natives which - * use the moddir as a base directory. otherwise, the current directory is - * undefined (but assumed to be hlds). +/** + * File inode types for use with open_dir() and next_file(). */ -native rename_file(const oldname[], const newname[], relative=0); - -/* Checks if a directory exists */ -native dir_exists(const dir[]); - -/* Returns a file size in bytes if flag is set to 0. -* When flag is set to 1 returns number of lines in the file, -* and when flags is 2, function returns 1 if the file ends -* with line feed. If file doesn't exist returns -1. */ -native file_size(const file[], flag=0); - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -//Open a file, returns a handle or 0 on failure -native fopen(const filename[],const mode[]); - -//Closes a file handle -native fclose(file); - -#define BLOCK_INT 4 -#define BLOCK_SHORT 2 -#define BLOCK_CHAR 1 -#define BLOCK_BYTE 1 - -//The following functions work as such: -// RAW - means the array you pass is a raw bytestream, for experts only -// BLOCK - means you are passing in an array where each element will be written -// NORMAL - means you are writing only one element -// RAW and BLOCK return the number of blocks acted upon successfully -// NORMAL returns 1 on success - -native fread(file, &data, mode); -native fread_blocks(file, data[], blocks, mode); -native fread_raw(file, stream[], blocksize, blocks); -native fwrite(file, data, mode); -native fwrite_blocks(file, const data[], blocks, mode); -native fwrite_raw(file, const stream[], blocksize, mode); - -//Returns 1 if the file is ended, 0 otherwise -native feof(file); - -//Reads a line from a text file -- includes newline! -native fgets(file, buffer[], maxlength); - -//Writes a line to a text file. Returns # of characters written. -native fputs(file, const text[]); - -//Writes a line to the file -native fprintf(file, const fmt[], any:...); - -//Sets the current position in a file (see SEEK_ values above) -native fseek(file, position, start); - -//Returns the current position in a file -native ftell(file); - -//These are straight from the C standard. -native fgetc(file); -native fputc(file, data); -native fungetc(file, data); - -//Return the size of a file -native filesize(const filename[], any:...); - -//Attempts to remove a directory. -//Note that you cannot remove a directory that has files on most -// operating systems. -native rmdir(const path[]); - -/* Returns 0 on success, like the POSIX specification */ -native mkdir(const dirname[]); - - -//Delete a file (delete_file macro) -native unlink(const filename[]); - -//Returns a handle to a directory -native open_dir(dir[], firstfile[], length); -native next_file(dirh, buffer[], length); -native close_dir(dirh); +enum FileType +{ + FileType_Unknown, /* Unknown file type (device/socket) */ + FileType_Directory, /* File is a directory */ + FileType_File, /* File is a file */ +}; /** - * Loads a file using the LoadFileForMe engine function. - * - * The data is truncated if there is not enough space. No null-terminator - * is applied; the data is the raw contents of the file. - * - * @param file File to load (may be a file from the GCF). - * @param buffer Buffer to store file contents. - * @param maxlength Maximum size of the file buffer. - * @param length Variable to store the file length. This may return - * a number larger than the buffer size. - * @return -1 if the file could not be loaded. Otherwise, - * the number of cells actually written to the buffer - * are returned. + * File time modes for use with GetFileTime(). */ -native LoadFileForMe(const file[], buffer[], maxlength, &length=0); - -/** - * Flushes a buffered output stream. - * - * @param file File handle, or 0 for all open streams. - * @return 0 on success, -1 on failure. - */ -native fflush(file); - enum FileTimeType { FileTime_LastAccess, /* Last access (not available on FAT) */ @@ -153,11 +36,523 @@ enum FileTimeType FileTime_LastChange, /* Last modification */ }; +/** + * File position modes for use with fseek(). + */ +#define SEEK_SET 0 /* Seek from start */ +#define SEEK_CUR 1 /* Seek from current position */ +#define SEEK_END 2 /* Seek from end position */ + +/** + * Options for use with file_size() flag parameter. + */ +#define FSOPT_BYTES_COUNT 0 /* Returns the file size in number of bytes */ +#define FSOPT_LINES_COUNT 1 /* Returns how many lines there are in this file */ +#define FSOPT_END_WITH_LF 2 /* Returns whether the last line is '\n' */ + +/** + * Data block modes for use with fread*() and fwrite*(). + */ +#define BLOCK_INT 4 +#define BLOCK_SHORT 2 +#define BLOCK_CHAR 1 +#define BLOCK_BYTE 1 + +/** + * File permissions flags for use with mkdir(). + */ +#define FPERM_U_READ 0x0100 /* User can read. */ +#define FPERM_U_WRITE 0x0080 /* User can write. */ +#define FPERM_U_EXEC 0x0040 /* User can exec. */ +#define FPERM_U_RWX FPERM_U_READ | FPERM_U_WRITE | FPERM_U_EXEC + +#define FPERM_G_READ 0x0020 /* Group can read. */ +#define FPERM_G_WRITE 0x0010 /* Group can write. */ +#define FPERM_G_EXEC 0x0008 /* Group can exec. */ +#define FPERM_G_RWX FPERM_G_READ | FPERM_G_WRITE | FPERM_G_EXEC + +#define FPERM_O_READ 0x0004 /* Anyone can read. */ +#define FPERM_O_WRITE 0x0002 /* Anyone can write. */ +#define FPERM_O_EXEC 0x0001 /* Anyone can exec. */ +#define FPERM_O_RWX FPERM_O_READ | FPERM_O_WRITE | FPERM_O_EXEC + +#define FPERM_DIR_DEFAULT FPERM_U_RWX | FPERM_G_RWX | FPERM_O_RWX /* rwx r-x r-x (0755) */ + + +/** + * Reads content from directory + * + * @note This native is expensive. Consider the use of open_dir(), next_file() and close_dir() instead. + * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. + * + * @param dirname Path to open + * @param pos Index the element + * @param output String buffer to hold content + * @param len Maximum size of string buffer + * @param outlen Number of characters written to the buffer + * + * @return Returns index of next element, otherwiwe 0 when end of dir is reached + */ +native read_dir(const dirname[], pos, output[], len, &outlen = 0); + +/** + * Reads line from file. + * + * @note This native is expensive. Consider the use of new file natives (fopen(), fgets(), etc.) + * if purpose is to read several lines of a file. + * + * @param file Path to open + * @param line Index of the line, starting to 0 + * @param text String buffer to hold line read + * @param len Maximum size of string buffer + * @param txtlen Number of characters written to the buffer + * + * @return Returns index of next line, otherwise 0 when end of file is reached + * @error Unable to read the file + */ +native read_file(const file[], line, text[], len, &txtlen = 0); + +/** + * Writes text to file. + * + * @note This native is expensive. Consider the use of new file natives (fopen(), fputs(), etc.) + * if purpose is to write several lines of a file. + * + * @param file Path to open + * @param text String to write to + * @param line Index of the line, starting to 0 + * If < 0, content will be appended + * + * @noreturn + * @error Unable to write [temporary] file + */ +native write_file(const file[], const text[], line = -1); + +/** + * Deletes a file. + * + * @param file Path of the file to delete + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to delete files existing in the Valve + * search path, rather than solely files existing directly + * in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths. + * + * @return 1 on success, 0 on failure or if file not immediately removed. + */ +native delete_file(const file[], bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG"); + +/** + * Checks if a file exists. + * + * @param file Path to the file + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * + * @return 1 if the file exists, 0 otherwise + */ +native file_exists(const file[], bool:use_valve_fs = false); + + /** + * Renames a file. + * + * @param oldname New path to the file + * @param newname Path to the existing file + * @param relative If true, native will act like other natives which + * use the moddir as a base directory. Otherwise, the + * current directory is undefined (but assumed to be hlds). + * + * @return 1 on success, 0 otherwise + */ +native rename_file(const oldname[], const newname[], relative = 0); + +/** + * Checks if a directory exists. + * + * @param dir Path to the directory + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * + * @return 1 if the directory exists, 0 otherwise + */ +native dir_exists(const dir[], bool:use_valve_fs = false); + +/** + * Get the file size in bytes. + * + * @param file Path to the file + * @param flag Flag options, see FSOPT_* constants + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * If used, flag option is ignored. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * + * @return If flag is FSOPT_BYTES_COUNT or use_valve_fs to true, the file size in bytes + * If flag is FSOPT_LINES_COUNT, the number of lines in the file + * If flag is FSOPT_END_WITH_LF, 1 is returned if file ends with line feed + * If file doesn't exist, -1 + */ +native file_size(const file[], flag = FSOPT_BYTES_COUNT, bool:use_valve_fs = false, const valve_path_id[] = "GAME"); + +/** + * Opens or creates a file, returning a file handle on success. File handles + * should be closed with fclose(). + * + * @note The open mode may be one of the following strings: + * "r": Open an existing file for reading. + * "w": Create a file for writing, or truncate (delete the contents of) an + * existing file and then open it for writing. + * "a": Create a file for writing, or open an existing file such that writes + * will be appended to the end. + * "r+": Open an existing file for both reading and writing. + * "w+": Create a file for reading and writing, or truncate an existing file + * and then open it for reading and writing. + * "a+": Create a file for both reading and writing, or open an existing file + * such that writes will be appended to the end. + * + * @note The open mode may also contain an additional character after "r", "w", or "a", + * but before any "+" sign. This character may be "b" (indicating binary mode) or + * "t" (indicating text mode). By default, "text" mode is implied. On Linux and + * Mac, this has no distinction from binary mode. On Windows, it causes the '\n' + * character (0xA) to be written as "\r\n" (0xD, 0xA). + * + * Example: "rb" opens a binary file for writing; "at" opens a text file for + * appending. + * + * @note Registered paths ID are (in priority order) : + * GAME All paths related to current mod, including fallback + * Depending settings, it includes: _lv/_addon/_/_hd + * and itself + * GAMECONFIG The default writable directory () + * GAMEDOWNLOAD The download directory (_download) + * GAME_FALLBACK All paths related to fallback game, same as GAME + * DEFAULTGAME All paths related to the default game which is "valve", same as GAME + * BASE The base path where server is installed + * + * Note that some paths are non-writable. It includes all _* (expect _download) + * and DEFAULTGAME. Any file inside a non-writable path will be ignored if you try to open + * it in writing mode. + * + * @param filename File to open + * @param mode Open mode + * @param use_valve_fs If true, the Valve file system will be used instead + * This can be used to finred files existing in valve + * search paths, rather than solely files existing directly + * in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * + * @return A file handle, or null if the file could not be opened. + */ +native fopen(const filename[], const mode[], bool:use_valve_fs = false, const valve_path_id[] = "GAME"); + +/** + * Closes a file handle. + * + * @param file File handle + */ +native fclose(file); + +/** + * Reads a single binary data from a file. + * + * @param file Handle to the file + * @param data Variable to store item read + * @param mode Size of each element, in bytes, to be read + * See BLOCK_* constants + * + * @return Number of elements read + */ +native fread(file, &any:data, mode); + +/** + * Reads binary data from a file. + * + * @param file Handle to the file + * @param data Array to store each item read + * @param blocks Number of items to read into the array + * @param mode Size of each element, in bytes, to be read + * Valid sizes are 1, 2, or 4. See BLOCK_* constants. + * + * @return Number of elements read + */ +native fread_blocks(file, any:data[], blocks, mode); + +/** + * Reads raw binary data from a file. + * + * @param file Handle to the file + * @param stream Array to store each item read + * @param blocksize Number of items to read into the array + * @param blocks Size of each element, in bytes. The data is read directly. + * That is, in 1 or 2-byte mode, the lower byte(s) in + * each cell are used directly, rather than performing + * any casts from a 4-byte number to a smaller number. + * + * @return Number of elements read + */ +native fread_raw(file, any:stream[], blocksize, blocks); + +/** + * Writes a single binary data to a file. + * + * @param file Handle to the file + * @param data Item to write + * @param mode Size of each item in the array in bytes + * Valid sizes are 1, 2, or 4. See BLOCK_* constants + * + * @return Number of elements written + */ +native fwrite(file, any:data, mode); + +/** + * Writes binary data to a file. + * + * @param file Handle to the file + * @param data Array of items to write + * @param blocks Number of items in the array + * @param mode Size of each item in the array in bytes + * Valid sizes are 1, 2, or 4. See BLOCK_* constants + * + * @return Number of elements written + */ +native fwrite_blocks(file, const any:data[], blocks, mode); + +/** + * Writes raw binary data to a file. + * + * @param file Handle to the file. + * @param stream Array of items to write. The data is written directly. + * That is, in 1 or 2-byte mode, the lower byte(s) in + * each cell are used directly, rather than performing + * any casts from a 4-byte number to a smaller number. + * @param blocks Size of each item in the array in bytes. + * @param mode Number of items in the array. + * + * @return Number of elements written + */ +native fwrite_raw(file, const any:stream[], blocks, mode); + +/** + * Tests if the end of file has been reached. + * + * @param file Handle to the file + * + * @return 1 if end of file has been reached, 0 otherwise. + */ +native feof(file); + +/** + * Reads a line from a text file. + * + * @param file Handle to the file. + * @param buffer String buffer to hold the line + * @param maxlength Maximum size of string buffer + * + * @return Total number of characters written on success, 0 otherwise + */ +native fgets(file, buffer[], maxlength); + +/** + * Writes a line of text to a text file. + * + * @param file Handle to the file + * @param text String to write + * @param null_term True to append NULL terminator, false otherwise + * + * @return 0 on success, -1 otherwise + */ +native fputs(file, const text[], bool:null_term = false); + +/** + * Writes a line of formatted text to a text file. + * + * @param file Handle to the file + * @param format Formatting rules + * @param ... Variable number of format parameters + * + * @return Total number of characters written on success, 0 otherwise + */ +native fprintf(file, const fmt[], any:...); + +/** + * Sets the file position indicator. + * + * @param file Handle to the file + * @param position Position relative to what is specified in whence + * @param start SEEK_ constant value of where to see from + * + * @return 0 on success, a non-zero value otherwise + */ +native fseek(file, position, start); + +/** + * Gets current position in the file. + * + * @param file Handle to the file + * + * @return Value for the file position indicator + */ +native ftell(file); + +/** + * Gets character from file. + * + * @param file Handle to the file + * + * @return Character read on success, -1 otherwise + */ +native fgetc(file); + +/** + * Writes character to file + * + * @param file Handle to the file + * @param data Character to put + * + * @return Character written on success, -1 otherwise + */ +native fputc(file, data); + +/** + * Ungets character from file. + * + * @param file Handle to the file + * @param data Character to unget + * + * @return On success, the character put back is returned, -1 otherwise + */ +native fungetc(file, data); + +/** + * Flushes a buffered output stream. + * + * @param file File handle, or 0 for all open streams + * + * @return 0 on success, -1 on failure + */ +native fflush(file); + +/** + * Gets the formatted file size in bytes. + * + * @param filename Path to the file + * @param ... Variable number of format parameters + * + * @return File size in bytes, otherwise -1 if file not found + */ +native filesize(const filename[], any:...); + +/** + * Removes a directory. + * + * @note On most Operating Systems you cannot remove a directory which has files inside it. + * + * @param path Path to the directory + * + * @return 1 on success, 0 otherwise + */ +native rmdir(const path[]); + +/** + * Creates a directory. + * + * @param path Path to create + * @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have + * the execute bit set on Linux. On Windows, the mode is ignored. + * @param use_valve_fs If true, the Valve file system will be used instead + * This can be used to create folders in the game's + * Valve search paths, rather than directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for default + * In this case, mode is ignored + * + * @return 0 on success, -1 otherwise + */ +native mkdir(const dirname[], mode = FPERM_DIR_DEFAULT, bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG"); + +/** + * Deletes a file (delete_file macro) + * + * @param filename Path of the file to delete + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to delete files existing in the Valve + * search path, rather than solely files existing directly + * in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * + * @return 1 on success, 0 on failure or if file not immediately removed + */ +native unlink(const filename[], bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG"); + +/** + * Opens a directory/folder for contents enumeration. + * + * @note Directories are closed with close_dir(). + * + * @param dir Path to open. + * @param firstfile String buffer to hold first file name + * @param length Maximum size of the string buffer + * @param type Optional variable to store the file type + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths. + * + * @return Handle to the directory, 0 otherwise + */ +native open_dir(dir[], firstfile[], length, &FileType:type = FileType_Unknown, bool:use_valve_fs = false, const valve_path_id[] = "GAME"); + +/** + * Reads the next directory entry as a local filename. + * + * @note Contents of buffers are undefined when returning false. + * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. + * + * @param dirh Handle to a directory + * @param buffer String buffer to hold directory name + * @param length Maximum size of string buffer + * @param type Optional variable to store the file type. FileType_* constants + * + * @return 1 on success, 0 if there are no more files to read. + */ +native next_file(dirh, buffer[], length, &FileType:type = FileType_Unknown); + +/** + * Closes the directory. + * + * @param dirh Handle to a directory + */ +native close_dir(dirh); + +/** + * Loads a file using the LoadFileForMe engine function. + * + * The data is truncated if there is not enough space. No null-terminator + * is applied; the data is the raw contents of the file. + * + * @param file File to load (may be a file from the GCF) + * @param buffer Buffer to store file contents + * @param maxlength Maximum size of the file buffer + * @param length Variable to store the file length. This may return + * a number larger than the buffer size + * @return -1 if the file could not be loaded. Otherwise, + * the number of cells actually written to the buffer + * are returned. + */ +native LoadFileForMe(const file[], buffer[], maxlength, &length = 0); + /** * Returns a file timestamp as a unix timestamp. * - * @param file File name. - * @param tmode Time mode. See FileTime_* constants. - * @return Returns a file timestamp as a unix timestamp. + * @param file File name + * @param tmode Time mode, see FileTime_* constants + * + * @return Returns a file timestamp as a unix timestamp */ -native GetFileTime( const file[], FileTimeType:tmode ); +native GetFileTime(const file[], FileTimeType:tmode); From a580c8c5e5bd0a92d23004fade8a79e240def5d3 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 9 Mar 2015 00:10:26 +0100 Subject: [PATCH 06/10] VFS: Add SetFilePermissions native --- amxmodx/file.cpp | 38 ++++++++++++++++++++++++++++++++++++++ plugins/include/file.inc | 16 +++++++++++++--- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index 1341851b..f64c7a72 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -1101,6 +1101,42 @@ static cell AMX_NATIVE_CALL GetFileTime(AMX *amx, cell *params) return static_cast(time_val); } +#define FPERM_U_READ 0x0100 /* User can read. */ +#define FPERM_U_WRITE 0x0080 /* User can write. */ +#define FPERM_U_EXEC 0x0040 /* User can exec. */ +#define FPERM_G_READ 0x0020 /* Group can read. */ +#define FPERM_G_WRITE 0x0010 /* Group can write. */ +#define FPERM_G_EXEC 0x0008 /* Group can exec. */ +#define FPERM_O_READ 0x0004 /* Anyone can read. */ +#define FPERM_O_WRITE 0x0002 /* Anyone can write. */ +#define FPERM_O_EXEC 0x0001 /* Anyone can exec. */ + +// native bool:SetFilePermissions(const path[], int mode); +static cell SetFilePermissions(AMX *amx, cell *params) +{ + int length; + const char* realpath = build_pathname(get_amxstring(amx, params[1], 0, length)); + +#if defined PLATFORM_WINDOWS + + int mask = 0; + + if (params[2] & (FPERM_U_WRITE | FPERM_G_WRITE | FPERM_O_WRITE)) + { + mask |= _S_IWRITE; + } + + if (params[2] & (FPERM_U_READ | FPERM_G_READ | FPERM_O_READ | FPERM_U_EXEC | FPERM_G_EXEC | FPERM_O_EXEC)) + { + mask |= _S_IREAD; + } + + return _chmod(realpath, mask) == 0; +#elif + return chmod(realpath, params[2]) == 0; +#endif +} + AMX_NATIVE_INFO file_Natives[] = { {"read_dir", read_dir}, @@ -1147,6 +1183,8 @@ AMX_NATIVE_INFO file_Natives[] = {"LoadFileForMe", LoadFileForMe}, {"GetFileTime", GetFileTime}, + {"SetFilePermissions", SetFilePermissions}, + {NULL, NULL} }; diff --git a/plugins/include/file.inc b/plugins/include/file.inc index c617538a..9b73b874 100755 --- a/plugins/include/file.inc +++ b/plugins/include/file.inc @@ -59,7 +59,7 @@ enum FileTimeType #define BLOCK_BYTE 1 /** - * File permissions flags for use with mkdir(). + * File permissions flags for use with mkdir() and SetFilePermissions(). */ #define FPERM_U_READ 0x0100 /* User can read. */ #define FPERM_U_WRITE 0x0080 /* User can write. */ @@ -227,14 +227,14 @@ native file_size(const file[], flag = FSOPT_BYTES_COUNT, bool:use_valve_fs = fal * * @note Registered paths ID are (in priority order) : * GAME All paths related to current mod, including fallback - * Depending settings, it includes: _lv/_addon/_/_hd + * Depending settings, it includes: _lv/_addon/_/_hd * and itself * GAMECONFIG The default writable directory () * GAMEDOWNLOAD The download directory (_download) * GAME_FALLBACK All paths related to fallback game, same as GAME * DEFAULTGAME All paths related to the default game which is "valve", same as GAME * BASE The base path where server is installed - * + * * Note that some paths are non-writable. It includes all _* (expect _download) * and DEFAULTGAME. Any file inside a non-writable path will be ignored if you try to open * it in writing mode. @@ -556,3 +556,13 @@ native LoadFileForMe(const file[], buffer[], maxlength, &length = 0); * @return Returns a file timestamp as a unix timestamp */ native GetFileTime(const file[], FileTimeType:tmode); + +/** + * Changes a file or directories permissions. + * + * @param path Path to the file + * @param mode Permissions to set, see FPERM_* constants + * + * @return True on success, false otherwise + */ +native bool:SetFilePermissions(const path[], mode); From 71ab8d560eaf76cef8d3056c113a997c9e7a83aa Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 9 Mar 2015 00:38:05 +0100 Subject: [PATCH 07/10] VFS: Add more sane FileRead/Write* natives to read/write a single value --- amxmodx/file.cpp | 55 +++++++++++++++++++++++--- plugins/include/file.inc | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 5 deletions(-) diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index f64c7a72..8596b09b 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -1132,11 +1132,49 @@ static cell SetFilePermissions(AMX *amx, cell *params) } return _chmod(realpath, mask) == 0; -#elif +#else return chmod(realpath, params[2]) == 0; #endif } +template +static cell File_ReadTyped(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + cell* data = get_amxaddr(amx, params[2]); + + T value; + + if (fp->Read(&value, sizeof(value)) != sizeof(value)) + { + return 0; + } + + *data = value; + return 1; +} + +template +static cell File_WriteTyped(AMX *amx, cell *params) +{ + FileObject* fp = reinterpret_cast(params[1]); + + if (!fp) + { + return 0; + } + + T value = static_cast(params[2]); + + return !!(fp->Write(&value, sizeof(value)) == sizeof(value)); +} + AMX_NATIVE_INFO file_Natives[] = { {"read_dir", read_dir}, @@ -1181,10 +1219,17 @@ AMX_NATIVE_INFO file_Natives[] = {"rmdir", amx_rmdir}, {"mkdir", amx_mkdir}, - {"LoadFileForMe", LoadFileForMe}, - {"GetFileTime", GetFileTime}, - {"SetFilePermissions", SetFilePermissions}, + {"LoadFileForMe", LoadFileForMe}, + {"GetFileTime", GetFileTime}, + {"SetFilePermissions", SetFilePermissions}, + {"FileReadInt8", File_ReadTyped}, + {"FileReadUint8", File_ReadTyped}, + {"FileReadInt16", File_ReadTyped}, + {"FileReadUint16", File_ReadTyped}, + {"FileReadInt32", File_ReadTyped}, + {"FileWriteInt8", File_WriteTyped}, + {"FileWriteInt16", File_WriteTyped}, + {"FileWriteInt32", File_WriteTyped}, {NULL, NULL} }; - diff --git a/plugins/include/file.inc b/plugins/include/file.inc index 9b73b874..82016380 100755 --- a/plugins/include/file.inc +++ b/plugins/include/file.inc @@ -566,3 +566,88 @@ native GetFileTime(const file[], FileTimeType:tmode); * @return True on success, false otherwise */ native bool:SetFilePermissions(const path[], mode); + +/** + * Reads a single int8 (byte) from a file. The returned value is sign- + * extended to an int32. + * + * @param file Handle to the file + * @param data Variable to store the data read + * + * @return True on success, false on failure + */ +native bool:FileReadInt8(file, &any:data); + +/** + * Reads a single uint8 (unsigned byte) from a file. The returned value is + * zero-extended to an int32. + * + * @param file Handle to the file + * @param data Variable to store the data read + * + * @return True on success, false on failure + */ +native bool:FileReadUint8(file, &any:data); + +/** + * Reads a single int16 (short) from a file. The value is sign-extended to + * an int32. + * + * @param file Handle to the file + * @param data Variable to store the data read + * + * @return True on success, false on failure + */ +native bool:FileReadInt16(file, &any:data); + +/** + * Reads a single unt16 (unsigned short) from a file. The value is zero- + * extended to an int32. + * + * @param file Handle to the file + * @param data Variable to store the data read + * + * @return True on success, false on failure + */ +native bool:FileReadUint16(file, &any:data); + +/** + * Reads a single int32 (int/cell) from a file. + * + * @param file Handle to the file + * @param data Variable to store the data read + * + * @return True on success, false on failure + */ +native bool:FileReadInt32(file, &any:data); + +/** + * Writes a single int8 (byte) to a file. + * + * @param file Handle to the file + * @param data Data to write (truncated to an int8) + * + * @return True on success, false on failure + */ +native bool:FileWriteInt8(file, any:data); + +/** + * Writes a single int16 (short) to a file. + * + * @param file Handle to the file + * @param data Data to write (truncated to an int16) + * + * @return True on success, false on failure + */ +native bool:FileWriteInt16(file, any:data); + +/** + * Writes a single int32 (int/cell) to a file. + * + * @param file Handle to the file + * @param data Data to write + * + * @return True on success, false on failure + */ +native bool:FileWriteInt32(file, any:data); + From ba11085ddc055a60ea2bbd03f8acf205ff95f64e Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 9 Mar 2015 00:48:28 +0100 Subject: [PATCH 08/10] VFS: Add constant in pawn include to define max path --- plugins/include/file.inc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/include/file.inc b/plugins/include/file.inc index 82016380..2ac10e3e 100755 --- a/plugins/include/file.inc +++ b/plugins/include/file.inc @@ -16,6 +16,19 @@ #endif #define _file_included +/** + * @note All paths in AMX Mod X natives are relative to the mod folder + * unless otherwise noted. + * + * Most functions in AMX Mod X (at least, ones that deal with direct + * file manipulation) will support an alternate path specification. + */ + +/** + * Maximum path length. + */ +#define PLATFORM_MAX_PATH 256 + /** * File inode types for use with open_dir() and next_file(). */ From 8f6b8588c14c15b9b006e4f1722675192a812df4 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 23 Mar 2015 18:30:22 +0100 Subject: [PATCH 09/10] VFS: Do not traumatize Nextra --- amxmodx/CFileSystem.h | 4 ++-- amxmodx/file.cpp | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/amxmodx/CFileSystem.h b/amxmodx/CFileSystem.h index a7c2cc8c..a9d79f40 100644 --- a/amxmodx/CFileSystem.h +++ b/amxmodx/CFileSystem.h @@ -79,14 +79,14 @@ class ValveFile : public FileObject static bool Delete(const char* filename, const char* pathID) { - if (!g_FileSystem->FileExists(filename)) + if (!Exists(filename)) { return false; } g_FileSystem->RemoveFile(filename, pathID); - if (g_FileSystem->FileExists(filename)) + if (Exists(filename)) { return false; } diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index 8596b09b..008b9dd3 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -37,9 +37,9 @@ static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params) } const char* entry = dir->GetEntryName(); + cell* outputLen = get_amxaddr(amx, params[5]); - size_t entrylen = set_amxstring_utf8(amx, params[3], entry, strlen(entry), params[4] + 1); - *get_amxaddr(amx, params[5]) = entrylen; + *outputLen = set_amxstring_utf8(amx, params[3], entry, strlen(entry), params[4] + 1); return offset; } @@ -79,8 +79,8 @@ static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params) if (buffer[length - 1] == '\r') buffer[--length] = '\0'; - length = set_amxstring_utf8(amx, params[3], buffer, length, params[4] + 1); // + EOS - *get_amxaddr(amx, params[5]) = length; + cell* textLen = get_amxaddr(amx, params[5]); + *textLen = set_amxstring_utf8(amx, params[3], buffer, length, params[4] + 1); // + EOS return currentLine; } @@ -761,7 +761,7 @@ static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) size_t numParams = *params / sizeof(cell); - if (*params / sizeof(cell) >= 4 && params[5] > 0) + if (numParams >= 4 && params[5] > 0) { const char* wildcardedPath = g_LibSys.PathFormat("%s%s*", path, (path[length - 1] != '/' && path[length - 1] != '\\') ? "/" : ""); const char* pathID = get_amxstring(amx, params[6], 1, length); @@ -780,8 +780,9 @@ static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) } set_amxstring_utf8(amx, params[2], pFirst, strlen(pFirst), params[3] + 1); + cell* fileType = get_amxaddr(amx, params[4]); - *get_amxaddr(amx, params[4]) = g_FileSystem->FindIsDirectory(handle) ? FileType_Directory : FileType_File; + *fileType = g_FileSystem->FindIsDirectory(handle) ? FileType_Directory : FileType_File; return reinterpret_cast(new DirectoryHandle(reinterpret_cast(&handle), true)); } @@ -795,7 +796,8 @@ static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) if (numParams >= 4) { - *get_amxaddr(amx, params[4]) = dir->IsEntryDirectory() ? FileType_Directory : FileType_File; + cell* fileType = get_amxaddr(amx, params[4]); + *fileType = dir->IsEntryDirectory() ? FileType_Directory : FileType_File; } const char* entry = dir->GetEntryName(); @@ -858,7 +860,8 @@ static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params) if (numParams >= 4) { - *get_amxaddr(amx, params[4]) = g_FileSystem->FindIsDirectory(*handle) ? FileType_Directory : FileType_File; + cell* fileType = get_amxaddr(amx, params[4]); + *fileType = g_FileSystem->FindIsDirectory(*handle) ? FileType_Directory : FileType_File; } set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1); @@ -881,7 +884,8 @@ static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params) if (numParams >= 4) { - *get_amxaddr(amx, params[4]) = handle->IsEntryDirectory() ? FileType_Directory : FileType_File; + cell* fileType = get_amxaddr(amx, params[4]); + *fileType = handle->IsEntryDirectory() ? FileType_Directory : FileType_File; } const char* entry = handle->GetEntryName(); From 52c73126e1551ebec656712c4553f704ece7eb6d Mon Sep 17 00:00:00 2001 From: Arkshine Date: Wed, 25 Mar 2015 13:50:07 +0100 Subject: [PATCH 10/10] VFS: Fix various things - The "ALL" fake pathID is replaced by what does SM, having a public var NULL_STRING which will acts as NULL when needed. To make compiler accepting public array, this patch was needed: https://hg.alliedmods.net/sourcemod-central/rev/b12f329def09 - The offset thing in read_dir: considering that's something very specific to this native and that implementation in CDirectory doesn't make sense because of the offset compatibility for windows, all code is now in the native. --- amxmodx/CLibrarySys.cpp | 43 ++++------------- amxmodx/CLibrarySys.h | 9 +++- amxmodx/CPlugin.cpp | 7 ++- amxmodx/CPlugin.h | 2 + amxmodx/amxmodx.cpp | 2 +- amxmodx/amxmodx.h | 1 + amxmodx/file.cpp | 93 +++++++++++++++++------------------- amxmodx/string.cpp | 10 ++++ compiler/libpc300/sc1.c | 4 +- compiler/libpc300/sc6.c | 5 +- plugins/include/amxconst.inc | 10 +++- plugins/include/file.inc | 12 ++--- 12 files changed, 101 insertions(+), 97 deletions(-) diff --git a/amxmodx/CLibrarySys.cpp b/amxmodx/CLibrarySys.cpp index 03b2892d..689b789d 100644 --- a/amxmodx/CLibrarySys.cpp +++ b/amxmodx/CLibrarySys.cpp @@ -61,28 +61,16 @@ CDirectory::~CDirectory() } } -void CDirectory::NextEntry(cell* offset) +DirHandle CDirectory::GetHandle() +{ + return m_dir; +} + +void CDirectory::NextEntry() { #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) + if (FindNextFile(m_dir, &m_fd) == 0) { FindClose(m_dir); m_dir = INVALID_HANDLE_VALUE; @@ -90,22 +78,7 @@ void CDirectory::NextEntry(cell* offset) #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))) + if (!(m_ep = readdir(m_dir))) { closedir(m_dir); m_dir = nullptr; diff --git a/amxmodx/CLibrarySys.h b/amxmodx/CLibrarySys.h index 1ce8f37b..d57063b4 100644 --- a/amxmodx/CLibrarySys.h +++ b/amxmodx/CLibrarySys.h @@ -58,9 +58,15 @@ #define PLATFORM_MAX_PATH 260 #if defined PLATFORM_WINDOWS + typedef HMODULE LibraryHandle; + typedef HANDLE DirHandle; + #elif defined PLATFORM_POSIX + typedef void* LibraryHandle; + typedef DIR* DirHandle; + #endif enum FileTimeType @@ -80,7 +86,7 @@ class CDirectory public: bool MoreFiles(); - void NextEntry(cell* offset = nullptr); + void NextEntry(); const char* GetEntryName(); bool IsEntryDirectory(); bool IsEntryFile(); @@ -89,6 +95,7 @@ class CDirectory public: bool IsValid(); + DirHandle GetHandle(); private: diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index 5db24c52..04ad342f 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -152,6 +152,11 @@ int CPluginMngr::loadPluginsFromFile(const char* filename, bool warn) { *get_amxaddr(plugin->getAMX(), addr) = gpGlobals->maxClients; } + + if (amx_FindPubVar(plugin->getAMX(), "NULL_STRING", &addr) != AMX_ERR_NOTFOUND) + { + plugin->m_pNullStringOfs = get_amxaddr(plugin->getAMX(), addr); + } } } @@ -256,7 +261,7 @@ const char* CPluginMngr::CPlugin::getStatus() const return "error"; } -CPluginMngr::CPlugin::CPlugin(int i, const char* p, const char* n, char* e, int d) : name(n), title(n) +CPluginMngr::CPlugin::CPlugin(int i, const char* p, const char* n, char* e, int d) : name(n), title(n), m_pNullStringOfs(nullptr) { const char* unk = "unknown"; diff --git a/amxmodx/CPlugin.h b/amxmodx/CPlugin.h index a52ffd37..ced01d6b 100755 --- a/amxmodx/CPlugin.h +++ b/amxmodx/CPlugin.h @@ -61,6 +61,7 @@ public: ~CPlugin(); bool m_Debug; + cell* m_pNullStringOfs; public: inline const char* getName() { return name.c_str();} inline const char* getVersion() { return version.c_str();} @@ -90,6 +91,7 @@ public: const char* getStatus() const; inline bool isDebug() const { return m_Debug; } + inline cell* getNullStringOfs() const { return m_pNullStringOfs; } }; private: diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 321a991f..50ee79ff 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -29,7 +29,7 @@ static cell AMX_NATIVE_CALL get_xvar_id(AMX *amx, cell *params) char* sName = get_amxstring(amx, params[1], 0, len); cell ptr; - if (!strcmp(sName, "MaxClients")) + if (!strcmp(sName, "MaxClients") || !strcmp(sName, "NULL_STRING")) { return -1; } diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 4b216480..4bf6b85e 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -276,6 +276,7 @@ char* format_amxstring(AMX *amx, cell *params, int parm, int& len); AMX* get_amxscript(int, void**, const char**); const char* get_amxscriptname(AMX* amx); char* get_amxstring(AMX *amx, cell amx_addr, int id, int& len); +char *get_amxstring_null(AMX *amx, cell amx_addr, int id, int& len); extern "C" size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen); int amxstring_len(cell* cstr); diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index 008b9dd3..a5e1981e 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -29,7 +29,30 @@ static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params) cell offset = Max(0, params[2]); - dir->NextEntry(&offset); + if (offset >= 0) + { +#if defined PLATFORM_WINDOWS + // Should be declared after so entry starts to '.' and not '..' + // But old code did that, so keep this for compatibility. + ++offset; + + for (cell i = 0; i < offset && dir->MoreFiles(); ++i) + { + dir->NextEntry(); + } + +#elif defined PLATFORM_POSIX + + seekdir(dir->GetHandle(), offset); + + dir->NextEntry(); + + if (dir->IsValid()) + { + offset = telldir(dir->GetHandle()); + } +#endif + } if (!dir->IsValid()) { @@ -190,12 +213,7 @@ static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params) if (*params / sizeof(cell) >= 2 && params[2] > 0) { - const char* pathID = get_amxstring(amx, params[3], 1, length); - - if (!strcmp(pathID, "ALL")) - { - pathID = nullptr; - } + const char* pathID = get_amxstring_null(amx, params[3], 1, length); return ValveFile::Delete(file, pathID); } @@ -240,7 +258,7 @@ static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) { int length; const char* path = get_amxstring(amx, params[1], 0, length); - int flag = params[2]; + int flag = FSOPT_BYTES_COUNT; AutoPtr fp; @@ -248,12 +266,7 @@ static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) if (numParams >= 3 && params[3] > 0) { - const char* pathID = get_amxstring(amx, params[4], 1, length); - - if (!strcmp(pathID, "ALL")) - { - pathID = nullptr; - } + const char* pathID = get_amxstring_null(amx, params[4], 1, length); fp = ValveFile::Open(path, "r", pathID); } @@ -267,9 +280,13 @@ static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) return -1; } + if (numParams >= 2) + { + flag = params[2]; + } + switch (flag) { - default: case FSOPT_BYTES_COUNT: { fp->Seek(0, SEEK_END); @@ -314,12 +331,7 @@ static cell AMX_NATIVE_CALL amx_fopen(AMX *amx, cell *params) if (*params / sizeof(cell) >= 3 && params[3] > 0) { - const char* pathID = get_amxstring(amx, params[4], 2, length); - - if (!strcmp(pathID, "ALL")) - { - pathID = nullptr; - } + const char* pathID = get_amxstring_null(amx, params[4], 2, length); fp = ValveFile::Open(file, flags, pathID); } @@ -388,16 +400,14 @@ static cell AMX_NATIVE_CALL amx_fwrite_blocks(AMX *amx, cell *params) } break; } - default: - { - if (size != BLOCK_INT) - { - size = BLOCK_INT; - } - } case BLOCK_INT: { read = fp->Write(data, sizeof(cell) * blocks); + break; + } + default: + { + return 0; } } @@ -429,7 +439,6 @@ static cell AMX_NATIVE_CALL amx_fwrite(AMX *amx, cell *params) short value = static_cast(data); return fp->Write(&value, sizeof(value)); } - default: case BLOCK_INT: { int value = static_cast(data); @@ -499,7 +508,6 @@ static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) return res; } case BLOCK_INT: - default: { int value; size_t res = fp->Read(&value, sizeof(value)); @@ -561,18 +569,15 @@ static cell AMX_NATIVE_CALL amx_fread_blocks(AMX *amx, cell *params) } break; } - default: - { - if (size != BLOCK_INT) - { - size = BLOCK_INT; - } - } case BLOCK_INT: { read = fp->Read(data, sizeof(cell) * blocks); break; } + default: + { + return 0; + } } return read / size; @@ -764,12 +769,7 @@ static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) if (numParams >= 4 && params[5] > 0) { const char* wildcardedPath = g_LibSys.PathFormat("%s%s*", path, (path[length - 1] != '/' && path[length - 1] != '\\') ? "/" : ""); - const char* pathID = get_amxstring(amx, params[6], 1, length); - - if (!strcmp(pathID, "ALL")) - { - pathID = nullptr; - } + const char* pathID = get_amxstring_null(amx, params[6], 1, length); static FileFindHandle_t handle; const char* pFirst = g_FileSystem->FindFirst(wildcardedPath, &handle, pathID); @@ -976,18 +976,13 @@ static cell AMX_NATIVE_CALL amx_mkdir(AMX *amx, cell *params) if (numParams >= 3 && params[3] > 0) { - const char* pathID = get_amxstring(amx, params[4], 1, length); + const char* pathID = get_amxstring_null(amx, params[4], 1, length); if (g_FileSystem->IsDirectory(path)) { return -1; } - if (!strcmp(pathID, "ALL")) - { - pathID = nullptr; - } - g_FileSystem->CreateDirHierarchy(path, pathID); if (g_FileSystem->IsDirectory(path)) diff --git a/amxmodx/string.cpp b/amxmodx/string.cpp index e9ca20f7..492c1d7a 100755 --- a/amxmodx/string.cpp +++ b/amxmodx/string.cpp @@ -176,6 +176,16 @@ char *get_amxstring(AMX *amx, cell amx_addr, int id, int& len) return buffer[id]; } +char *get_amxstring_null(AMX *amx, cell amx_addr, int id, int& len) +{ + if (get_amxaddr(amx, amx_addr) == g_plugins.findPluginFast(amx)->getNullStringOfs()) + { + return nullptr; + } + + return get_amxstring(amx, amx_addr, id, len); +} + void copy_amxmemory(cell* dest, cell* src, int len) { while (len--) diff --git a/compiler/libpc300/sc1.c b/compiler/libpc300/sc1.c index cb071acd..8230118c 100755 --- a/compiler/libpc300/sc1.c +++ b/compiler/libpc300/sc1.c @@ -1895,8 +1895,10 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst if (size > INT_MAX) error(105); /* overflow, exceeding capacity */ #endif +#if 0 /* We don't actually care */ if (ispublic) error(56,name); /* arrays cannot be public */ +#endif dim[numdim++]=(int)size; } /* while */ /* if this variable is never used (which can be detected only in the @@ -1936,7 +1938,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst sym->usage|=uDEFINE; } /* if */ if (ispublic) - sym->usage|=uPUBLIC; + sym->usage|=uPUBLIC|uREAD; if (fconst) sym->usage|=uCONST; if (fstock) diff --git a/compiler/libpc300/sc6.c b/compiler/libpc300/sc6.c index af5762ca..bd617926 100755 --- a/compiler/libpc300/sc6.c +++ b/compiler/libpc300/sc6.c @@ -619,7 +619,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) assert(sym->vclass==sGLOBAL); mainaddr=sym->addr; } /* if */ - } else if (sym->ident==iVARIABLE) { + } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) { if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) match=++numpubvars; } /* if */ @@ -794,7 +794,8 @@ SC_FUNC int assemble(FILE *fout,FILE *fin) /* write the public variables table */ count=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { + if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY) + && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { assert((sym->usage & uDEFINE)!=0); assert(sym->vclass==sGLOBAL); func.address=sym->addr; diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 23d9b05a..d2b4f681 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -39,7 +39,15 @@ */ #define MAX_PLAYERS 32 /* Maximum number of players AMX Mod X supports */ -public stock const MaxClients; /* Maximum number of players the server supports */ +/** + * Maximum number of players the server supports + */ +public stock const MaxClients; + +/** + * Pass this into certain functions to act as a C++ NULL + */ +public stock const NULL_STRING[1]; /** * The maximum buffer size required to store a clients name. diff --git a/plugins/include/file.inc b/plugins/include/file.inc index 2ac10e3e..c675bffc 100755 --- a/plugins/include/file.inc +++ b/plugins/include/file.inc @@ -149,7 +149,7 @@ native write_file(const file[], const text[], line = -1); * This can be used to delete files existing in the Valve * search path, rather than solely files existing directly * in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. * * @return 1 on success, 0 on failure or if file not immediately removed. */ @@ -204,7 +204,7 @@ native dir_exists(const dir[], bool:use_valve_fs = false); * the Valve search paths, rather than solely files * existing directly in the gamedir. * If used, flag option is ignored. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths * * @return If flag is FSOPT_BYTES_COUNT or use_valve_fs to true, the file size in bytes * If flag is FSOPT_LINES_COUNT, the number of lines in the file @@ -258,7 +258,7 @@ native file_size(const file[], flag = FSOPT_BYTES_COUNT, bool:use_valve_fs = fal * This can be used to finred files existing in valve * search paths, rather than solely files existing directly * in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths * * @return A file handle, or null if the file could not be opened. */ @@ -481,7 +481,7 @@ native rmdir(const path[]); * @param use_valve_fs If true, the Valve file system will be used instead * This can be used to create folders in the game's * Valve search paths, rather than directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for default + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default * In this case, mode is ignored * * @return 0 on success, -1 otherwise @@ -496,7 +496,7 @@ native mkdir(const dirname[], mode = FPERM_DIR_DEFAULT, bool:use_valve_fs = fals * This can be used to delete files existing in the Valve * search path, rather than solely files existing directly * in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths * * @return 1 on success, 0 on failure or if file not immediately removed */ @@ -515,7 +515,7 @@ native unlink(const filename[], bool:use_valve_fs = false, const valve_path_id[] * This can be used to find files existing in any of * the Valve search paths, rather than solely files * existing directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or "ALL" for all search paths. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. * * @return Handle to the directory, 0 otherwise */