2022-07-30 12:24:03 -04:00
|
|
|
#pragma once
|
|
|
|
|
2024-11-04 15:24:20 -05:00
|
|
|
#include <Geode/Result.hpp>
|
2022-11-28 12:09:39 -05:00
|
|
|
#include "general.hpp"
|
2023-04-27 03:41:07 -04:00
|
|
|
#include "../loader/Event.hpp"
|
2024-05-05 16:49:07 -04:00
|
|
|
#include "Task.hpp"
|
2022-10-30 14:59:20 -04:00
|
|
|
|
2024-11-09 01:05:16 -05:00
|
|
|
#include <matjson3.hpp>
|
2022-10-30 14:59:20 -04:00
|
|
|
#include <Geode/DefaultInclude.hpp>
|
2024-06-02 21:35:05 -04:00
|
|
|
#include <filesystem>
|
2022-10-30 14:59:20 -04:00
|
|
|
#include <string>
|
2022-11-28 12:09:39 -05:00
|
|
|
#include <unordered_set>
|
2022-07-30 12:24:03 -04:00
|
|
|
|
2023-01-27 18:25:19 -05:00
|
|
|
template <>
|
2024-06-02 21:35:05 -04:00
|
|
|
struct matjson::Serialize<std::filesystem::path> {
|
2024-11-09 01:05:16 -05:00
|
|
|
static geode::Result<std::filesystem::path, std::string> fromJson(Value const& value)
|
|
|
|
{
|
|
|
|
auto str = GEODE_UNWRAP(value.asString());
|
|
|
|
return geode::Ok(std::filesystem::path(str).make_preferred());
|
2023-01-27 18:25:19 -05:00
|
|
|
}
|
2024-11-09 01:05:16 -05:00
|
|
|
|
|
|
|
static Value toJson(std::filesystem::path const& value)
|
|
|
|
{
|
|
|
|
return Value(value.string());
|
2024-01-24 09:17:42 -05:00
|
|
|
}
|
2023-01-27 18:25:19 -05:00
|
|
|
};
|
2022-12-13 15:39:45 -05:00
|
|
|
|
2022-09-26 06:53:40 -04:00
|
|
|
namespace geode::utils::file {
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Result<std::string> readString(std::filesystem::path const& path);
|
|
|
|
GEODE_DLL Result<matjson::Value> readJson(std::filesystem::path const& path);
|
|
|
|
GEODE_DLL Result<ByteVector> readBinary(std::filesystem::path const& path);
|
2022-07-30 12:24:03 -04:00
|
|
|
|
2023-04-22 14:37:57 -04:00
|
|
|
template <class T>
|
2024-06-02 21:35:05 -04:00
|
|
|
Result<T> readFromJson(std::filesystem::path const& file) {
|
2023-04-22 14:37:57 -04:00
|
|
|
GEODE_UNWRAP_INTO(auto json, readJson(file));
|
2024-11-09 01:05:16 -05:00
|
|
|
return json.as<T>();
|
2023-04-22 14:37:57 -04:00
|
|
|
}
|
|
|
|
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Result<> writeString(std::filesystem::path const& path, std::string const& data);
|
|
|
|
GEODE_DLL Result<> writeBinary(std::filesystem::path const& path, ByteVector const& data);
|
2022-07-30 12:24:03 -04:00
|
|
|
|
2023-04-22 14:37:57 -04:00
|
|
|
template <class T>
|
2024-06-02 21:35:05 -04:00
|
|
|
Result<> writeToJson(std::filesystem::path const& path, T const& data) {
|
2024-01-24 09:17:42 -05:00
|
|
|
GEODE_UNWRAP(writeString(path, matjson::Value(data).dump()));
|
|
|
|
return Ok();
|
2023-04-22 14:37:57 -04:00
|
|
|
}
|
|
|
|
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Result<> createDirectory(std::filesystem::path const& path);
|
|
|
|
GEODE_DLL Result<> createDirectoryAll(std::filesystem::path const& path);
|
|
|
|
GEODE_DLL Result<std::vector<std::filesystem::path>> readDirectory(
|
|
|
|
std::filesystem::path const& path, bool recursive = false
|
2023-02-25 04:21:43 -05:00
|
|
|
);
|
2022-10-05 08:41:05 -04:00
|
|
|
|
2023-01-31 07:48:34 -05:00
|
|
|
class Unzip;
|
|
|
|
|
2022-12-12 05:45:20 -05:00
|
|
|
class GEODE_DLL Zip final {
|
|
|
|
public:
|
2024-06-02 21:35:05 -04:00
|
|
|
using Path = std::filesystem::path;
|
2022-12-12 05:45:20 -05:00
|
|
|
|
|
|
|
private:
|
|
|
|
class Impl;
|
|
|
|
std::unique_ptr<Impl> m_impl;
|
|
|
|
|
|
|
|
Zip();
|
|
|
|
Zip(std::unique_ptr<Impl>&& impl);
|
|
|
|
|
|
|
|
Result<> addAllFromRecurse(
|
|
|
|
Path const& dir, Path const& entry
|
|
|
|
);
|
2023-01-31 07:48:34 -05:00
|
|
|
|
|
|
|
// for sharing Impl
|
|
|
|
friend class Unzip;
|
2022-12-12 05:45:20 -05:00
|
|
|
|
|
|
|
public:
|
|
|
|
Zip(Zip const&) = delete;
|
|
|
|
Zip(Zip&& other);
|
|
|
|
~Zip();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create zipper for file
|
|
|
|
*/
|
|
|
|
static Result<Zip> create(Path const& file);
|
|
|
|
|
|
|
|
/**
|
2023-01-31 07:48:34 -05:00
|
|
|
* Create zipper for in-memory data
|
|
|
|
*/
|
|
|
|
static Result<Zip> create();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Path to the created zip
|
|
|
|
* @returns The path to the zip that is being created, or an empty path
|
|
|
|
* if the zip was opened in memory
|
2022-12-12 05:45:20 -05:00
|
|
|
*/
|
|
|
|
Path getPath() const;
|
|
|
|
|
2023-01-31 07:48:34 -05:00
|
|
|
/**
|
|
|
|
* Get the zipped data
|
|
|
|
*/
|
|
|
|
ByteVector getData() const;
|
|
|
|
|
2022-12-12 05:45:20 -05:00
|
|
|
/**
|
|
|
|
* Add an entry to the zip with data
|
|
|
|
*/
|
2022-12-14 06:11:19 -05:00
|
|
|
Result<> add(Path const& entry, ByteVector const& data);
|
2022-12-12 05:45:20 -05:00
|
|
|
/**
|
|
|
|
* Add an entry to the zip with string data
|
|
|
|
*/
|
|
|
|
Result<> add(Path const& entry, std::string const& data);
|
|
|
|
/**
|
|
|
|
* Add an entry to the zip from a file on disk. If you want to add the
|
|
|
|
* file with a different name, read it into memory first and add it
|
|
|
|
* with Zip::add
|
|
|
|
* @param file File on disk
|
|
|
|
* @param entryDir Folder to place the file in in the zip
|
|
|
|
*/
|
|
|
|
Result<> addFrom(Path const& file, Path const& entryDir = Path());
|
|
|
|
/**
|
|
|
|
* Add an entry to the zip from a directory on disk
|
|
|
|
* @param entry Path in the zip
|
|
|
|
* @param dir Directory on disk
|
|
|
|
*/
|
|
|
|
Result<> addAllFrom(Path const& dir);
|
|
|
|
/**
|
|
|
|
* Add a folder entry to the zip. If you want to add a folder from disk,
|
|
|
|
* use Zip::addAllFrom
|
|
|
|
* @param entry Folder path in zip
|
|
|
|
*/
|
|
|
|
Result<> addFolder(Path const& entry);
|
|
|
|
};
|
2022-11-29 17:48:06 -05:00
|
|
|
|
|
|
|
class GEODE_DLL Unzip final {
|
|
|
|
private:
|
2023-01-31 07:48:34 -05:00
|
|
|
using Impl = Zip::Impl;
|
2022-12-12 05:45:20 -05:00
|
|
|
std::unique_ptr<Impl> m_impl;
|
|
|
|
|
|
|
|
Unzip();
|
|
|
|
Unzip(std::unique_ptr<Impl>&& impl);
|
2022-11-29 17:48:06 -05:00
|
|
|
|
|
|
|
public:
|
|
|
|
Unzip(Unzip const&) = delete;
|
|
|
|
Unzip(Unzip&& other);
|
|
|
|
~Unzip();
|
|
|
|
|
2024-06-02 21:35:05 -04:00
|
|
|
using Path = std::filesystem::path;
|
2022-11-29 17:48:06 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create unzipper for file
|
|
|
|
*/
|
|
|
|
static Result<Unzip> create(Path const& file);
|
|
|
|
|
2023-01-31 07:48:34 -05:00
|
|
|
/**
|
|
|
|
* Create unzipper for data in-memory
|
|
|
|
*/
|
|
|
|
static Result<Unzip> create(ByteVector const& data);
|
|
|
|
|
2024-02-24 14:08:07 -05:00
|
|
|
/**
|
|
|
|
* Set a callback to be called with the progress of the unzip operation, first
|
|
|
|
* argument is the current entry, second argument is the total entries
|
|
|
|
* @note This is not thread-safe
|
|
|
|
* @param callback Callback to call with the progress of the unzip operation
|
|
|
|
*/
|
|
|
|
void setProgressCallback(
|
2024-11-04 12:42:09 -05:00
|
|
|
std::function<void(uint32_t, uint32_t)> callback
|
2024-02-24 14:08:07 -05:00
|
|
|
);
|
|
|
|
|
2022-11-29 17:48:06 -05:00
|
|
|
/**
|
|
|
|
* Path to the opened zip
|
2023-01-31 07:48:34 -05:00
|
|
|
* @returns The path to the zip that is being read, or an empty path
|
|
|
|
* if the zip was opened in memory
|
2022-11-29 17:48:06 -05:00
|
|
|
*/
|
|
|
|
Path getPath() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all entries in zip
|
|
|
|
*/
|
|
|
|
std::vector<Path> getEntries() const;
|
|
|
|
/**
|
|
|
|
* Check if zip has entry
|
|
|
|
* @param name Entry path in zip
|
|
|
|
*/
|
|
|
|
bool hasEntry(Path const& name);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract entry to memory
|
|
|
|
* @param name Entry path in zip
|
|
|
|
*/
|
2022-12-14 06:11:19 -05:00
|
|
|
Result<ByteVector> extract(Path const& name);
|
2022-11-29 17:48:06 -05:00
|
|
|
/**
|
|
|
|
* Extract entry to file
|
|
|
|
* @param name Entry path in zip
|
|
|
|
* @param path Target file path
|
|
|
|
*/
|
|
|
|
Result<> extractTo(Path const& name, Path const& path);
|
|
|
|
/**
|
|
|
|
* Extract all entries to directory
|
|
|
|
* @param dir Directory to unzip the contents to
|
|
|
|
*/
|
|
|
|
Result<> extractAllTo(Path const& dir);
|
|
|
|
|
2022-12-01 15:42:49 -05:00
|
|
|
/**
|
|
|
|
* Helper method for quickly unzipping a file
|
|
|
|
* @param from ZIP file to unzip
|
|
|
|
* @param to Directory to unzip to
|
|
|
|
* @param deleteZipAfter Whether to delete the zip after unzipping
|
|
|
|
* @returns Succesful result on success, errorful result on error
|
|
|
|
*/
|
|
|
|
static Result<> intoDir(
|
|
|
|
Path const& from,
|
|
|
|
Path const& to,
|
|
|
|
bool deleteZipAfter = false
|
|
|
|
);
|
2024-02-24 14:08:07 -05:00
|
|
|
|
|
|
|
static Result<> intoDir(
|
2024-11-04 12:42:09 -05:00
|
|
|
std::function<void(uint32_t, uint32_t)> progressCallback,
|
2024-02-24 14:08:07 -05:00
|
|
|
Path const& from,
|
|
|
|
Path const& to,
|
|
|
|
bool deleteZipAfter = false
|
|
|
|
);
|
2022-12-01 15:42:49 -05:00
|
|
|
};
|
2022-11-28 12:09:39 -05:00
|
|
|
|
2023-02-26 13:37:13 -05:00
|
|
|
/**
|
|
|
|
* Open a folder / file in the system's file explorer
|
|
|
|
* @param path Folder / file to open
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL bool openFolder(std::filesystem::path const& path);
|
2022-11-28 12:09:39 -05:00
|
|
|
|
|
|
|
enum class PickMode {
|
|
|
|
OpenFile,
|
|
|
|
SaveFile,
|
|
|
|
OpenFolder,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FilePickOptions {
|
|
|
|
struct Filter {
|
|
|
|
// Name of the filter
|
|
|
|
std::string description;
|
|
|
|
// Extensions (*.txt, *.doc, *.mp3, etc.)
|
|
|
|
std::unordered_set<std::string> files;
|
|
|
|
};
|
|
|
|
|
2023-02-26 13:37:13 -05:00
|
|
|
/**
|
|
|
|
* On PickMode::SaveFile and PickMode::OpenFile, last item is assumed
|
|
|
|
* to be a filename, unless it points to an extant directory.
|
|
|
|
* On PickMode::OpenFolder, path is treated as leading up to a directory
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
std::optional<std::filesystem::path> defaultPath;
|
2023-02-26 13:37:13 -05:00
|
|
|
/**
|
|
|
|
* File extension filters to show on the file picker
|
|
|
|
*/
|
2022-11-28 12:09:39 -05:00
|
|
|
std::vector<Filter> filters;
|
|
|
|
};
|
|
|
|
|
2023-02-26 13:37:13 -05:00
|
|
|
/**
|
|
|
|
* Prompt the user to pick a file using the system's file system picker
|
|
|
|
* @param mode Type of file selection prompt to show
|
|
|
|
* @param options Picker options
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Task<Result<std::filesystem::path>> pick(PickMode mode, FilePickOptions const& options);
|
2023-10-08 09:38:17 -04:00
|
|
|
|
2023-02-26 13:37:13 -05:00
|
|
|
/**
|
|
|
|
* Prompt the user to pick a bunch of files for opening using the system's file system picker
|
|
|
|
* @param options Picker options
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Task<Result<std::vector<std::filesystem::path>>> pickMany(FilePickOptions const& options);
|
2023-10-08 09:38:17 -04:00
|
|
|
|
2024-06-20 16:00:04 -04:00
|
|
|
class GEODE_DLL FileWatchEvent final : public Event {
|
2023-04-27 02:22:56 -04:00
|
|
|
protected:
|
2024-06-02 21:35:05 -04:00
|
|
|
std::filesystem::path m_path;
|
2023-04-27 02:22:56 -04:00
|
|
|
|
|
|
|
public:
|
2024-06-02 21:35:05 -04:00
|
|
|
FileWatchEvent(std::filesystem::path const& path);
|
|
|
|
std::filesystem::path getPath() const;
|
2023-04-27 02:22:56 -04:00
|
|
|
};
|
|
|
|
|
2024-06-20 16:00:04 -04:00
|
|
|
class GEODE_DLL FileWatchFilter final : public EventFilter<FileWatchEvent> {
|
2023-04-27 02:22:56 -04:00
|
|
|
protected:
|
2024-06-02 21:35:05 -04:00
|
|
|
std::filesystem::path m_path;
|
2023-04-27 02:22:56 -04:00
|
|
|
|
|
|
|
public:
|
|
|
|
using Callback = void(FileWatchEvent*);
|
|
|
|
|
2024-11-04 12:42:09 -05:00
|
|
|
ListenerResult handle(std::function<Callback> callback, FileWatchEvent* event);
|
2024-06-02 21:35:05 -04:00
|
|
|
FileWatchFilter(std::filesystem::path const& path);
|
2023-04-27 02:22:56 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Watch a file for changes. Whenever the file is modified on disk, a
|
|
|
|
* FileWatchEvent is emitted. Add an EventListener with FileWatchFilter
|
|
|
|
* to catch these events
|
|
|
|
* @param file The file to watch
|
|
|
|
* @note Watching uses file system equivalence instead of path equivalence,
|
|
|
|
* so different paths that point to the same file will be considered the
|
|
|
|
* same
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL Result<> watchFile(std::filesystem::path const& file);
|
2023-04-27 02:22:56 -04:00
|
|
|
/**
|
|
|
|
* Stop watching a file for changes
|
|
|
|
* @param file The file to unwatch
|
|
|
|
*/
|
2024-06-02 21:35:05 -04:00
|
|
|
GEODE_DLL void unwatchFile(std::filesystem::path const& file);
|
2022-07-30 12:24:03 -04:00
|
|
|
}
|