// Copyright (C) 2003 Dolphin Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617#pragma once1819#include <cstdio>20#include <string>21#include <string_view>22#include <time.h>23#include <cstdint>2425#include "Common/File/Path.h"2627// Some functions here support Android content URIs. These are marked as such.2829#ifdef _WIN3230inline struct tm* localtime_r(const time_t *clock, struct tm *result) {31if (localtime_s(result, clock) == 0)32return result;33return NULL;34}35#endif3637namespace File {3839// Mostly to handle UTF-8 filenames better on Windows.40FILE *OpenCFile(const Path &filename, const char *mode);4142// Reminiscent of PSP's FileAccess enum, due to its use in emulating it.43enum OpenFlag {44OPEN_NONE = 0,45OPEN_READ = 1,46OPEN_WRITE = 2,47OPEN_APPEND = 4,48OPEN_CREATE = 8,49OPEN_TRUNCATE = 16,50// EXCL?51};5253// TODO: This currently only handles Android Content URIs, but might port the rest54// of DirectoryFileSystem::Open here eventually for symmetry.55int OpenFD(const Path &filename, OpenFlag flags);5657// Cross-platform way to close FDs, corresponsing in platform support with OpenFD above.58void CloseFD(int fd);5960// Resolves symlinks and similar.61std::string ResolvePath(std::string_view path);6263// Returns true if file filename exists64bool Exists(const Path &path);6566// Returns true if file filename exists in directory path.67bool ExistsInDir(const Path &path, std::string_view filename);6869// Returns true if filename exists, and is a directory70// Supports Android content URIs.71bool IsDirectory(const Path &path);7273// Returns struct with modification date of file74bool GetModifTime(const Path &filename, tm &return_time);75// Same but with unix timestamp76bool GetModifTimeT(const Path &filename, time_t *return_time); // the time_t, of course, matches time_now_unix_utc().7778// Returns the size of filename (64bit)79uint64_t GetFileSize(const Path &filename);8081// Overloaded GetSize, accepts FILE*82uint64_t GetFileSize(FILE *f);8384// Computes the recursive size of a directory. Warning: Might be slow!85uint64_t ComputeRecursiveDirectorySize(const Path &path);8687// Returns true if successful, or path already exists.88bool CreateDir(const Path &filename);8990void ChangeMTime(const Path &path, time_t mtime);9192// Creates the full path of fullPath returns true on success93bool CreateFullPath(const Path &fullPath);9495// Deletes a given file by name, return true on success96// Doesn't support deleting a directory (although it will work on some platforms - ideally shouldn't)97bool Delete(const Path &filename, bool quiet = false);9899// Deletes a directory by name, returns true on success100// Directory must be empty.101bool DeleteDir(const Path &filename);102103// Deletes the given directory and anything under it. Returns true on success.104bool DeleteDirRecursively(const Path &directory);105106// Renames/moves file srcFilename to destFilename, returns true on success107// Will usually only work with in the same partition or other unit of storage,108// so you might have to fall back to copy/delete.109bool Rename(const Path &srcFilename, const Path &destFilename);110111// copies file srcFilename to destFilename, returns true on success112bool Copy(const Path &srcFilename, const Path &destFilename);113114// Tries to rename srcFilename to destFilename, if that fails,115// it tries to copy and delete the src if succeeded. If that fails too,116// returns false, otherwise returns true.117bool Move(const Path &srcFilename, const Path &destFilename);118119// Move file, but only if it can be done quickly (rename or similar).120bool MoveIfFast(const Path &srcFilename, const Path &destFilename);121122// creates an empty file filename, returns true on success123bool CreateEmptyFile(const Path &filename);124125// Opens ini file (cheats, texture replacements etc.)126// TODO: Belongs in System or something.127bool OpenFileInEditor(const Path &fileName);128129// Uses some heuristics to determine if this is a folder that we would want to130// write to.131bool IsProbablyInDownloadsFolder(const Path &folder);132133// TODO: Belongs in System or something.134const Path &GetExeDirectory();135136const Path GetCurDirectory();137138// Portable version of fseek() that works with 64-bit offsets if supported by139// the operating system.140int Fseek(FILE *file, int64_t offset, int whence);141142// Portable version of fseek() that works with 64-bit offsets if supported by143// the operating system, and returns the new offset from the start of the file144// or -1 if it failed.145int64_t Fseektell(FILE *file, int64_t offset, int whence);146147// Portable version of ftell() that works with 64-bit offsets if supported by148// the operating system.149int64_t Ftell(FILE *file);150151// simple wrapper for cstdlib file functions to152// hopefully will make error checking easier153// and make forgetting an fclose() harder154class IOFile {155public:156IOFile() {}157IOFile(const Path &filename, const char openmode[]);158~IOFile();159160// Prevent copies.161IOFile(const IOFile &) = delete;162void operator=(const IOFile &) = delete;163164bool Open(const Path &filename, const char openmode[]);165bool Close();166167template <typename T>168bool ReadArray(T* data, size_t length)169{170if (!IsOpen() || length != fread(data, sizeof(T), length, m_file))171m_good = false;172173return m_good;174}175176template <typename T>177bool WriteArray(const T* data, size_t length)178{179if (!IsOpen() || length != fwrite(data, sizeof(T), length, m_file))180m_good = false;181182return m_good;183}184185bool ReadBytes(void* data, size_t length)186{187return ReadArray(reinterpret_cast<char*>(data), length);188}189190bool WriteBytes(const void* data, size_t length)191{192return WriteArray(reinterpret_cast<const char*>(data), length);193}194195bool IsOpen() const { return nullptr != m_file; }196197// m_good is set to false when a read, write or other function fails198bool IsGood() const { return m_good; }199operator bool() const { return IsGood() && IsOpen(); }200201FILE* ReleaseHandle();202203FILE* GetHandle() { return m_file; }204205void SetHandle(FILE* file);206207bool Seek(int64_t off, int origin);208uint64_t Tell();209uint64_t GetSize();210bool Resize(uint64_t size);211bool Flush();212213// clear error state214void Clear() {215m_good = true;216#ifndef HAVE_LIBRETRO_VFS217#undef clearerr218std::clearerr(m_file);219#endif220}221222private:223FILE *m_file = nullptr;224bool m_good = true;225};226227#ifdef HAVE_LIBRETRO_VFS228// Call this on libretro core initialization with the libretro virtual file229// system interface.230void InitLibretroVFS(const struct retro_vfs_interface_info *vfs) noexcept;231#endif232233// TODO: Refactor, this was moved from the old file_util.cpp.234235// Whole-file reading/writing236bool WriteStringToFile(bool textFile, std::string_view str, const Path &filename);237bool WriteDataToFile(bool textFile, const void* data, size_t size, const Path &filename);238239bool ReadFileToStringOptions(bool textFile, bool allowShort, const Path &path, std::string *str);240241// Wrappers that clarify the intentions.242inline bool ReadBinaryFileToString(const Path &path, std::string *str) {243return ReadFileToStringOptions(false, false, path, str);244}245inline bool ReadSysTextFileToString(const Path &path, std::string *str) {246return ReadFileToStringOptions(true, true, path, str);247}248inline bool ReadTextFileToString(const Path &path, std::string *str) {249return ReadFileToStringOptions(true, false, path, str);250}251252// Return value must be delete[]-d.253uint8_t *ReadLocalFile(const Path &path, size_t *size);254255} // namespace256257258