// Copyright (c) 2013, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ #include #include #include #include #include #include #include #include #undef CreateDirectory namespace agi { namespace fs { /// Define a filesystem error which takes a path or a string #define DEFINE_FS_EXCEPTION(type, base, message) \ struct type : public base { \ type(path const& p) : base(message + p.string()) { } \ type(std::string const& s) : base(s) { } \ const char *GetName() const { return ""; } \ Exception *Copy() const { return new type(*this); } \ } /// @class agi::FileSystemError /// @extends agi::Exception /// @brief Base class for errors related to the file system /// /// This base class can not be instantiated. /// File system errors do not support inner exceptions, as they /// are always originating causes for errors. DEFINE_EXCEPTION(FileSystemError, Exception); /// A file can't be accessed for some reason DEFINE_FS_EXCEPTION(FileNotAccessible, FileSystemError, "File is not accessible: "); /// A file can't be accessed because there's no file by the given name DEFINE_FS_EXCEPTION(FileNotFound, FileNotAccessible, "File not found: "); /// An error of some unknown type has occured DEFINE_EXCEPTION(FileSystemUnknownError, FileSystemError);; /// The path exists, but isn't a file DEFINE_FS_EXCEPTION(NotAFile, FileNotAccessible, "Path is not a file (and should be): "); /// The path exists, but isn't a directory DEFINE_FS_EXCEPTION(NotADirectory, FileNotAccessible, "Path is not a directory (and should be): "); /// The given path is too long for the filesystem DEFINE_FS_EXCEPTION(PathTooLog, FileSystemError, "Path is too long: "); /// Insufficient free space to complete operation DEFINE_FS_EXCEPTION(DriveFull, FileSystemError, "Insufficient free space to write file: "); /// Base class for access denied errors DEFINE_FS_EXCEPTION(AccessDenied, FileNotAccessible, "Access denied to path: "); /// Trying to read the file gave an access denied error DEFINE_FS_EXCEPTION(ReadDenied, AccessDenied, "Access denied when trying to read: "); /// Trying to write the file gave an access denied error DEFINE_FS_EXCEPTION(WriteDenied, AccessDenied, "Access denied when trying to write: "); /// File exists and cannot be overwritten due to being read-only DEFINE_FS_EXCEPTION(ReadOnlyFile, WriteDenied, "File is read-only: "); bool Exists(path const& p); bool FileExists(path const& file); bool DirectoryExists(path const& dir); /// Get the local-charset encoded shortname for a file /// /// This is purely for compatibility with external libraries which do /// not support unicode filenames on Windows. On all other platforms, /// it is a no-op. std::string ShortName(path const& file_path); /// Check for amount of free space on a path uintmax_t FreeSpace(path const& dir_path); /// Get the size in bytes of the file at path /// /// @throws agi::FileNotFound if path does not exist /// @throws agi::acs::NotAFile if path is a directory /// @throws agi::acs::Read if path exists but could not be read uintmax_t Size(path const& file_path); /// Get the modification time of the file at path /// /// @throws agi::FileNotFound if path does not exist /// @throws agi::acs::NotAFile if path is a directory /// @throws agi::acs::Read if path exists but could not be read time_t ModifiedTime(path const& file_path); /// Create a directory and all required intermediate directories /// @throws agi::acs::Write if the directory could not be created. /// /// Trying to create a directory which already exists is not an error. bool CreateDirectory(path const& dir_path); /// Touch the given path /// /// Creates the file if it does not exist, or updates the modified /// time if it does void Touch(path const& file_path); /// Rename a file or directory /// @param from Source path /// @param to Destination path void Rename(path const& from, path const& to); /// Copy a file /// @param from Source path /// @param to Destination path /// /// The destination path will be created if it does not exist. void Copy(path const& from, path const& to); /// Delete a file /// @param path Path to file to delete /// @throws agi::FileNotAccessibleError if file exists but could not be deleted bool Remove(path const& file); /// Check if the file has the given extension /// @param p Path to check /// @param ext Case-insensitive extension, without leading dot bool HasExtension(path const& p, std::string const& ext); agi::fs::path Canonicalize(agi::fs::path const& path); class DirectoryIterator { struct PrivData; std::shared_ptr privdata; std::string value; public: typedef path value_type; typedef path* pointer; typedef path& reference; typedef size_t difference_type; typedef std::forward_iterator_tag iterator_category; bool operator==(DirectoryIterator const&) const; bool operator!=(DirectoryIterator const& rhs) const { return !(*this == rhs); } DirectoryIterator& operator++(); std::string const& operator*() const { return value; } DirectoryIterator(path const& p, std::string const& filter); DirectoryIterator(); ~DirectoryIterator(); template void GetAll(T& cont); }; inline DirectoryIterator& begin(DirectoryIterator &it) { return it; } inline DirectoryIterator end(DirectoryIterator &) { return DirectoryIterator(); } template inline void DirectoryIterator::GetAll(T& cont) { copy(*this, end(*this), std::back_inserter(cont)); } } }