251cced1f8
Various minor things done to project files Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way) Updated regex project file and makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
964 lines
23 KiB
C++
964 lines
23 KiB
C++
/**
|
|
* vim: set ts=4 :
|
|
* =============================================================================
|
|
* SourceMod
|
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
* =============================================================================
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
* or <http://www.sourcemod.net/license.php>.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#include <sys/stat.h>
|
|
#include "sm_globals.h"
|
|
#include "HandleSys.h"
|
|
#include "LibrarySys.h"
|
|
#include "sm_stringutil.h"
|
|
#include "Logger.h"
|
|
#include "PluginSys.h"
|
|
#include "sourcemm_api.h"
|
|
#include "ForwardSys.h"
|
|
|
|
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
|
|
|
|
HandleType_t g_FileType;
|
|
HandleType_t g_DirType;
|
|
IChangeableForward *g_pLogHook = NULL;
|
|
|
|
class FileNatives :
|
|
public SMGlobalClass,
|
|
public IHandleTypeDispatch,
|
|
public IPluginsListener
|
|
{
|
|
public:
|
|
FileNatives()
|
|
{
|
|
m_bIsLoggingHooked = false;
|
|
}
|
|
virtual void OnSourceModAllInitialized()
|
|
{
|
|
g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
|
g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
|
g_pLogHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String);
|
|
g_PluginSys.AddPluginsListener(this);
|
|
}
|
|
virtual void OnSourceModShutdown()
|
|
{
|
|
g_PluginSys.RemovePluginsListener(this);
|
|
if (m_bIsLoggingHooked)
|
|
{
|
|
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
|
|
m_bIsLoggingHooked = false;
|
|
}
|
|
g_Forwards.ReleaseForward(g_pLogHook);
|
|
g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
|
|
g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
|
|
g_DirType = 0;
|
|
g_FileType = 0;
|
|
}
|
|
virtual void OnHandleDestroy(HandleType_t type, void *object)
|
|
{
|
|
if (type == g_FileType)
|
|
{
|
|
FILE *fp = (FILE *)object;
|
|
fclose(fp);
|
|
}
|
|
else if (type == g_DirType)
|
|
{
|
|
IDirectory *pDir = (IDirectory *)object;
|
|
g_LibSys.CloseDirectory(pDir);
|
|
}
|
|
}
|
|
virtual void OnPluginDestroyed(IPlugin *plugin)
|
|
{
|
|
if (m_bIsLoggingHooked && g_pLogHook->GetFunctionCount() == 0)
|
|
{
|
|
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
|
|
m_bIsLoggingHooked = false;
|
|
}
|
|
}
|
|
virtual void AddLogHook(IPluginFunction *pFunc)
|
|
{
|
|
if (!m_bIsLoggingHooked)
|
|
{
|
|
SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
|
|
m_bIsLoggingHooked = true;
|
|
}
|
|
|
|
g_pLogHook->AddFunction(pFunc);
|
|
}
|
|
virtual void RemoveLogHook(IPluginFunction *pFunc)
|
|
{
|
|
g_pLogHook->RemoveFunction(pFunc);
|
|
|
|
if (m_bIsLoggingHooked && g_pLogHook->GetFunctionCount() == 0)
|
|
{
|
|
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
|
|
m_bIsLoggingHooked = false;
|
|
}
|
|
}
|
|
virtual void LogPrint(const char *msg)
|
|
{
|
|
cell_t result;
|
|
|
|
result = 0;
|
|
|
|
g_in_game_log_hook = true;
|
|
g_pLogHook->PushString(msg);
|
|
g_pLogHook->Execute(&result);
|
|
g_in_game_log_hook = false;
|
|
|
|
if (result >= Pl_Handled)
|
|
{
|
|
RETURN_META(MRES_SUPERCEDE);
|
|
}
|
|
}
|
|
private:
|
|
bool m_bIsLoggingHooked;
|
|
} s_FileNatives;
|
|
|
|
static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *path;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
|
|
|
|
IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
|
|
if (!pDir)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
|
}
|
|
|
|
static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
IDirectory *pDir;
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
int err;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
if (!pDir->MoreFiles())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
cell_t *filetype;
|
|
if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (pDir->IsEntryDirectory())
|
|
{
|
|
*filetype = 1;
|
|
} else if (pDir->IsEntryFile()) {
|
|
*filetype = 2;
|
|
} else {
|
|
*filetype = 0;
|
|
}
|
|
|
|
const char *path = pDir->GetEntryName();
|
|
if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
|
|
!= SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
pDir->NextEntry();
|
|
|
|
return true;
|
|
}
|
|
|
|
static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name, *mode;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
|
|
FILE *pFile = fopen(realpath, mode);
|
|
if (!pFile)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
|
}
|
|
|
|
static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
|
|
return (unlink(realpath)) ? 0 : 1;
|
|
}
|
|
|
|
static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
int err;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char *buf;
|
|
if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (fgets(buf, params[3], pFile) == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
return (feof(pFile)) ? 1 : 0;
|
|
}
|
|
|
|
static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
fseek(pFile, params[2], params[3]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
return ftell(pFile);
|
|
}
|
|
|
|
static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (params[0] >= 2 && params[2] == 1)
|
|
{
|
|
return basefilesystem->FileExists(name) ? 1 : 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
#ifdef PLATFORM_WINDOWS
|
|
struct _stat s;
|
|
if (_stat(realpath, &s) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (s.st_mode & S_IFREG)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#elif defined PLATFORM_POSIX
|
|
struct stat s;
|
|
if (stat(realpath, &s) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (S_ISREG(s.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *newpath, *oldpath;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char new_realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
|
|
char old_realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
|
|
|
|
#ifdef PLATFORM_WINDOWS
|
|
return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
|
|
#elif defined PLATFORM_POSIX
|
|
return (rename(old_realpath, new_realpath)) ? 0 : 1;
|
|
#endif
|
|
}
|
|
|
|
static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
#ifdef PLATFORM_WINDOWS
|
|
struct _stat s;
|
|
if (_stat(realpath, &s) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (s.st_mode & S_IFDIR)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#elif defined PLATFORM_POSIX
|
|
struct stat s;
|
|
if (stat(realpath, &s) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (S_ISDIR(s.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return -1;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
#ifdef PLATFORM_WINDOWS
|
|
struct _stat s;
|
|
if (_stat(realpath, &s) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if (s.st_mode & S_IFREG)
|
|
{
|
|
return static_cast<cell_t>(s.st_size);
|
|
}
|
|
return -1;
|
|
#elif defined PLATFORM_POSIX
|
|
struct stat s;
|
|
if (stat(realpath, &s) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if (S_ISREG(s.st_mode))
|
|
{
|
|
return static_cast<cell_t>(s.st_size);
|
|
}
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
|
|
return (rmdir(realpath)) ? 0 : 1;
|
|
}
|
|
|
|
static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char *fmt;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
char buffer[2048];
|
|
int arg = 3;
|
|
atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
|
|
fprintf(pFile, "%s\n", buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
return (fflush(pFile) == 0) ? 1 : 0;
|
|
}
|
|
|
|
static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char path[PLATFORM_MAX_PATH], *fmt, *buffer;
|
|
int arg = 5;
|
|
pContext->LocalToString(params[2], &buffer);
|
|
pContext->LocalToString(params[4], &fmt);
|
|
|
|
atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
|
|
|
|
return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
|
|
}
|
|
|
|
static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
|
|
|
char buffer[1024];
|
|
size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
|
|
|
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (len >= sizeof(buffer)-2)
|
|
{
|
|
buffer[1022] = '\n';
|
|
buffer[1023] = '\0';
|
|
} else {
|
|
buffer[len++] = '\n';
|
|
buffer[len] = '\0';
|
|
}
|
|
|
|
Engine_LogPrintWrapper(buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
|
|
|
char buffer[1024];
|
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
|
|
|
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
|
|
g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
|
|
|
char buffer[1024];
|
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
|
|
|
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
|
|
g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
char *name;
|
|
int err;
|
|
if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
|
|
{
|
|
pContext->ThrowNativeErrorEx(err, NULL);
|
|
return 0;
|
|
}
|
|
|
|
time_t time_val;
|
|
char realpath[PLATFORM_MAX_PATH];
|
|
g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
|
|
|
if (!g_LibSys.FileTime(realpath, (FileTimeType)params[2], &time_val))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return (cell_t)time_val;
|
|
}
|
|
|
|
static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char buffer[2048];
|
|
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
|
|
|
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
|
|
g_Logger.LogToOpenFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec;
|
|
FILE *pFile;
|
|
|
|
sec.pOwner = NULL;
|
|
sec.pIdentity = g_pCoreIdent;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char buffer[2048];
|
|
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
|
|
|
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
g_Logger.LogToOpenFile(pFile, "%s", buffer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
|
FILE *pFile;
|
|
size_t read = 0;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
if (params[4] != 1 && params[4] != 2 && params[4] != 4)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
|
|
}
|
|
|
|
cell_t *data;
|
|
pContext->LocalToPhysAddr(params[2], &data);
|
|
|
|
if (params[4] == 4)
|
|
{
|
|
read = fread(data, sizeof(cell_t), params[3], pFile);
|
|
}
|
|
else if (params[4] == 2)
|
|
{
|
|
int16_t val;
|
|
for (cell_t i = 0; i < params[3]; i++)
|
|
{
|
|
if (fread(&val, sizeof(int16_t), 1, pFile) != 1)
|
|
{
|
|
break;
|
|
}
|
|
data[read++] = val;
|
|
}
|
|
}
|
|
else if (params[4] == 1)
|
|
{
|
|
int8_t val;
|
|
for (cell_t i = 0; i < params[3]; i++)
|
|
{
|
|
if (fread(&val, sizeof(int8_t), 1, pFile) != 1)
|
|
{
|
|
break;
|
|
}
|
|
data[read++] = val;
|
|
}
|
|
}
|
|
|
|
if (read != (size_t)params[3] && ferror(pFile) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return read;
|
|
}
|
|
|
|
static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
|
FILE *pFile;
|
|
cell_t num_read = 0;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char *buffer;
|
|
pContext->LocalToString(params[2], &buffer);
|
|
|
|
char val;
|
|
while (1)
|
|
{
|
|
/* If we're in stop mode, break as soon as the buffer is full. */
|
|
if (params[4] && (params[3] == 0 || num_read >= params[3] - 1))
|
|
{
|
|
break;
|
|
}
|
|
if (fread(&val, sizeof(val), 1, pFile) != 1)
|
|
{
|
|
if (ferror(pFile))
|
|
{
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
if (val == '\0')
|
|
{
|
|
break;
|
|
}
|
|
if (params[3] > 0 && num_read < params[3] - 1)
|
|
{
|
|
buffer[num_read++] = val;
|
|
}
|
|
}
|
|
|
|
if (params[3] > 0)
|
|
{
|
|
buffer[num_read] = '\0';
|
|
}
|
|
|
|
return num_read;
|
|
}
|
|
|
|
static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
|
FILE *pFile;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
cell_t *data;
|
|
pContext->LocalToPhysAddr(params[2], &data);
|
|
|
|
if (params[4] != 1 && params[4] != 2 && params[4] != 4)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
|
|
}
|
|
|
|
/* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */
|
|
|
|
if (params[4] == 4)
|
|
{
|
|
if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if (params[4] == 2)
|
|
{
|
|
for (cell_t i = 0; i < params[3]; i++)
|
|
{
|
|
if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if (params[4] == 1)
|
|
{
|
|
for (cell_t i = 0; i < params[3]; i++)
|
|
{
|
|
if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
|
HandleError herr;
|
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
|
FILE *pFile;
|
|
|
|
if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
|
|
!= HandleError_None)
|
|
{
|
|
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
|
|
}
|
|
|
|
char *buffer;
|
|
pContext->LocalToString(params[2], &buffer);
|
|
|
|
size_t len = strlen(buffer);
|
|
|
|
if (params[3])
|
|
{
|
|
len++;
|
|
}
|
|
|
|
return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
|
|
}
|
|
|
|
static cell_t sm_AddGameLogHook(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
IPluginFunction *pFunction;
|
|
|
|
if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
|
|
{
|
|
return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
|
|
}
|
|
|
|
s_FileNatives.AddLogHook(pFunction);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell_t sm_RemoveGameLogHook(IPluginContext *pContext, const cell_t *params)
|
|
{
|
|
IPluginFunction *pFunction;
|
|
|
|
if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
|
|
{
|
|
return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
|
|
}
|
|
|
|
s_FileNatives.RemoveLogHook(pFunction);
|
|
|
|
return 1;
|
|
}
|
|
|
|
REGISTER_NATIVES(filesystem)
|
|
{
|
|
{"OpenDirectory", sm_OpenDirectory},
|
|
{"ReadDirEntry", sm_ReadDirEntry},
|
|
{"OpenFile", sm_OpenFile},
|
|
{"DeleteFile", sm_DeleteFile},
|
|
{"ReadFileLine", sm_ReadFileLine},
|
|
{"IsEndOfFile", sm_IsEndOfFile},
|
|
{"FileSeek", sm_FileSeek},
|
|
{"FilePosition", sm_FilePosition},
|
|
{"FileExists", sm_FileExists},
|
|
{"RenameFile", sm_RenameFile},
|
|
{"DirExists", sm_DirExists},
|
|
{"FileSize", sm_FileSize},
|
|
{"RemoveDir", sm_RemoveDir},
|
|
{"WriteFileLine", sm_WriteFileLine},
|
|
{"BuildPath", sm_BuildPath},
|
|
{"LogToGame", sm_LogToGame},
|
|
{"LogMessage", sm_LogMessage},
|
|
{"LogError", sm_LogError},
|
|
{"FlushFile", sm_FlushFile},
|
|
{"GetFileTime", sm_GetFileTime},
|
|
{"LogToOpenFile", sm_LogToOpenFile},
|
|
{"LogToOpenFileEx", sm_LogToOpenFileEx},
|
|
{"ReadFile", sm_ReadFile},
|
|
{"ReadFileString", sm_ReadFileString},
|
|
{"WriteFile", sm_WriteFile},
|
|
{"WriteFileString", sm_WriteFileString},
|
|
{"AddGameLogHook", sm_AddGameLogHook},
|
|
{"RemoveGameLogHook", sm_RemoveGameLogHook},
|
|
{NULL, NULL},
|
|
};
|