diff --git a/core/logic/intercom.h b/core/logic/intercom.h index 2fa40410..78dd1eaf 100644 --- a/core/logic/intercom.h +++ b/core/logic/intercom.h @@ -83,6 +83,7 @@ class IFileSystem_Logic public: virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0; virtual const char *FindNext(FileFindHandle_t handle) = 0; + virtual bool FindIsDirectory(FileFindHandle_t handle) = 0; virtual void FindClose(FileFindHandle_t handle) = 0; virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0; virtual void Close(FileHandle_t file) = 0; @@ -90,6 +91,17 @@ public: virtual bool EndOfFile(FileHandle_t file) = 0; virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0; virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0; + virtual int Read(void* pOutput, int size, FileHandle_t file) = 0; + virtual int Write(void const* pInput, int size, FileHandle_t file) = 0; + virtual void Seek(FileHandle_t file, int post, int seekType) = 0; + virtual unsigned int Tell(FileHandle_t file) = 0; + virtual int FPrint(FileHandle_t file, const char *pData) = 0; + virtual void Flush(FileHandle_t file) = 0; + virtual bool IsOk(FileHandle_t file) = 0; + virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0; + virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0; + virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0; + virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0; }; namespace SourceMod diff --git a/core/logic/smn_filesystem.cpp b/core/logic/smn_filesystem.cpp index 82430e52..16f20e3c 100644 --- a/core/logic/smn_filesystem.cpp +++ b/core/logic/smn_filesystem.cpp @@ -55,9 +55,135 @@ #endif HandleType_t g_FileType; +HandleType_t g_ValveFileType; HandleType_t g_DirType; +HandleType_t g_ValveDirType; IChangeableForward *g_pLogHook = NULL; +enum class FSType +{ + STDIO, + VALVE, +}; + +class FSHelper +{ +public: + void SetFSType(FSType fstype) + { + _fstype = fstype; + } +public: + inline void *Open(const char *filename, const char *mode, const char *pathID) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->Open(filename, mode, pathID); + else + return fopen(filename, mode); + } + + inline int Read(void *pOut, int size, void *pFile) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->Read(pOut, size, (FileHandle_t)pFile); + else + return fread(pOut, 1, size, (FILE *)pFile) * size; + } + + inline char *ReadLine(char *pOut, int size, void *pFile) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->ReadLine(pOut, size, (FileHandle_t)pFile); + else + return fgets(pOut, size, (FILE *)pFile); + } + + inline size_t Write(const void *pData, int size, void *pFile) + { + if (_fstype == FSType::VALVE) + return (size_t)smcore.filesystem->Write(pData, size, (FileHandle_t)pFile); + else + return fwrite(pData, 1, size, (FILE *)pFile); + } + + inline void Seek(void *pFile, int pos, int seekType) + { + if (_fstype == FSType::VALVE) + smcore.filesystem->Seek((FileHandle_t)pFile, pos, seekType); + else + fseek((FILE *)pFile, pos, seekType); + } + + inline int Tell(void *pFile) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->Tell((FileHandle_t)pFile); + else + return ftell((FILE *)pFile); + } + + inline bool HasError(void *pFile) + { + if (_fstype == FSType::VALVE) + return !smcore.filesystem->IsOk((FileHandle_t)pFile); + else + return ferror((FILE *)pFile) != 0; + } + + inline void Close(void *pFile) + { + if (_fstype == FSType::VALVE) + smcore.filesystem->Close((FileHandle_t)pFile); + else + fclose((FILE *)pFile); + } + + inline bool Remove(const char *pFilePath, const char *pathID) + { + if (_fstype == FSType::VALVE) + { + if (!smcore.filesystem->FileExists(pFilePath, pathID)) + return false; + + smcore.filesystem->RemoveFile(pFilePath, pathID); + + if (smcore.filesystem->FileExists(pFilePath, pathID)) + return false; + + return true; + } + else + { + return unlink(pFilePath) == 0; + } + } + + inline bool EndOfFile(void *pFile) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->EndOfFile((FileHandle_t)pFile); + else + return feof((FILE *)pFile) != 0; + } + + inline bool Flush(void *pFile) + { + if (_fstype == FSType::VALVE) + return smcore.filesystem->Flush((FileHandle_t)pFile), true; + else + return fflush((FILE *)pFile) == 0; + } +private: + FSType _fstype; +}; + +struct ValveDirectory +{ + FileFindHandle_t hndl; + char szFirstPath[PLATFORM_MAX_PATH]; + bool bHandledFirstPath; +}; + class FileNatives : public SMGlobalClass, public IHandleTypeDispatch, @@ -70,7 +196,9 @@ public: virtual void OnSourceModAllInitialized() { g_FileType = handlesys->CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_ValveFileType = handlesys->CreateType("ValveFile", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_DirType = handlesys->CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_ValveDirType = handlesys->CreateType("ValveDirectory", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_pLogHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String); pluginsys->AddPluginsListener(this); } @@ -80,8 +208,12 @@ public: forwardsys->ReleaseForward(g_pLogHook); handlesys->RemoveType(g_DirType, g_pCoreIdent); handlesys->RemoveType(g_FileType, g_pCoreIdent); + handlesys->RemoveType(g_ValveFileType, g_pCoreIdent); + handlesys->RemoveType(g_ValveDirType, g_pCoreIdent); g_DirType = 0; g_FileType = 0; + g_ValveFileType = 0; + g_ValveDirType = 0; } virtual void OnHandleDestroy(HandleType_t type, void *object) { @@ -95,6 +227,17 @@ public: IDirectory *pDir = (IDirectory *)object; libsys->CloseDirectory(pDir); } + else if (type == g_ValveFileType) + { + FileHandle_t fp = (FileHandle_t) object; + smcore.filesystem->Close(fp); + } + else if (type == g_ValveDirType) + { + ValveDirectory *valveDir = (ValveDirectory *)object; + smcore.filesystem->FindClose(valveDir->hndl); + delete valveDir; + } } virtual void AddLogHook(IPluginFunction *pFunc) { @@ -127,23 +270,56 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } - - char realpath[PLATFORM_MAX_PATH]; - g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); - - IDirectory *pDir = libsys->OpenDirectory(realpath); - if (!pDir) + + Handle_t handle = 0; + + if (params[0] >= 2 && params[2]) { - return 0; + char wildcardedPath[PLATFORM_MAX_PATH]; + snprintf(wildcardedPath, sizeof(wildcardedPath), "%s*", path); + ValveDirectory *valveDir = new ValveDirectory; + + char *pathID; + if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + const char *pFirst = smcore.filesystem->FindFirstEx(wildcardedPath, pathID, &valveDir->hndl); + if (pFirst) + { + valveDir->bHandledFirstPath = false; + strncpy(valveDir->szFirstPath, pFirst, sizeof(valveDir->szFirstPath)); + } + else + { + valveDir->bHandledFirstPath = true; + } + + handle = handlesys->CreateHandle(g_ValveDirType, valveDir, pContext->GetIdentity(), g_pCoreIdent, NULL); } + else + { + char realpath[PLATFORM_MAX_PATH]; + g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); - return handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); + IDirectory *pDir = libsys->OpenDirectory(realpath); + if (!pDir) + { + return 0; + } + + handle = handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); + } + + return handle; } static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - IDirectory *pDir; + void *pTempDir; HandleError herr; HandleSecurity sec; int err; @@ -151,44 +327,90 @@ static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, (void **)&pDir)) - != HandleError_None) + if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, &pTempDir)) == HandleError_None) + { + IDirectory *pDir = (IDirectory *)pTempDir; + if (!pDir->MoreFiles()) + { + return 0; + } + + 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) + { + return pContext->ThrowNativeErrorEx(err, NULL); + } + + pDir->NextEntry(); + } + else if ((herr=handlesys->ReadHandle(hndl, g_ValveDirType, &sec, &pTempDir)) == HandleError_None) + { + ValveDirectory *valveDir = (ValveDirectory *)pTempDir; + + const char *pEntry = NULL; + if (!valveDir->bHandledFirstPath) + { + if (valveDir->szFirstPath[0]) + { + pEntry = valveDir->szFirstPath; + } + } + else + { + pEntry = smcore.filesystem->FindNext(valveDir->hndl); + } + + valveDir->bHandledFirstPath = true; + + // No more entries + if (!pEntry) + { + return 0; + } + + if ((err=pContext->StringToLocalUTF8(params[2], params[3], pEntry, NULL)) + != SP_ERROR_NONE) + { + return pContext->ThrowNativeErrorEx(err, NULL); + } + + cell_t *filetype; + if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if (smcore.filesystem->FindIsDirectory(valveDir->hndl)) + { + *filetype = 1; + } else { + *filetype = 2; + } + } + else { 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; + return 1; } static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) @@ -206,16 +428,40 @@ static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH]; - g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); - - FILE *pFile = fopen(realpath, mode); - if (!pFile) + Handle_t handle = 0; + HandleType_t handleType; + FSHelper fshelper; + const char *openpath; + char *pathID; + if (params[0] <= 2 || !params[3]) { - return 0; + handleType = g_FileType; + fshelper.SetFSType(FSType::STDIO); + + char realpath[PLATFORM_MAX_PATH]; + g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); + openpath = realpath; + } + else + { + if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + handleType = g_ValveFileType; + fshelper.SetFSType(FSType::VALVE); + openpath = name; } - return handlesys->CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL); + void *pFile = fshelper.Open(openpath, mode, pathID); + if (pFile) + { + handle = handlesys->CreateHandle(handleType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL); + } + + return handle; } static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) @@ -228,10 +474,29 @@ static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) return 0; } - char realpath[PLATFORM_MAX_PATH]; - g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); + FSHelper fshelper; + const char *filepath; + char *pathID; + if (params[0] < 2 || !params[2]) + { + fshelper.SetFSType(FSType::STDIO); + char realpath[PLATFORM_MAX_PATH]; + g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); + filepath = realpath; + } + else + { + if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + fshelper.SetFSType(FSType::VALVE); + filepath = name; + } - return (unlink(realpath)) ? 0 : 1; + return fshelper.Remove(filepath, pathID) ? 1 : 0; } static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) @@ -239,18 +504,12 @@ static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; int err; + void *pFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=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) { @@ -258,12 +517,22 @@ static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) return 0; } - if (fgets(buf, params[3], pFile) == NULL) + FSHelper fshelper; + + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) { - return 0; + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - return 1; + return fshelper.ReadLine(buf, params[3], pFile) == NULL ? 0 : 1; } static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params) @@ -271,18 +540,26 @@ static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; + void *pFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + FSHelper fshelper; + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - return (feof(pFile)) ? 1 : 0; + return fshelper.EndOfFile(pFile) ? 1 : 0; } static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params) @@ -290,18 +567,26 @@ static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; + void *pFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + FSHelper fshelper; + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - fseek(pFile, params[2], params[3]); + fshelper.Seek(pFile, params[2], params[3]); return 1; } @@ -311,18 +596,27 @@ static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; + void *pFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + FSHelper fshelper; + + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - return ftell(pFile); + return (cell_t)fshelper.Tell(pFile); } static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) @@ -337,7 +631,17 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) if (params[0] >= 2 && params[2] == 1) { - return smcore.filesystem->FileExists(name) ? 1 : 0; + char *pathID = NULL; + if (params[0] >= 3) + { + if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + } + + return smcore.filesystem->FileExists(name, pathID) ? 1 : 0; } char realpath[PLATFORM_MAX_PATH]; @@ -381,6 +685,19 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } + + if (params[0] >= 3 && params[3] == 1) + { + char *pathID; + if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + smcore.filesystem->RenameFile(oldpath, newpath, pathID); + return 1; + } char new_realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath); @@ -403,6 +720,18 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } + + if (params[0] >= 2 && params[2] == 1) + { + char *pathID; + if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + return smcore.filesystem->IsDirectory(name, pathID) ? 1 : 0; + } char realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); @@ -443,9 +772,19 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) if (params[0] >= 2 && params[2] == 1) { - if (smcore.filesystem->FileExists(name)) + char *pathID = NULL; + if (params[0] >= 3) { - return smcore.filesystem->Size(name); + if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return -1; + } + } + + if (smcore.filesystem->FileExists(name, pathID)) + { + return smcore.filesystem->Size(name, pathID); } else { @@ -508,9 +847,29 @@ static cell_t sm_SetFilePermissions(IPluginContext *pContext, const cell_t *para static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params) { char *name; - char realpath[PLATFORM_MAX_PATH]; - pContext->LocalToString(params[1], &name); + + if (params[0] >= 3 && params[3] == 1) + { + int err; + char *pathID; + if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE) + { + return pContext->ThrowNativeErrorEx(err, NULL); + } + + if (smcore.filesystem->IsDirectory(name, pathID)) + return 0; + + smcore.filesystem->CreateDirHierarchy(name, pathID); + + if (smcore.filesystem->IsDirectory(name, pathID)) + return 1; + + return 0; + } + + char realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); #if defined PLATFORM_WINDOWS @@ -541,19 +900,14 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; + void *pTempFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=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); @@ -562,8 +916,23 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) char buffer[2048]; int arg = 3; - smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); - fprintf(pFile, "%s\n", buffer); + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pTempFile)) == HandleError_None) + { + FILE *pFile = (FILE *) pTempFile; + smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); + fprintf(pFile, "%s\n", buffer); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pTempFile)) == HandleError_None) + { + FileHandle_t pFile = (FileHandle_t) pTempFile; + smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); + sprintf(buffer, "%s\n", buffer); + smcore.filesystem->FPrint(pFile, buffer); + } + else + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } return 1; } @@ -573,18 +942,26 @@ static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec; - FILE *pFile; + void *pFile; sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + FSHelper fshelper; + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - return (fflush(pFile) == 0) ? 1 : 0; + return fshelper.Flush(pFile) ? 1 : 0; } static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params) @@ -749,11 +1126,20 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); - FILE *pFile; size_t read = 0; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + void *pFile = NULL; + FSHelper fshelper; + + if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } @@ -765,21 +1151,21 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params) cell_t *data; pContext->LocalToPhysAddr(params[2], &data); - + if (params[4] == 4) { - read = fread(data, sizeof(cell_t), params[3], pFile); + read = fshelper.Read(data, sizeof(cell_t) * params[3], pFile); } else if (params[4] == 2) { uint16_t val; for (cell_t i = 0; i < params[3]; i++) { - if (fread(&val, sizeof(uint16_t), 1, pFile) != 1) + if (fshelper.Read(&val, sizeof(uint16_t), pFile) != 1) { break; } - data[read++] = val; + data[read += sizeof(uint16_t)] = val; } } else if (params[4] == 1) @@ -787,20 +1173,20 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params) uint8_t val; for (cell_t i = 0; i < params[3]; i++) { - if (fread(&val, sizeof(uint8_t), 1, pFile) != 1) + if (fshelper.Read(&val, sizeof(uint8_t), pFile) != 1) { break; } - data[read++] = val; + data[read += sizeof(uint8_t)] = val; } } - if (read != (size_t)params[3] && ferror(pFile) != 0) + if (read != ((size_t)params[3] * params[4]) && fshelper.HasError(pFile)) { return -1; } - return read; + return read / params[4]; } static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params) @@ -808,18 +1194,27 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); - FILE *pFile; + void *pFile; cell_t num_read = 0; - if ((herr=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); + FSHelper fshelper; + + if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + if (params[4] != -1) { if (size_t(params[4]) > size_t(params[3])) @@ -829,9 +1224,9 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params) params[3]); } - num_read = (cell_t)fread(buffer, 1, params[4], pFile); + num_read = (cell_t)fshelper.Read(buffer, params[4], pFile); - if (num_read != params[4] && ferror(pFile)) + if (num_read != params[4] && fshelper.HasError(pFile)) { return -1; } @@ -846,9 +1241,9 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params) { break; } - if (fread(&val, sizeof(val), 1, pFile) != 1) + if (fshelper.Read(&val, sizeof(val), pFile) != 1) { - if (ferror(pFile)) + if (fshelper.HasError(pFile)) { return -1; } @@ -877,10 +1272,18 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); - FILE *pFile; + void *pFile; + FSHelper fshelper; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } @@ -897,7 +1300,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params) if (params[4] == 4) { - if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3]) + if (fshelper.Write(data, sizeof(cell_t) * params[3], pFile) != (sizeof(cell_t) * (size_t)params[3])) { return 0; } @@ -906,7 +1309,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params) { for (cell_t i = 0; i < params[3]; i++) { - if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1) + if (fshelper.Write(&data[i], sizeof(int16_t), pFile) != sizeof(int16_t)) { return 0; } @@ -916,7 +1319,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params) { for (cell_t i = 0; i < params[3]; i++) { - if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1) + if (fshelper.Write(&data[i], sizeof(int8_t), pFile) != sizeof(int8_t)) { return 0; } @@ -931,10 +1334,18 @@ static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params) Handle_t hndl = static_cast(params[1]); HandleError herr; HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); - FILE *pFile; + void *pFile; + FSHelper fshelper; - if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) - != HandleError_None) + if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::STDIO); + } + else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None) + { + fshelper.SetFSType(FSType::VALVE); + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } @@ -949,7 +1360,7 @@ static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params) len++; } - return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0; + return (fshelper.Write(buffer, len, pFile) == len) ? 1 : 0; } static cell_t sm_AddGameLogHook(IPluginContext *pContext, const cell_t *params) diff --git a/core/logic_bridge.cpp b/core/logic_bridge.cpp index 13fba9fe..05b2aa8c 100644 --- a/core/logic_bridge.cpp +++ b/core/logic_bridge.cpp @@ -147,6 +147,10 @@ public: { return filesystem->FindNext(handle); } + bool FindIsDirectory(FileFindHandle_t handle) + { + return filesystem->FindIsDirectory(handle); + } void FindClose(FileFindHandle_t handle) { filesystem->FindClose(handle); @@ -175,6 +179,50 @@ public: { return filesystem->Size(pFileName, pPathID); } + int Read(void* pOutput, int size, FileHandle_t file) + { + return filesystem->Read(pOutput, size, file); + } + int Write(void const* pInput, int size, FileHandle_t file) + { + return filesystem->Write(pInput, size, file); + } + void Seek(FileHandle_t file, int pos, int seekType) + { + filesystem->Seek(file, pos, (FileSystemSeek_t) seekType); + } + unsigned int Tell(FileHandle_t file) + { + return filesystem->Tell(file); + } + int FPrint(FileHandle_t file, const char *pData) + { + return filesystem->FPrintf(file, "%s", pData); + } + void Flush(FileHandle_t file) + { + filesystem->Flush(file); + } + bool IsOk(FileHandle_t file) + { + return filesystem->IsOk(file); + } + void RemoveFile(const char *pRelativePath, const char *pathID) + { + filesystem->RemoveFile(pRelativePath, pathID); + } + void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID) + { + filesystem->RenameFile(pOldPath, pNewPath, pathID); + } + bool IsDirectory(const char *pFileName, const char *pathID) + { + return filesystem->IsDirectory(pFileName, pathID); + } + void CreateDirHierarchy(const char *path, const char *pathID) + { + filesystem->CreateDirHierarchy(path, pathID); + } }; static VFileSystem_Logic logic_filesystem; diff --git a/plugins/include/files.inc b/plugins/include/files.inc index c25ed8ac..ce9cbfbc 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -108,9 +108,14 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], * @note OpenDirectory() supports the "file://" notation. * * @param path Path to open. + * @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 NULL_STRING for all search paths. * @return A Handle to the directory, INVALID_HANDLE on open error. */ -native Handle:OpenDirectory(const String:path[]); +native Handle:OpenDirectory(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME"); /** * Reads the current directory entry as a local filename, then moves to the next file. @@ -136,17 +141,27 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type= * * @param file 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 find 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 NULL_STRING for all search paths. * @return A Handle to the file, INVALID_HANDLE on open error. */ -native Handle:OpenFile(const String:file[], const String:mode[]); +native Handle:OpenFile(const String:file[], const String:mode[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME"); /** * Deletes a file. * * @param path Path of the file to delete. - * @return True on success, false otherwise. + * @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 NULL_STRING for all search paths. + * @return True on success, false on failure or if file not immediately removed. */ -native bool:DeleteFile(const String:path[]); +native bool:DeleteFile(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH"); /** * Reads a line from a text file. @@ -304,28 +319,38 @@ native FilePosition(Handle:file); * @param path 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 GAME search paths, rather than solely files + * 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 NULL_STRING for all search paths. * @return True if the file exists, false otherwise. */ -native bool:FileExists(const String:path[], bool:use_valve_fs=false); +native bool:FileExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME"); /** * Renames a file. * * @param newpath New path to the file. * @param oldpath Path to the existing file. - * @return True on success, false otherwise. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to rename files 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 NULL_STRING for all search paths. + * @return True on success or use_valve_fs specified, false otherwise. */ -native bool:RenameFile(const String:newpath[], const String:oldpath[]); +native bool:RenameFile(const String:newpath[], const String:oldpath[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH"); /** * Checks if a directory exists. * * @param path 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. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. * @return True if the directory exists, false otherwise. */ -native bool:DirExists(const String:path[]); +native bool:DirExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME"); /** * Get the file size in bytes. @@ -333,18 +358,20 @@ native bool:DirExists(const String:path[]); * @param path 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 GAME search paths, rather than solely files + * 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 NULL_STRING for all search paths. * @return File size in bytes, -1 if file not found. */ -native FileSize(const String:path[], bool:use_valve_fs=false); +native FileSize(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME"); /** * Flushes a file's buffered output; any buffered output * is immediately written to the file. * * @param file Handle to the file. - * @return True on success, false on failure. + * @return True on success or use_valve_fs specified with OpenFile, + * otherwise false on failure. */ native FlushFile(Handle:file); @@ -373,8 +400,13 @@ native bool:RemoveDir(const String:path[]); * @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 NULL_STRING for default. + * In this case, mode is ignored. */ -native bool:CreateDirectory(const String:path[], mode); +native bool:CreateDirectory(const String:path[], mode, bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH"); /** * Changes a file or directories permissions.