The Battle for Wesnoth  1.15.1+dev
filesystem.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Declarations for File-IO.
18  */
19 
20 #pragma once
21 
22 #include <algorithm>
23 #include <ctime>
24 #include <functional>
25 #include <iosfwd>
26 #include <string>
27 #include <vector>
28 #include <memory>
29 
30 #include "exceptions.hpp"
32 
33 class config;
34 
35 struct SDL_RWops;
36 
37 namespace filesystem {
38 
39 using scoped_istream = std::unique_ptr<std::istream>;
40 using scoped_ostream = std::unique_ptr<std::ostream>;
41 
42 typedef std::unique_ptr<SDL_RWops, void(*)(SDL_RWops*)> rwops_ptr;
43 
44 rwops_ptr make_read_RWops(const std::string &path);
45 rwops_ptr make_write_RWops(const std::string &path);
46 
47 /** An exception object used when an IO error occurs */
48 struct io_exception : public game::error {
49  io_exception() : game::error("") {}
50  io_exception(const std::string& msg) : game::error(msg) {}
51 };
52 
53 struct file_tree_checksum;
54 
58 
59 // A list of file and directory blacklist patterns
61 {
62 public:
64  : file_patterns_(), directory_patterns_()
65  {}
66  blacklist_pattern_list(const std::vector<std::string>& file_patterns, const std::vector<std::string>& directory_patterns)
67  : file_patterns_(file_patterns), directory_patterns_(directory_patterns)
68  {}
69 
70  bool match_file(const std::string& name) const
71  {
72  return std::any_of(file_patterns_.begin(), file_patterns_.end(),
73  std::bind(&utils::wildcard_string_match, std::ref(name), std::placeholders::_1));
74  }
75 
76  bool match_dir(const std::string& name) const
77  {
78  return std::any_of(directory_patterns_.begin(), directory_patterns_.end(),
79  std::bind(&utils::wildcard_string_match, std::ref(name), std::placeholders::_1));
80  }
81 
82  void add_file_pattern(const std::string& pattern)
83  {
84  file_patterns_.push_back(pattern);
85  }
86 
87  void add_directory_pattern(const std::string& pattern)
88  {
89  directory_patterns_.push_back(pattern);
90  }
91 
92  void remove_blacklisted_files_and_dirs(std::vector<std::string>& files, std::vector<std::string>& directories) const;
93 
94 private:
95  std::vector<std::string> file_patterns_;
96  std::vector<std::string> directory_patterns_;
97 };
98 
100  {
101  /* Blacklist dot-files/dirs, which are hidden files in UNIX platforms */
102  ".+",
103  "#*#",
104  "*~",
105  "*-bak",
106  "*.swp",
107  "*.pbl",
108  "*.ign",
109  "_info.cfg",
110  "*.exe",
111  "*.bat",
112  "*.cmd",
113  "*.com",
114  "*.scr",
115  "*.sh",
116  "*.js",
117  "*.vbs",
118  "*.o",
119  "*.ini",
120  /* Remove junk created by certain file manager ;) */
121  "Thumbs.db",
122  /* Eclipse plugin */
123  "*.wesnoth",
124  "*.project",
125  },
126  {
127  ".+",
128  /* macOS metadata-like cruft (http://floatingsun.net/2007/02/07/whats-with-__macosx-in-zip-files/) */
129  "__MACOSX",
130  }
131 };
132 
133 /** Some tasks to run on startup. */
134 void init();
135 
136 /**
137  * Populates 'files' with all the files and
138  * 'dirs' with all the directories in dir.
139  * If files or dirs are nullptr they will not be used.
140  *
141  * mode: determines whether the entire path or just the filename is retrieved.
142  * filter: determines if we skip images and sounds directories
143  * reorder: triggers the special handling of _main.cfg and _final.cfg
144  * checksum: can be used to store checksum info
145  */
146 void get_files_in_dir(const std::string &dir,
147  std::vector<std::string>* files,
148  std::vector<std::string>* dirs=nullptr,
149  file_name_option mode = FILE_NAME_ONLY,
150  file_filter_option filter = NO_FILTER,
152  file_tree_checksum* checksum = nullptr);
153 
154 std::string get_dir(const std::string &dir);
155 
156 // The location of various important files:
157 std::string get_prefs_file();
158 std::string get_credentials_file();
159 std::string get_default_prefs_file();
160 std::string get_save_index_file();
161 std::string get_saves_dir();
162 std::string get_intl_dir();
163 std::string get_screenshot_dir();
164 std::string get_addons_dir();
165 
166 /**
167  * Get the next free filename using "name + number (3 digits) + extension"
168  * maximum 1000 files then start always giving 999
169  */
170 std::string get_next_filename(const std::string& name, const std::string& extension);
171 void set_user_config_dir(const std::string& path);
172 void set_user_data_dir(std::string path);
173 
174 std::string get_user_config_dir();
175 std::string get_user_data_dir();
176 std::string get_cache_dir();
177 
178 std::string get_cwd();
179 std::string get_exe_dir();
180 
181 bool make_directory(const std::string& dirname);
182 bool delete_directory(const std::string& dirname, const bool keep_pbl = false);
183 bool delete_file(const std::string &filename);
184 
185 bool looks_like_pbl(const std::string& file);
186 
187 // Basic disk I/O:
188 
189 /** Basic disk I/O - read file. */
190 std::string read_file(const std::string &fname);
191 filesystem::scoped_istream istream_file(const std::string& fname, bool treat_failure_as_error = true);
192 filesystem::scoped_ostream ostream_file(const std::string& fname, bool create_directory = true);
193 /** Throws io_exception if an error occurs. */
194 void write_file(const std::string& fname, const std::string& data);
195 
196 std::string read_map(const std::string& name);
197 
198 /**
199  * Creates a directory if it does not exist already.
200  *
201  * @param dirname Path to directory. All parents should exist.
202  * @returns True if the directory exists or could be
203  * successfully created; false otherwise.
204  */
205 bool create_directory_if_missing(const std::string& dirname);
206 /**
207  * Creates a recursive directory tree if it does not exist already
208  * @param dirname Full path of target directory. Non existing parents
209  * will be created
210  * @return True if the directory exists or could be
211  * successfully created; false otherwise.
212  */
213 bool create_directory_if_missing_recursive(const std::string& dirname);
214 
215 /** Returns true if the given file is a directory. */
216 bool is_directory(const std::string& fname);
217 
218 /** Returns true if a file or directory with such name already exists. */
219 bool file_exists(const std::string& name);
220 
221 /** Get the modification time of a file. */
222 std::time_t file_modified_time(const std::string& fname);
223 
224 /** Returns true if the file ends with '.gz'. */
225 bool is_gzip_file(const std::string& filename);
226 
227 /** Returns true if the file ends with '.bz2'. */
228 bool is_bzip2_file(const std::string& filename);
229 
230 inline bool is_compressed_file(const std::string& filename) {
231  return is_gzip_file(filename) || is_bzip2_file(filename);
232 }
233 
235 {
237  explicit file_tree_checksum(const config& cfg);
238  void write(config& cfg) const;
239  void reset() {nfiles = 0;modified = 0;sum_size=0;}
240  // @todo make variables private!
241  std::size_t nfiles, sum_size;
242  std::time_t modified;
243  bool operator==(const file_tree_checksum &rhs) const;
244  bool operator!=(const file_tree_checksum &rhs) const
245  { return !operator==(rhs); }
246 };
247 
248 /** Get the time at which the data/ tree was last modified at. */
249 const file_tree_checksum& data_tree_checksum(bool reset = false);
250 
251 /** Returns the size of a file, or -1 if the file doesn't exist. */
252 int file_size(const std::string& fname);
253 
254 /** Returns the sum of the sizes of the files contained in a directory. */
255 int dir_size(const std::string& path);
256 
257 bool ends_with(const std::string& str, const std::string& suffix);
258 
259 /**
260  * Returns the base filename of a file, with directory name stripped.
261  * Equivalent to a portable basename() function.
262  *
263  * If @a remove_extension is true, the filename extension will be stripped
264  * from the returned value.
265  */
266 std::string base_name(const std::string& file, const bool remove_extension = false);
267 
268 /**
269  * Returns the directory name of a file, with filename stripped.
270  * Equivalent to a portable dirname()
271  */
272 std::string directory_name(const std::string& file);
273 
274 /**
275  * Finds the nearest parent in existence for a file or directory.
276  *
277  * @note The file's own existence is not checked.
278  *
279  * @returns An absolute path to the closest parent of the given path, or an
280  * empty string if none could be found. While on POSIX platforms this
281  * cannot happen (unless the original path was already empty), on
282  * Windows it might be the case that the original path refers to a
283  * drive letter or network share that does not exist.
284  */
285 std::string nearest_extant_parent(const std::string& file);
286 
287 /**
288  * Returns the absolute path of a file.
289  *
290  * @param path Original path.
291  * @param normalize_separators Whether to substitute path separators with the
292  * platform's preferred format.
293  * @param resolve_dot_entries Whether to resolve . and .. directory entries.
294  * This requires @a path to refer to a valid
295  * existing object.
296  *
297  * @returns An absolute path -- that is, a path that is independent of the
298  * current working directory for the process. If resolve_dot_entries
299  * is set to true, the returned path has . and .. components resolved;
300  * however, if resolution fails because a component does not exist, an
301  * empty string is returned instead.
302  */
303 std::string normalize_path(const std::string& path,
304  bool normalize_separators = false,
305  bool resolve_dot_entries = false);
306 
307 /**
308  * Sanitizes a path to remove references to the user's name.
309  */
310 std::string sanitize_path(const std::string& path);
311 
312 /**
313  * Returns whether the path is the root of the file hierarchy.
314  *
315  * @note This function is unreliable for paths that do not exist -- it will
316  * always return @a false for those.
317  */
318 bool is_root(const std::string& path);
319 
320 /**
321  * Returns the name of the root device if included in the given path.
322  *
323  * This only properly makes sense on Windows with paths containing a drive
324  * letter or UNC at the start -- otherwise, it will return the empty string. To
325  * ensure that a suitable root name can be found you might want to use
326  * normalize_path() first with @a resolve_dot_entries set to true.
327  */
328 std::string root_name(const std::string& path);
329 
330 /**
331  * Returns whether the path seems to be relative.
332  */
333 bool is_relative(const std::string& path);
334 
335 /**
336  * Returns whether @a c is a path separator.
337  *
338  * @note / is always a path separator. Additionally, on Windows \\ is a
339  * path separator as well.
340  */
341 bool is_path_sep(char c);
342 
343 /**
344  * Returns the standard path separator for the current platform.
345  */
346 char path_separator();
347 
348 /**
349  * The paths manager is responsible for recording the various paths
350  * that binary files may be located at.
351  * It should be passed a config object which holds binary path information.
352  * This is in the format
353  *@verbatim
354  * [binary_path]
355  * path=<path>
356  * [/binary_path]
357  * Binaries will be searched for in [wesnoth-path]/data/<path>/images/
358  *@endverbatim
359  */
361 {
363  binary_paths_manager(const config& cfg);
365 
366  void set_paths(const config& cfg);
367 
368 private:
370  binary_paths_manager& operator=(const binary_paths_manager& o);
371 
372  void cleanup();
373 
374  std::vector<std::string> paths_;
375 };
376 
378 
379 /**
380  * Returns a vector with all possible paths to a given type of binary,
381  * e.g. 'images', 'sounds', etc,
382  */
383 const std::vector<std::string>& get_binary_paths(const std::string& type);
384 
385 /**
386  * Returns a complete path to the actual file of a given @a type
387  * or an empty string if the file isn't present.
388  */
389 std::string get_binary_file_location(const std::string& type, const std::string& filename);
390 
391 /**
392  * Returns a complete path to the actual directory of a given @a type
393  * or an empty string if the directory isn't present.
394  */
395 std::string get_binary_dir_location(const std::string &type, const std::string &filename);
396 
397 /**
398  * Returns a complete path to the actual WML file or directory
399  * or an empty string if the file isn't present.
400  */
401 std::string get_wml_location(const std::string &filename,
402  const std::string &current_dir = std::string());
403 
404 /**
405  * Returns a short path to @a filename, skipping the (user) data directory.
406  */
407 std::string get_short_wml_path(const std::string &filename);
408 
409 /**
410  * Returns an image path to @a filename for binary path-independent use in saved games.
411  *
412  * Example:
413  * units/konrad-fighter.png ->
414  * data/campaigns/Heir_To_The_Throne/images/units/konrad-fighter.png
415  */
416 std::string get_independent_image_path(const std::string &filename);
417 
418 /**
419  * Returns the appropriate invocation for a Wesnoth-related binary, assuming
420  * that it is located in the same directory as the running wesnoth binary.
421  * This is just a string-transformation based on argv[0], so the returned
422  * program is not guaranteed to actually exist. '-debug' variants are handled
423  * correctly.
424  */
425 std::string get_program_invocation(const std::string &program_name);
426 
427 /**
428  * Returns the localized version of the given filename, if it exists.
429  */
430 std::string get_localized_path(const std::string& file, const std::string& suff = "");
431 
432 }
std::string get_binary_dir_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual directory of a given type or an empty string if the directory i...
bool delete_directory(const std::string &dirname, const bool keep_pbl)
Definition: filesystem.cpp:862
std::string get_program_invocation(const std::string &program_name)
Returns the appropriate invocation for a Wesnoth-related binary, assuming that it is located in the s...
std::string get_next_filename(const std::string &name, const std::string &extension)
Get the next free filename using "name + number (3 digits) + extension" maximum 1000 files then start...
Definition: filesystem.cpp:509
bool delete_file(const std::string &filename)
Definition: filesystem.cpp:901
static bool create_directory_if_missing(const bfs::path &dirpath)
Definition: filesystem.cpp:316
bool looks_like_pbl(const std::string &file)
void add_directory_pattern(const std::string &pattern)
Definition: filesystem.hpp:87
void set_user_data_dir(std::string newprefdir)
Definition: filesystem.cpp:622
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:282
bool ends_with(const std::string &str, const std::string &suffix)
rwops_ptr make_read_RWops(const std::string &path)
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
Definition: filesystem.cpp:920
The paths manager is responsible for recording the various paths that binary files may be located at...
Definition: filesystem.hpp:360
bool wildcard_string_match(const std::string &str, const std::string &match)
Match using &#39;*&#39; as any number of characters (including none), &#39;+&#39; as one or more characters, and &#39;?&#39; as any one character.
void init()
Some tasks to run on startup.
Definition: filesystem.cpp:241
std::string get_screenshot_dir()
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn&#39;t prese...
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
std::string get_saves_dir()
static bfs::path get_dir(const bfs::path &dirpath)
Definition: filesystem.cpp:293
io_exception(const std::string &msg)
Definition: filesystem.hpp:50
void clear_binary_paths_cache()
std::string get_cwd()
Definition: filesystem.cpp:809
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:762
bool match_file(const std::string &name) const
Definition: filesystem.hpp:70
rwops_ptr make_write_RWops(const std::string &path)
std::string get_user_data_dir()
Definition: filesystem.cpp:775
std::vector< std::string > directory_patterns_
Definition: filesystem.hpp:96
std::string get_intl_dir()
void write_file(const std::string &fname, const std::string &data)
Throws io_exception if an error occurs.
Definition: filesystem.cpp:981
std::string root_name(const std::string &path)
Returns the name of the root device if included in the given path.
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
std::string path
Definition: game_config.cpp:39
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::string get_independent_image_path(const std::string &filename)
Returns an image path to filename for binary path-independent use in saved games. ...
std::vector< std::string > file_patterns_
Definition: filesystem.hpp:95
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user&#39;s name.
std::string get_default_prefs_file()
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
Definition: filesystem.cpp:912
void add_file_pattern(const std::string &pattern)
Definition: filesystem.hpp:82
std::string read_map(const std::string &name)
bool is_path_sep(char c)
Returns whether c is a path separator.
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:40
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with &#39;.gz&#39;.
std::string get_cache_dir()
Definition: filesystem.cpp:780
const std::vector< std::string > & get_binary_paths(const std::string &type)
Returns a vector with all possible paths to a given type of binary, e.g.
std::string get_exe_dir()
Definition: filesystem.cpp:821
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, file_name_option mode, file_filter_option filter, file_reorder_option reorder, file_tree_checksum *checksum)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
Definition: filesystem.cpp:368
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
void set_user_config_dir(const std::string &newconfigdir)
Definition: filesystem.cpp:732
int dir_size(const std::string &pname)
Returns the sum of the sizes of the files contained in a directory.
std::string get_wml_location(const std::string &filename, const std::string &current_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn&#39;t pres...
std::vector< std::string > paths_
Definition: filesystem.hpp:374
An exception object used when an IO error occurs.
Definition: filesystem.hpp:48
bool operator==(const config &a, const config &b)
Definition: config.cpp:1405
bool make_directory(const std::string &dirname)
Definition: filesystem.cpp:851
bool is_compressed_file(const std::string &filename)
Definition: filesystem.hpp:230
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
std::unique_ptr< SDL_RWops, void(*)(SDL_RWops *)> rwops_ptr
Definition: filesystem.hpp:42
std::string get_localized_path(const std::string &file, const std::string &suff)
Returns the localized version of the given filename, if it exists.
const file_tree_checksum & data_tree_checksum(bool reset=false)
Get the time at which the data/ tree was last modified at.
char path_separator()
Returns the standard path separator for the current platform.
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
int file_size(const std::string &fname)
Returns the size of a file, or -1 if the file doesn&#39;t exist.
std::string get_user_config_dir()
Definition: filesystem.cpp:746
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with &#39;.bz2&#39;.
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
std::string get_addons_dir()
std::string get_credentials_file()
bool operator!=(const file_tree_checksum &rhs) const
Definition: filesystem.hpp:244
blacklist_pattern_list(const std::vector< std::string > &file_patterns, const std::vector< std::string > &directory_patterns)
Definition: filesystem.hpp:66
std::string get_prefs_file()
bool match_dir(const std::string &name) const
Definition: filesystem.hpp:76
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
mock_char c
std::string get_save_index_file()
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
static bool create_directory_if_missing_recursive(const bfs::path &dirpath)
Definition: filesystem.cpp:340
static const blacklist_pattern_list default_blacklist
Definition: filesystem.hpp:99
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)
Definition: filesystem.cpp:958