1 /*
2  * Xournal++
3  *
4  * Helper for reading / writing files
5  *
6  * @author Xournal++ Team
7  * https://github.com/xournalpp/xournalpp
8  *
9  * @license GNU GPLv2 or later
10  */
11 
12 #pragma once
13 
14 #include <cstring>
15 #include <optional>
16 
17 #include <gio/gio.h>
18 
19 #include "filesystem.h"
20 
21 namespace Util {
22 /**
23  * Read a file to a string
24  *
25  * @param path Path to read
26  * @param showErrorToUser Show an error to the user, if the file could not be read
27  *
28  * @return contents if the file was read, std::nullopt if not
29  */
30 [[maybe_unused]] [[nodiscard]] std::optional<std::string> readString(fs::path const& path, bool showErrorToUser = true);
31 
32 /**
33  * Get escaped path, all " and \ are escaped
34  */
35 [[maybe_unused]] [[nodiscard]] std::string getEscapedPath(const fs::path& path);
36 
37 /**
38  * @return true if this file has .xopp or .xoj extension
39  */
40 [[maybe_unused]] [[nodiscard]] bool hasXournalFileExt(const fs::path& path);
41 
42 /**
43  * Clear the the last known xournal extension (last .xoj, .xopp etc.)
44  *
45  * @param ext An extension to clear additionally, eg .pdf (would also clear
46  *  .pdf.xopp etc.)
47  */
48 void clearExtensions(fs::path& path, const std::string& ext = "");
49 
50 // Uri must be ASCII-encoded!
51 [[maybe_unused]] [[nodiscard]] std::optional<fs::path> fromUri(const std::string& uri);
52 
53 [[maybe_unused]] [[nodiscard]] std::optional<std::string> toUri(const fs::path& path);
54 
55 
56 [[maybe_unused]] [[nodiscard]] fs::path fromGFile(GFile* file);
57 [[maybe_unused]] [[nodiscard]] GFile* toGFile(fs::path const& path);
58 
59 [[maybe_unused]] [[nodiscard]] inline fs::path fromGFilename(char* path, bool owned = true) {
60     auto deleter = [path, owned]() {
61         if (owned) {
62             g_free(path);
63         }
64     };
65 
66     if (path == nullptr) {
67         return {};
68     }
69     size_t pSize{0};
70     GError* err{};
71     auto* u8Path = g_filename_to_utf8(path, std::strlen(path), nullptr, &pSize, &err);
72     if (err) {
73         g_message("Failed to convert g_filename to utf8 with error code: %d\n%s", err->code, err->message);
74         g_error_free(err);
75         deleter();
76         return {};
77     }
78     auto ret = fs::u8path(u8Path, u8Path + pSize);
79     g_free(u8Path);
80     deleter();
81     return ret;
82 }
83 
toGFilename(fs::path const & path)84 [[maybe_unused]] [[nodiscard]] inline std::string toGFilename(fs::path const& path) {
85     auto u8path = path.u8string();
86     size_t pSize{0};
87     GError* err{};
88     auto* local = g_filename_from_utf8(u8path.c_str(), ssize_t(u8path.size()), nullptr, &pSize, &err);
89     if (err) {
90         g_message("Failed to convert g_filename from utf8 with error code: %d\n%s", err->code, err->message);
91         g_error_free(err);
92         return {};
93     }
94     auto ret = std::string{local, pSize};
95     g_free(local);
96     return ret;
97 }
98 
99 
100 void openFileWithDefaultApplication(const fs::path& filename);
101 void openFileWithFilebrowser(const fs::path& filename);
102 
103 [[maybe_unused]] [[nodiscard]] bool isChildOrEquivalent(fs::path const& path, fs::path const& base);
104 
105 [[maybe_unused]] bool safeRenameFile(fs::path const& from, fs::path const& to);
106 
107 [[maybe_unused]] fs::path ensureFolderExists(const fs::path& p);
108 
109 /**
110  * Convert to platform compatible path. Call this before
111  * passing a path to another program.
112  */
113 fs::path getLongPath(const fs::path& path);
114 
115 /**
116  * Return the configuration folder path (may not be guaranteed to exist).
117  */
118 [[maybe_unused]] [[nodiscard]] fs::path getConfigFolder();
119 [[maybe_unused]] [[nodiscard]] fs::path getConfigSubfolder(const fs::path& subfolder = "");
120 [[maybe_unused]] [[nodiscard]] fs::path getCacheSubfolder(const fs::path& subfolder = "");
121 [[maybe_unused]] [[nodiscard]] fs::path getDataSubfolder(const fs::path& subfolder = "");
122 [[maybe_unused]] [[nodiscard]] fs::path getConfigFile(const fs::path& relativeFileName = "");
123 [[maybe_unused]] [[nodiscard]] fs::path getCacheFile(const fs::path& relativeFileName = "");
124 [[maybe_unused]] [[nodiscard]] fs::path getTmpDirSubfolder(const fs::path& subfolder = "");
125 [[maybe_unused]] [[nodiscard]] fs::path getAutosaveFilepath();
126 [[maybe_unused]] [[nodiscard]] fs::path getGettextFilepath(const char* localeDir);
127 
128 }  // namespace Util
129