3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
33 #include "sm_globals.h"
34 #include "HandleSys.h"
35 #include "LibrarySys.h"
36 #include "sm_stringutil.h"
38 #include "PluginSys.h"
39 #include "sourcemm_api.h"
41 HandleType_t g_FileType;
42 HandleType_t g_DirType;
46 public IHandleTypeDispatch
49 virtual void OnSourceModAllInitialized()
51 g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
52 g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
54 virtual void OnSourceModShutdown()
56 g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
57 g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
61 virtual void OnHandleDestroy(HandleType_t type, void *object)
63 if (type == g_FileType)
65 FILE *fp = (FILE *)object;
67 } else if (type == g_DirType) {
68 IDirectory *pDir = (IDirectory *)object;
69 g_LibSys.CloseDirectory(pDir);
74 static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
78 if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
80 pContext->ThrowNativeErrorEx(err, NULL);
84 char realpath[PLATFORM_MAX_PATH];
85 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
87 IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
93 return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
96 static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
98 Handle_t hndl = static_cast<Handle_t>(params[1]);
105 sec.pIdentity = g_pCoreIdent;
107 if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
110 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
113 if (!pDir->MoreFiles())
119 if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
121 pContext->ThrowNativeErrorEx(err, NULL);
125 if (pDir->IsEntryDirectory())
128 } else if (pDir->IsEntryFile()) {
134 const char *path = pDir->GetEntryName();
135 if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
138 pContext->ThrowNativeErrorEx(err, NULL);
147 static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
151 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
153 pContext->ThrowNativeErrorEx(err, NULL);
156 if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
158 pContext->ThrowNativeErrorEx(err, NULL);
162 char realpath[PLATFORM_MAX_PATH];
163 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
165 FILE *pFile = fopen(realpath, mode);
171 return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
174 static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
178 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
180 pContext->ThrowNativeErrorEx(err, NULL);
184 char realpath[PLATFORM_MAX_PATH];
185 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
187 return (unlink(realpath)) ? 0 : 1;
190 static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
192 Handle_t hndl = static_cast<Handle_t>(params[1]);
199 sec.pIdentity = g_pCoreIdent;
201 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
204 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
208 if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
210 pContext->ThrowNativeErrorEx(err, NULL);
214 if (fgets(buf, params[3], pFile) == NULL)
222 static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
224 Handle_t hndl = static_cast<Handle_t>(params[1]);
230 sec.pIdentity = g_pCoreIdent;
232 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
235 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
238 return (feof(pFile)) ? 1 : 0;
241 static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
243 Handle_t hndl = static_cast<Handle_t>(params[1]);
249 sec.pIdentity = g_pCoreIdent;
251 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
254 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
257 fseek(pFile, params[2], params[3]);
262 static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
264 Handle_t hndl = static_cast<Handle_t>(params[1]);
270 sec.pIdentity = g_pCoreIdent;
272 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
275 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
281 static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
285 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
287 pContext->ThrowNativeErrorEx(err, NULL);
291 char realpath[PLATFORM_MAX_PATH];
292 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
293 #ifdef PLATFORM_WINDOWS
295 if (_stat(realpath, &s) != 0)
299 if (s.st_mode & S_IFREG)
304 #elif defined PLATFORM_POSIX
306 if (stat(realpath, &s) != 0)
310 if (S_ISREG(s.st_mode))
318 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
320 char *newpath, *oldpath;
322 if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
324 pContext->ThrowNativeErrorEx(err, NULL);
327 if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
329 pContext->ThrowNativeErrorEx(err, NULL);
333 char new_realpath[PLATFORM_MAX_PATH];
334 g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
335 char old_realpath[PLATFORM_MAX_PATH];
336 g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
338 #ifdef PLATFORM_WINDOWS
339 return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
340 #elif defined PLATFORM_POSIX
341 return (rename(old_realpath, new_realpath)) ? 0 : 1;
345 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
349 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
351 pContext->ThrowNativeErrorEx(err, NULL);
355 char realpath[PLATFORM_MAX_PATH];
356 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
357 #ifdef PLATFORM_WINDOWS
359 if (_stat(realpath, &s) != 0)
363 if (s.st_mode & S_IFDIR)
368 #elif defined PLATFORM_POSIX
370 if (stat(realpath, &s) != 0)
374 if (S_ISDIR(s.st_mode))
382 static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
386 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
388 pContext->ThrowNativeErrorEx(err, NULL);
392 char realpath[PLATFORM_MAX_PATH];
393 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
394 #ifdef PLATFORM_WINDOWS
396 if (_stat(realpath, &s) != 0)
400 if (s.st_mode & S_IFREG)
402 return static_cast<cell_t>(s.st_size);
405 #elif defined PLATFORM_POSIX
407 if (stat(realpath, &s) != 0)
411 if (S_ISREG(s.st_mode))
413 return static_cast<cell_t>(s.st_size);
419 static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
423 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
425 pContext->ThrowNativeErrorEx(err, NULL);
429 char realpath[PLATFORM_MAX_PATH];
430 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
432 return (rmdir(realpath)) ? 0 : 1;
435 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
437 Handle_t hndl = static_cast<Handle_t>(params[1]);
443 sec.pIdentity = g_pCoreIdent;
445 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
448 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
453 if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
455 pContext->ThrowNativeErrorEx(err, NULL);
461 atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
462 fprintf(pFile, "%s\n", buffer);
467 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
469 Handle_t hndl = static_cast<Handle_t>(params[1]);
475 sec.pIdentity = g_pCoreIdent;
477 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
480 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
483 return (fflush(pFile) == 0) ? 1 : 0;
486 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
488 char path[PLATFORM_MAX_PATH], *fmt, *buffer;
490 pContext->LocalToString(params[2], &buffer);
491 pContext->LocalToString(params[4], &fmt);
493 atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
495 return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
498 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
500 g_SourceMod.SetGlobalTarget(LANG_SERVER);
503 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
505 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
510 if (len >= sizeof(buffer)-2)
515 buffer[len++] = '\n';
519 engine->LogPrint(buffer);
524 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
526 g_SourceMod.SetGlobalTarget(LANG_SERVER);
529 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
531 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
536 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
537 g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
542 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
544 g_SourceMod.SetGlobalTarget(LANG_SERVER);
547 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
549 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
554 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
555 g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
560 static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
564 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
566 pContext->ThrowNativeErrorEx(err, NULL);
571 char realpath[PLATFORM_MAX_PATH];
572 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
574 if (!g_LibSys.FileTime(realpath, (FileTimeType)params[2], &time_val))
579 return (cell_t)time_val;
582 static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
584 Handle_t hndl = static_cast<Handle_t>(params[1]);
590 sec.pIdentity = g_pCoreIdent;
592 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
595 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
599 g_SourceMod.SetGlobalTarget(LANG_SERVER);
600 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
602 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
607 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
608 g_Logger.LogToOpenFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
613 static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
615 Handle_t hndl = static_cast<Handle_t>(params[1]);
621 sec.pIdentity = g_pCoreIdent;
623 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
626 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
630 g_SourceMod.SetGlobalTarget(LANG_SERVER);
631 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
633 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
638 g_Logger.LogToOpenFile(pFile, "%s", buffer);
643 REGISTER_NATIVES(filesystem)
645 {"OpenDirectory", sm_OpenDirectory},
646 {"ReadDirEntry", sm_ReadDirEntry},
647 {"OpenFile", sm_OpenFile},
648 {"DeleteFile", sm_DeleteFile},
649 {"ReadFileLine", sm_ReadFileLine},
650 {"IsEndOfFile", sm_IsEndOfFile},
651 {"FileSeek", sm_FileSeek},
652 {"FilePosition", sm_FilePosition},
653 {"FileExists", sm_FileExists},
654 {"RenameFile", sm_RenameFile},
655 {"DirExists", sm_DirExists},
656 {"FileSize", sm_FileSize},
657 {"RemoveDir", sm_RemoveDir},
658 {"WriteFileLine", sm_WriteFileLine},
659 {"BuildPath", sm_BuildPath},
660 {"LogToGame", sm_LogToGame},
661 {"LogMessage", sm_LogMessage},
662 {"LogError", sm_LogError},
663 {"FlushFile", sm_FlushFile},
664 {"GetFileTime", sm_GetFileTime},
665 {"LogToOpenFile", sm_LogToOpenFile},
666 {"LogToOpenFileEx", sm_LogToOpenFileEx},