// 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 <fstream>20#include <cstdio>21#include <string>22#include <string_view>23#include <time.h>24#include <cstdint>2526#include "Common/File/Path.h"2728// Some functions here support Android content URIs. These are marked as such.2930#ifdef _WIN3231inline struct tm* localtime_r(const time_t *clock, struct tm *result) {32if (localtime_s(result, clock) == 0)33return result;34return NULL;35}36#endif3738namespace File {3940// Mostly to handle UTF-8 filenames better on Windows.41FILE *OpenCFile(const Path &filename, const char *mode);4243// Reminiscent of PSP's FileAccess enum, due to its use in emulating it.44enum OpenFlag {45OPEN_NONE = 0,46OPEN_READ = 1,47OPEN_WRITE = 2,48OPEN_APPEND = 4,49OPEN_CREATE = 8,50OPEN_TRUNCATE = 16,51// EXCL?52};5354// TODO: This currently only handles Android Content URIs, but might port the rest55// of DirectoryFileSystem::Open here eventually for symmetry.56int OpenFD(const Path &filename, OpenFlag flags);5758// Cross-platform way to close FDs, corresponsing in platform support with OpenFD above.59void CloseFD(int fd);6061// Resolves symlinks and similar.62std::string ResolvePath(std::string_view path);6364// Returns true if file filename exists65bool Exists(const Path &path);6667// Returns true if file filename exists in directory path.68bool ExistsInDir(const Path &path, const std::string &filename);6970// Returns true if filename exists, and is a directory71// Supports Android content URIs.72bool IsDirectory(const Path &filename);7374// Returns struct with modification date of file75bool GetModifTime(const Path &filename, tm &return_time);76// Same but with unix timestamp77bool GetModifTimeT(const Path &filename, time_t *return_time); // the time_t, of course, matches time_now_unix_utc().7879// Returns the size of filename (64bit)80uint64_t GetFileSize(const Path &filename);8182// Overloaded GetSize, accepts FILE*83uint64_t GetFileSize(FILE *f);8485// Computes the recursive size of a directory. Warning: Might be slow!86uint64_t ComputeRecursiveDirectorySize(const Path &path);8788// Returns true if successful, or path already exists.89bool CreateDir(const Path &filename);9091void ChangeMTime(const Path &path, time_t mtime);9293// Creates the full path of fullPath returns true on success94bool CreateFullPath(const Path &fullPath);9596// Deletes a given file by name, return true on success97// Doesn't support deleting a directory (although it will work on some platforms - ideally shouldn't)98bool Delete(const Path &filename);99100// Deletes a directory by name, returns true on success101// Directory must be empty.102bool DeleteDir(const Path &filename);103104// Deletes the given directory and anything under it. Returns true on success.105bool DeleteDirRecursively(const Path &directory);106107// Renames/moves file srcFilename to destFilename, returns true on success108// Will usually only work with in the same partition or other unit of storage,109// so you might have to fall back to copy/delete.110bool Rename(const Path &srcFilename, const Path &destFilename);111112// copies file srcFilename to destFilename, returns true on success113bool Copy(const Path &srcFilename, const Path &destFilename);114115// Tries to rename srcFilename to destFilename, if that fails,116// it tries to copy and delete the src if succeeded. If that fails too,117// returns false, otherwise returns true.118bool Move(const Path &srcFilename, const Path &destFilename);119120// Move file, but only if it can be done quickly (rename or similar).121bool MoveIfFast(const Path &srcFilename, const Path &destFilename);122123// creates an empty file filename, returns true on success124bool CreateEmptyFile(const Path &filename);125126// Opens ini file (cheats, texture replacements etc.)127// TODO: Belongs in System or something.128bool OpenFileInEditor(const Path &fileName);129130// Uses some heuristics to determine if this is a folder that we would want to131// write to.132bool IsProbablyInDownloadsFolder(const Path &folder);133134// TODO: Belongs in System or something.135const Path &GetExeDirectory();136137const Path GetCurDirectory();138139// simple wrapper for cstdlib file functions to140// hopefully will make error checking easier141// and make forgetting an fclose() harder142class IOFile {143public:144IOFile() {}145IOFile(const Path &filename, const char openmode[]);146~IOFile();147148// Prevent copies.149IOFile(const IOFile &) = delete;150void operator=(const IOFile &) = delete;151152bool Open(const Path &filename, const char openmode[]);153bool Close();154155template <typename T>156bool ReadArray(T* data, size_t length)157{158if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file))159m_good = false;160161return m_good;162}163164template <typename T>165bool WriteArray(const T* data, size_t length)166{167if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file))168m_good = false;169170return m_good;171}172173bool ReadBytes(void* data, size_t length)174{175return ReadArray(reinterpret_cast<char*>(data), length);176}177178bool WriteBytes(const void* data, size_t length)179{180return WriteArray(reinterpret_cast<const char*>(data), length);181}182183bool IsOpen() const { return nullptr != m_file; }184185// m_good is set to false when a read, write or other function fails186bool IsGood() const { return m_good; }187operator bool() const { return IsGood() && IsOpen(); }188189std::FILE* ReleaseHandle();190191std::FILE* GetHandle() { return m_file; }192193void SetHandle(std::FILE* file);194195bool Seek(int64_t off, int origin);196uint64_t Tell();197uint64_t GetSize();198bool Resize(uint64_t size);199bool Flush();200201// clear error state202void Clear() {203m_good = true;204#undef clearerr205std::clearerr(m_file);206}207208private:209std::FILE *m_file = nullptr;210bool m_good = true;211};212213// TODO: Refactor, this was moved from the old file_util.cpp.214215// Whole-file reading/writing216bool WriteStringToFile(bool textFile, const std::string &str, const Path &filename);217bool WriteDataToFile(bool textFile, const void* data, size_t size, const Path &filename);218219bool ReadFileToStringOptions(bool textFile, bool allowShort, const Path &path, std::string *str);220221// Wrappers that clarify the intentions.222inline bool ReadBinaryFileToString(const Path &path, std::string *str) {223return ReadFileToStringOptions(false, false, path, str);224}225inline bool ReadSysTextFileToString(const Path &path, std::string *str) {226return ReadFileToStringOptions(true, true, path, str);227}228inline bool ReadTextFileToString(const Path &path, std::string *str) {229return ReadFileToStringOptions(true, false, path, str);230}231232// Return value must be delete[]-d.233uint8_t *ReadLocalFile(const Path &path, size_t *size);234235} // namespace236237238