diff --git a/r5dev/filesystem/CMakeLists.txt b/r5dev/filesystem/CMakeLists.txt index a226c117..2c131e6d 100644 --- a/r5dev/filesystem/CMakeLists.txt +++ b/r5dev/filesystem/CMakeLists.txt @@ -18,3 +18,20 @@ add_sources( SOURCE_GROUP "Public" end_sources() target_include_directories( ${PROJECT_NAME} PRIVATE "${ENGINE_SOURCE_DIR}/tier0/" "${ENGINE_SOURCE_DIR}/tier1/" ) + +add_module( "lib" "filesystem_std" "vpc" ${FOLDER_CONTEXT} TRUE TRUE ) + +start_sources() + +add_sources( SOURCE_GROUP "Private" + "filesystem_std.cpp" + "filesystem_std.h" +) + +add_sources( SOURCE_GROUP "Public" + "${ENGINE_SOURCE_DIR}/public/ifilesystem.h" +) + +end_sources() + +target_include_directories( ${PROJECT_NAME} PRIVATE "${ENGINE_SOURCE_DIR}/tier0/" "${ENGINE_SOURCE_DIR}/tier1/" ) diff --git a/r5dev/filesystem/filesystem.cpp b/r5dev/filesystem/filesystem.cpp index 43e85eb8..b48a491f 100644 --- a/r5dev/filesystem/filesystem.cpp +++ b/r5dev/filesystem/filesystem.cpp @@ -4,4 +4,9 @@ /////////////////////////////////////////////////////////////////////////////// CFileSystem_Stdio** g_pFullFileSystem = nullptr; -CFileSystem_Stdio* g_pFileSystem_Stdio = nullptr; \ No newline at end of file +CFileSystem_Stdio* g_pFileSystem_Stdio = nullptr; + +CFileSystem_Stdio* FileSystem() +{ + return (*g_pFullFileSystem); +} diff --git a/r5dev/filesystem/filesystem.h b/r5dev/filesystem/filesystem.h index 577603ff..db78171d 100644 --- a/r5dev/filesystem/filesystem.h +++ b/r5dev/filesystem/filesystem.h @@ -36,10 +36,7 @@ extern CFileSystem_Stdio* g_pFileSystem_Stdio; //----------------------------------------------------------------------------- // Singleton FileSystem //----------------------------------------------------------------------------- -inline CFileSystem_Stdio* FileSystem() -{ - return (*g_pFullFileSystem); -} +extern CFileSystem_Stdio* FileSystem(); /////////////////////////////////////////////////////////////////////////////// class VFileSystem_Stdio : public IDetour diff --git a/r5dev/filesystem/filesystem_std.cpp b/r5dev/filesystem/filesystem_std.cpp new file mode 100644 index 00000000..f7229605 --- /dev/null +++ b/r5dev/filesystem/filesystem_std.cpp @@ -0,0 +1,354 @@ +//=============================================================================// +// +// Purpose: FileSystem class utilizing standard libraries. +// ---------------------------------------------------------------------------- +// NOTE: use this for standalone/tools projects +//=============================================================================// +#include "filesystem_std.h" + +ssize_t CBaseFileSystem::Read(void* pOutput, ssize_t size, FileHandle_t file) +{ + return fread(pOutput, size, 1, (FILE*)file); +} + +ssize_t CBaseFileSystem::Write(void const* pInput, ssize_t size, FileHandle_t file) +{ + return fwrite(pInput, size, 1, (FILE*)file); +} + +FileHandle_t CBaseFileSystem::Open(const char* pFileName, const char* pOptions, const char* pPathID, int64_t unknown) +{ + NOTE_UNUSED(unknown); + + char fullPath[1024]; + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + return (FileHandle_t)fopen(fullPath, pOptions); +} + +void CBaseFileSystem::Close(FileHandle_t file) +{ + fclose((FILE*)file); +} + +void CBaseFileSystem::Seek(FileHandle_t file, ssize_t pos, FileSystemSeek_t seekType) +{ + fseek((FILE*)file, (long)pos, seekType); +} + +ptrdiff_t CBaseFileSystem::Tell(FileHandle_t file) +{ + return ftell((FILE*)file); +} + +ssize_t CBaseFileSystem::FSize(const char* pFileName, const char* pPathID) +{ + char fullPath[1024]; + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + FILE* fp = fopen(fullPath, "rb"); + if (!fp) + return 0; + + fseek(fp, 0, SEEK_END); + ptrdiff_t size = Tell(fp); + + fclose(fp); + return size; +} + +ssize_t CBaseFileSystem::Size(FileHandle_t file) +{ + fseek((FILE*)file, 0, SEEK_END); + ptrdiff_t size = Tell((FILE*)file); + + fseek((FILE*)file, 0, SEEK_SET); + return size; +} + +void CBaseFileSystem::Flush(FileHandle_t file) +{ + fflush((FILE*)file); +} + +bool CBaseFileSystem::Precache(const char* pFileName, const char* pPathID) +{ + NOTE_UNUSED(pPathID); + NOTE_UNUSED(pFileName); + return true; +} + +bool CBaseFileSystem::FileExists(const char* pFileName, const char* pPathID) +{ + char fullPath[1024]; + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + FILE* fp = fopen(fullPath, "rb"); + if (!fp) + return false; + + fclose(fp); + return true; +} + +bool CBaseFileSystem::IsFileWritable(char const* pFileName, const char* pPathID) +{ + char fullPath[1024]; + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + FILE* fp = fopen(fullPath, "a"); + if (!fp) + return false; + + fclose(fp); + return true; +} + +bool CBaseFileSystem::SetFileWritable(char const* pFileName, bool writable, const char* pPathID) +{ + NOTE_UNUSED(pPathID); + NOTE_UNUSED(writable); + NOTE_UNUSED(pFileName); + return true; +} + +long long CBaseFileSystem::GetFileTime(const char* pFileName, const char* pPathID) +{ + char fullPath[1024]; + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + struct stat result; + + // On POSIX systems, st_mtime is the time of last + // modification in seconds since the epoch. + if (stat(fullPath, &result) == NULL) + return (long)result.st_mtime; + else + return -1; +} + +bool CBaseFileSystem::GetOptimalIOConstraints(FileHandle_t hFile, uint64_t* pOffsetAlign, uint64_t* pSizeAlign, uint64_t* pBufferAlign) +{ + if (pOffsetAlign) + *pOffsetAlign = 1; + if (pSizeAlign) + *pSizeAlign = 1; + if (pBufferAlign) + *pBufferAlign = 1; + return false; +} + +bool CBaseFileSystem::ReadToBuffer(FileHandle_t hFile, CUtlBuffer& buf, ssize_t nMaxBytes, FSAllocFunc_t pfnAlloc) +{ + ssize_t nBytesToRead = Size(hFile); + if (nBytesToRead == 0) + { + // no data in file + return true; + } + + if (nMaxBytes > 0) + { + // can't read more than file has + nBytesToRead = MIN(nMaxBytes, nBytesToRead); + } + + ssize_t nBytesRead = 0; + ptrdiff_t nBytesOffset = 0; + + ptrdiff_t iStartPos = Tell(hFile); + + if (nBytesToRead != 0) + { + ssize_t nBytesDestBuffer = nBytesToRead; + uint64_t nSizeAlign = 0, nBufferAlign = 0, nOffsetAlign = 0; + + bool bBinary = !(buf.IsText() && !buf.ContainsCRLF()); + + if (bBinary && !IsPosix() && !buf.IsExternallyAllocated() && !pfnAlloc && + (buf.TellPut() == 0) && (buf.TellGet() == 0) && (iStartPos % 4 == 0) && + GetOptimalIOConstraints(hFile, &nOffsetAlign, &nSizeAlign, &nBufferAlign)) + { + // correct conditions to allow an optimal read + if (iStartPos % nOffsetAlign != 0) + { + // move starting position back to nearest alignment + nBytesOffset = (iStartPos % nOffsetAlign); + Assert((iStartPos - nBytesOffset) % nOffsetAlign == 0); + Seek(hFile, -nBytesOffset, FILESYSTEM_SEEK_CURRENT); + + // going to read from aligned start, increase target buffer size by offset alignment + nBytesDestBuffer += nBytesOffset; + } + + // snap target buffer size to its size alignment + // add additional alignment slop for target pointer adjustment + nBytesDestBuffer = AlignValue(nBytesDestBuffer, nSizeAlign) + nBufferAlign; + } + + AssertMsg(!pfnAlloc, "Custom allocators not yet supported!"); + + //if (!pfnAlloc) + { + buf.EnsureCapacity(nBytesDestBuffer + buf.TellPut()); + } + //else + //{ + // // caller provided allocator + // void* pMemory = (*pfnAlloc)(g_pszReadFilename, nBytesDestBuffer); + // buf.SetExternalBuffer(pMemory, nBytesDestBuffer, 0, buf.GetFlags() & ~CUtlBuffer::EXTERNAL_GROWABLE); + //} + + ssize_t seekGet = -1; + if (nBytesDestBuffer != nBytesToRead) + { + // doing optimal read, align target pointer + ssize_t nAlignedBase = AlignValue((byte*)buf.Base(), nBufferAlign) - (byte*)buf.Base(); + buf.SeekPut(CUtlBuffer::SEEK_HEAD, nAlignedBase); + + // the buffer read position is slid forward to ignore the addtional + // starting offset alignment + seekGet = nAlignedBase + nBytesOffset; + } + + nBytesRead = ReadEx(buf.PeekPut(), nBytesDestBuffer - nBufferAlign, nBytesToRead + nBytesOffset, hFile); + buf.SeekPut(CUtlBuffer::SEEK_CURRENT, nBytesRead); + + if (seekGet != -1) + { + // can only seek the get after data has been put, otherwise buffer sets overflow error + buf.SeekGet(CUtlBuffer::SEEK_HEAD, seekGet); + } + + Seek(hFile, iStartPos + (nBytesRead - nBytesOffset), FILESYSTEM_SEEK_HEAD); + } + + return (nBytesRead != 0); +} + +bool CBaseFileSystem::ReadFile(const char* pFileName, const char* pPath, CUtlBuffer& buf, ssize_t nMaxBytes, ptrdiff_t nStartingByte, FSAllocFunc_t pfnAlloc) +{ + //CHECK_DOUBLE_SLASHES(pFileName); + + bool bBinary = !(buf.IsText() && !buf.ContainsCRLF()); + + FileHandle_t fp = Open(pFileName, (bBinary) ? "rb" : "rt", pPath); + if (!fp) + return false; + + if (nStartingByte != 0) + { + Seek(fp, nStartingByte, FILESYSTEM_SEEK_HEAD); + } + + AssertMsg(!pfnAlloc, "Custom allocators not yet supported!"); + + //if (pfnAlloc) + //{ + // g_pszReadFilename = (char*)pFileName; + //} + + bool bSuccess = ReadToBuffer(fp, buf, nMaxBytes, pfnAlloc); + + Close(fp); + + return bSuccess; +} + +bool CBaseFileSystem::WriteFile(const char* pFileName, const char* pPath, CUtlBuffer& buf) +{ + const char* pWriteFlags = "wb"; + if (buf.IsText() && !buf.ContainsCRLF()) + { + pWriteFlags = "wt"; + } + + FileHandle_t fp = Open(pFileName, pWriteFlags, pPath); + if (!fp) + return false; + + ssize_t nBytesWritten = Write(buf.Base(), buf.TellMaxPut(), fp); + + Close(fp); + return (nBytesWritten != 0); +} + +ssize_t CBaseFileSystem::ReadEx(void* pOutput, ssize_t /*destSize*/, ssize_t size, FileHandle_t file) +{ + if (!file) + { + assert(0); // Tried to Read NULL file handle! + return 0; + } + if (size < 0) + { + return 0; + } + + const ssize_t nRet = fread(pOutput, 1, size, (FILE*)file); + return nRet; + +} + +int CBaseFileSystem::CreateDirHierarchy(const char* pFileName, const char* pPathID) +{ + char fullPath[1024]; + int results; + + //if (pPathID) + // snprintf(fullPath, sizeof(fullPath), "%s/%s", pPathID, pFileName); + //else + snprintf(fullPath, sizeof(fullPath), "%s", pFileName); + + V_FixSlashes(fullPath); + + char* pFullPath = fullPath; + while ((pFullPath = strchr(pFullPath, CORRECT_PATH_SEPARATOR)) != NULL) + { + // Temporarily turn the slash into a null + // to get the current directory. + *pFullPath = '\0'; + + results = _mkdir(fullPath); + + if (results && errno != EEXIST) + return results; + + *pFullPath++ = CORRECT_PATH_SEPARATOR; + } + + // Try to create the final directory in the path. + return _mkdir(fullPath); +} + +char* CBaseFileSystem::ReadLine(char* maxChars, ssize_t maxOutputLength, FileHandle_t file) +{ + return fgets(maxChars, (int)maxOutputLength, (FILE*)file); +} + +CUtlString CBaseFileSystem::ReadString(FileHandle_t pFile) +{ + CUtlString result; + char c = '\0'; + + do + { + Read(&c, sizeof(char), pFile); + + if (c) + result += c; + + } while (c); + + return result; +} diff --git a/r5dev/filesystem/filesystem_std.h b/r5dev/filesystem/filesystem_std.h new file mode 100644 index 00000000..c8d44a54 --- /dev/null +++ b/r5dev/filesystem/filesystem_std.h @@ -0,0 +1,294 @@ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H +#include +#include "ifilesystem.h" + +class CBaseFileSystem : public CTier1AppSystem +{ +public: + // Stub implementation of IAppSystem. + //virtual ~CBaseFileSystem() {}; + virtual bool Connect(const CreateInterfaceFn factory) { return false; }; + virtual void Disconnect() {}; + virtual void* QueryInterface(const char* const pInterfaceName) { return nullptr; }; + virtual InitReturnVal_t Init() { return InitReturnVal_t::INIT_FAILED; }; + virtual void Shutdown() {}; + virtual AppSystemTier_t GetTier() { return AppSystemTier_t::APP_SYSTEM_TIER_OTHER; }; + virtual void Reconnect(const CreateInterfaceFn factory, const char* const pInterfaceName) {}; + + + //-------------------------------------------------------- + virtual bool IsSteam() const { return false; }; + virtual FilesystemMountRetval_t MountSteamContent(int nExtraAppId = -1) { return FilesystemMountRetval_t::FILESYSTEM_MOUNT_FAILED; }; + + virtual bool InitFeatureFlags() { return false; }; + virtual bool InitFeatureFlags(const char* pszFlagSetFile) { return false; }; + + virtual void AddSearchPath(const char* pPath, const char* pPathID, SearchPathAdd_t addType) {}; + virtual bool RemoveSearchPath(const char* pPath, const char* pPathID) { return false; }; + virtual void RemoveAllSearchPaths(void) {}; + virtual void RemoveSearchPaths(const char* szPathID) {}; + virtual void MarkPathIDByRequestOnly(const char* pPathID, bool bRequestOnly) {} + virtual const char* RelativePathToFullPath(const char* pFileName, const char* pPathID, char* pLocalPath, ssize_t localPathBufferSize, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t* pPathType = NULL) { return nullptr; }; +#if IsGameConsole() + virtual bool GetPackFileInfoFromRelativePath(const char* pFileName, const char* pPathID, char* pPackPath, ssize_t nPackPathBufferSize, ptrdiff_t& nPosition, ssize_t& nLength) { return false; }; +#endif + virtual ssize_t GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, ssize_t nMaxLen) { return NULL; }; + virtual bool AddPackFile(const char* fullpath, const char* pathID) { return false; }; + + //-------------------------------------------------------- + // File manipulation operations + //-------------------------------------------------------- + virtual void RemoveFile(char const* pRelativePath, const char* pathID = 0) {}; // Deletes a file (on the WritePath) + virtual bool RenameFile(char const* pOldPath, char const* pNewPath, const char* pathID = 0) { return false; }; // Renames a file (on the WritePath) + virtual int CreateDirHierarchy(const char* path, const char* pathID = 0); // create a local directory structure + virtual bool IsDirectory(const char* pFileName, const char* pathID = 0) { return false; }; // File I/O and info + virtual ssize_t FileTimeToString(char* pStrip, ssize_t maxCharsIncludingTerminator, long fileTime) { return NULL; }; // Returns the string size + + //-------------------------------------------------------- + // Open file operations + //-------------------------------------------------------- + + virtual void SetBufferSize(FileHandle_t file/*, ssize_t nBytes*/) {}; + virtual bool IsOk(FileHandle_t file) { return false; }; + virtual bool EndOfFile(FileHandle_t file) { return false; }; + virtual char* ReadLine(char* pOutput, size_t maxChars, FileHandle_t file) { return nullptr; }; +#if ! defined(SWIG) + // Don't let SWIG see the PRINTF_FORMAT_STRING attribute or it will complain. + virtual ssize_t FPrintf(FileHandle_t file, PRINTF_FORMAT_STRING const char* pFormat, ...) FMTFUNCTION(3, 4) { return NULL; }; +#else + virtual ssize_t FPrintf(FileHandle_t file, const char* pFormat, ...) FMTFUNCTION(3, 4) { return NULL; }; +#endif + + //-------------------------------------------------------- + // Dynamic library operations + //-------------------------------------------------------- + // load/unload modules + virtual CSysModule* LoadModule(const char* pFileName, const char* pPathID = 0, bool bValidatedDllOnly = true) { return nullptr; }; + virtual void UnloadModule(CSysModule* pModule) {}; + + //-------------------------------------------------------- + // File searching operations + //-------------------------------------------------------- + // FindFirst/FindNext. Also see FindFirstEx. + virtual const char* FindFirst(const char* pWildCard, FileFindHandle_t* pHandle) { return nullptr; }; + virtual const char* FindNext(FileFindHandle_t handle) { return nullptr; }; + virtual bool FindIsDirectory(FileFindHandle_t handle) { return false; }; + virtual void FindClose(FileFindHandle_t handle) {}; + + // Same as FindFirst, but you can filter by path ID, which can make it faster. + virtual const char* FindFirstEx( + const char* pWildCard, + const char* pPathID, + FileFindHandle_t* pHandle + ) { return nullptr; }; + + // Searches for a file in all paths and results absolute path names for the file, works in pack files (zip and vpk) too + // Lets you search for something like sound/sound.cache and get a list of every sound cache + virtual void FindFileAbsoluteList(CUtlVector& outAbsolutePathNames, const char* pWildCard, const char* pPathID) {}; + + //-------------------------------------------------------- + // File name and directory operations + //-------------------------------------------------------- + + // FIXME: This method is obsolete! Use RelativePathToFullPath instead! + // converts a partial path into a full path + virtual const char* GetLocalPath(const char* pFileName, char* pLocalPath, ssize_t localPathBufferSize) { return nullptr; }; + + // Returns true on success ( based on current list of search paths, otherwise false if + // it can't be resolved ) + virtual bool FullPathToRelativePath(const char* pFullpath, char* pRelative, ssize_t maxlen) { return false; }; + + // Gets the current working directory + virtual bool GetCurrentDirectory(char* pDirectory, unsigned int maxlen) { return false; }; // Last parameter is a DWORD passed to 'GetCurrentDirectoryA()' internally. + + //-------------------------------------------------------- + // Filename dictionary operations + //-------------------------------------------------------- + + virtual FileNameHandle_t FindOrAddFileName(char const* pFileName) { return nullptr; }; + virtual bool String(const FileNameHandle_t& handle, char* buf, ssize_t buflen) { return NULL; }; + + //-------------------------------------------------------- + // Asynchronous file operations + //-------------------------------------------------------- + +//--------------- [ !!! AMOS: !!! ALL ASYNC METHODS ARE UNIMPLEMENTED !!! PURECALL !!! ] ---------------// + //------------------------------------ + // Global operations + //------------------------------------ + virtual void PureCall0() {}; + virtual void PureCall1() {}; + virtual void PureCall2() {}; + virtual void PureCall3() {}; + virtual void PureCall4() {}; + virtual void PureCall5() {}; + + //-------------------------------------------------------- + // Debugging operations + //-------------------------------------------------------- + + // Dump to printf/OutputDebugString the list of files that have not been closed + virtual void PrintOpenedFiles(void) {}; + virtual void PrintSearchPaths(void) {}; + + // output + virtual void SetWarningFunc(void (*pfnWarning)(const char* fmt, ...)) {}; + virtual void SetWarningLevel(FileWarningLevel_t level) {}; + virtual void AddLoggingFunc(void (*pfnLogFunc)(const char* fileName, const char* accessType)) {}; + virtual void RemoveLoggingFunc(FileSystemLoggingFunc_t logFunc) {}; + + virtual __int64 __fastcall sub_14038C240(__int64 a1) { return NULL; }; + virtual __int64 __fastcall sub_14038C380(__int64 a1) { return NULL; }; + virtual __int64 __fastcall sub_14038C400(__int64 a1, __int64 a2) { return NULL; }; + + // Returns the file system statistics retrieved by the implementation. Returns NULL if not supported. + virtual const FileSystemStatistics* GetFilesystemStatistics() { return nullptr; }; + + //-------------------------------------------------------- + // Start of new functions after Lost Coast release (7/05) + //-------------------------------------------------------- + + virtual FileHandle_t OpenEx(const char* pFileName, const char* pOptions, unsigned flags = 0, const char* pathID = 0/*, char** ppszResolvedFilename = NULL*/) { return nullptr; }; + + // Extended version of read provides more context to allow for more optimal reading + virtual ssize_t ReadEx(void* pOutput, ssize_t sizeDest, ssize_t size, FileHandle_t file); + virtual ssize_t ReadFileEx(const char* pFileName, const char* pPath, void** ppBuf, bool bNullTerminate = false, bool bOptimalAlloc = false, ssize_t nMaxBytes = 0, ptrdiff_t nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL) { return NULL; }; + + virtual FileNameHandle_t FindFileName(char const* pFileName) { return nullptr; }; + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking(bool state) {}; + virtual bool IsBlockingFileAccessEnabled() { return false; }; + + virtual IBlockingFileItemList* RetrieveBlockingFileAccessInfo() { return nullptr; }; +#endif + + virtual void SetupPreloadData() {}; + virtual void DiscardPreloadData() {}; + + // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup. + // Otherwise, it'll just fall through to the regular KeyValues loading routines + virtual KeyValues* LoadKeyValues(KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) { return nullptr; }; + virtual bool LoadKeyValues(KeyValues& head, KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) { return false; }; + + virtual bool GetFileTypeForFullPath(char const* pFullPath, wchar_t* buf, size_t bufSizeInBytes) { return false; }; + + //-------------------------------------------------------- + //-------------------------------------------------------- + virtual bool ReadToBuffer(FileHandle_t hFile, CUtlBuffer& buf, ssize_t nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL); + + //-------------------------------------------------------- + // Optimal IO operations + //-------------------------------------------------------- + virtual bool GetOptimalIOConstraints(FileHandle_t hFile, uint64_t* pOffsetAlign, uint64_t* pSizeAlign, uint64_t* pBufferAlign); + virtual void* AllocOptimalReadBuffer(ptrdiff_t nOffset = 0/*!!! UNUSED !!!*/, ssize_t nSize = 0) { return nullptr; }; + virtual void FreeOptimalReadBuffer(void*) {}; + + + virtual bool __fastcall sub_140383E00(__int64 a2) { return false; }; + virtual bool sub_1403836A0() { return false; }; + virtual __int64 __fastcall sub_140384310(int a1) { return NULL; }; + virtual __int64 __fastcall CheckVPKMode(int nMode) { return NULL; }; // Checks if the VPK mode equals the mode input. + + + //-------------------------------------------------------- + // Cache/VPK operations + //-------------------------------------------------------- + virtual bool ReadFromCache(const char* pPath, FileSystemCache* pCache) { return false; }; + + virtual bool __fastcall sub_14037FFA0(__int64 a1, unsigned int a2, __int64 a3) { return false; }; + + virtual void SetVPKCacheModeClient() {}; // g_nVPKCacheMode = 1; + virtual void SetVPKCacheModeServer() {}; // g_nVPKCacheMode = 2; + virtual bool IsVPKCacheEnabled() { return false; }; // g_nVPKCacheMode != 0; + + virtual __int64 __fastcall PrecacheTaskItem(__int64 a1) { return NULL; }; + + virtual void ResetItemCacheSize(int edx) {}; + virtual void __fastcall sub_140380100(__int64 a1) {}; + virtual void __fastcall sub_140380230(char a2) {}; + virtual void* __fastcall sub_1403801F0(const void* a1, unsigned int a2) { return nullptr; }; + virtual void __fastcall sub_140380220(__int64 a1) {}; + virtual bool ResetItemCache() { return false; }; + virtual char __fastcall sub_1403836D0(int a1, char* a2, unsigned int a3) { return false; }; + virtual __int64 __fastcall sub_140383840(unsigned int a1, __int64 a2, char* a3, unsigned int BufferCount) { return NULL; }; + virtual const char** __fastcall sub_140383760(unsigned int a1) { return nullptr; }; + virtual __int64 __fastcall sub_140383A20(const char* a1) { return NULL; }; + + virtual VPKData_t* MountVPKFile(const char* pVpkPath) { return nullptr; }; + virtual const char* UnmountVPKFile(const char* pBasename) { return nullptr; }; + + virtual void __fastcall sub_140383370() {}; + virtual void __fastcall sub_140383560() {}; + + virtual unsigned __int64 __fastcall PnpCtxRegQueryInfoKey(__int64 a1, char* a2, unsigned int* a3, unsigned __int64 a4, unsigned __int64 a5, void(__fastcall* a6)(unsigned __int64)) { return NULL; }; + virtual char* sub_1403842B0() { return nullptr; }; + virtual __int64 __fastcall sub_1403842C0(__int64 a1, unsigned int a2, __int64 a3) { return NULL; }; + + virtual char __fastcall LoadMainVPK(const char* pszVPKFile) { return NULL; }; + + virtual __int64 sub_140380080() { return NULL; }; + virtual char __fastcall sub_14038B530(const char* a1, unsigned __int8* a2, char* a3, __int64 Count) { return NULL; }; + virtual __int64 __fastcall sub_14038C830(unsigned __int16* a1) { return NULL; }; + virtual __int64 __fastcall sub_140388360(char* a1, __int64 a2) { return NULL; }; + virtual __int64 __fastcall sub_140384C60(char* a1, unsigned __int64 a2) { return NULL; }; + virtual void __fastcall sub_140382A80() { }; + virtual __int64 __fastcall sub_14038CC90(int a1, unsigned int a2, __int64 a3, __int64 a4) { return NULL; }; + virtual __int64 __fastcall UserMathErrorFunction() { return NULL; }; + + virtual ssize_t Read(void* pOutput, ssize_t size, FileHandle_t file); + virtual ssize_t Write(void const* pInput, ssize_t size, FileHandle_t file); + + // if pathID is NULL, all paths will be searched for the file + virtual FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pPathID = 0, int64_t unknown = 0); + virtual void Close(FileHandle_t file); + + virtual void Seek(FileHandle_t file, ptrdiff_t pos, FileSystemSeek_t seekType); + virtual ptrdiff_t Tell(FileHandle_t file); + virtual ssize_t FSize(const char* pFileName, const char* pPathID = 0); // Gets optimized away if it isn't named differently or used. + virtual ssize_t Size(FileHandle_t file); + + virtual void Flush(FileHandle_t file); + virtual bool Precache(const char* pFileName, const char* pPathID = 0); + + virtual bool FileExists(const char* pFileName, const char* pPathID = 0); + virtual bool IsFileWritable(char const* pFileName, const char* pPathID = 0); + virtual bool SetFileWritable(char const* pFileName, bool writable, const char* pPathID = 0); + + virtual long long GetFileTime(const char* pFileName, const char* pPathID = 0); + + virtual bool ReadFile(const char* pFileName, const char* pPath, CUtlBuffer& buf, ssize_t nMaxBytes = 0, ptrdiff_t nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL); + virtual bool WriteFile(const char* pFileName, const char* pPath, CUtlBuffer& buf); + virtual bool UnzipFile(const char* pFileName, const char* pPath, const char* pDestination) { return false; }; + + char* ReadLine(char* maxChars, ssize_t maxOutputLength, FileHandle_t file); + CUtlString ReadString(FileHandle_t pFile); +}; + +class CFileSystem_Stdio : public CBaseFileSystem +{ +protected: + // implementation of CBaseFileSystem virtual functions + virtual FILE* FS_fopen(const char* filename, const char* options, unsigned flags, int64* size) { return nullptr; }; + virtual void FS_setbufsize(FILE* fp, unsigned nBytes) {}; + virtual void FS_fclose(FILE* fp) {}; + virtual void FS_fseek(FILE* fp, int64 pos, int seekType) {}; + virtual long FS_ftell(FILE* fp) { return NULL; }; + virtual int FS_feof(FILE* fp) { return NULL; }; + virtual size_t FS_fread(void* dest, size_t destSize, size_t size, FILE* fp) { return NULL; }; + virtual size_t FS_fwrite(const void* src, size_t size, FILE* fp) { return NULL; }; + virtual bool FS_setmode(FILE* fp, FileMode_t mode) { return false; }; + virtual size_t FS_vfprintf(FILE* fp, const char* fmt, va_list list) { return NULL; }; + virtual int FS_ferror(FILE* fp) { return NULL; }; + virtual int FS_fflush(FILE* fp) { return NULL; }; + virtual char* FS_fgets(char* dest, unsigned int destSize) { return nullptr; }; + virtual int FS_stat(const char* path, struct _stat* buf, bool* pbLoadedFromSteamCache = NULL) { return NULL; }; + virtual int FS_chmod(const char* path, int pmode) { return NULL; }; + virtual HANDLE FS_FindFirstFile(const char* findname, WIN32_FIND_DATA* dat) { return NULL; }; + virtual bool FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA* dat) { return false; }; + virtual bool FS_FindClose(HANDLE handle) { return false; }; + virtual int FS_GetSectorSize(FILE*) { return NULL; }; +}; + +#endif // FILESYSTEM_H