The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
filesystem.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * Declarations for File-IO.
19 */
20
21#pragma once
22
23#include <chrono>
24#include <cstdint>
25#include <fstream>
26#include <iosfwd>
27#include <memory>
28#include <string>
29#include <vector>
30
31#include "exceptions.hpp"
32#include "game_version.hpp"
33#include "global.hpp"
35
36namespace game_config {
37extern std::string path;
38extern std::string default_preferences_path;
39extern bool check_migration;
40
41/** observer team name used for observer team chat */
42extern const std::string observer_team_name;
43
45}
46
47class config;
49
50namespace filesystem {
51
52using scoped_istream = std::unique_ptr<std::istream>;
53using scoped_ostream = std::unique_ptr<std::ostream>;
54
55/** An exception object used when an IO error occurs */
56struct io_exception : public game::error {
58 io_exception(const std::string& msg) : game::error(msg) {}
59};
60
61struct file_tree_checksum;
62
66
67// default extensions
68extern const std::string map_extension;
69extern const std::string mask_extension;
70extern const std::string wml_extension;
71
72// A list of file and directory blacklist patterns
74{
75public:
77
78 blacklist_pattern_list(std::vector<std::string> file_patterns, std::vector<std::string> directory_patterns)
79 : file_patterns_(std::move(file_patterns)), directory_patterns_(std::move(directory_patterns))
80 {}
81
82 bool match_file(const std::string& name) const;
83
84 bool match_dir(const std::string& name) const;
85
86 void add_file_pattern(std::string pattern)
87 {
88 file_patterns_.push_back(std::move(pattern));
89 }
90
91 void add_directory_pattern(std::string pattern)
92 {
93 directory_patterns_.push_back(std::move(pattern));
94 }
95
96 void remove_blacklisted_files_and_dirs(std::vector<std::string>& files, std::vector<std::string>& directories) const;
97
98private:
99 std::vector<std::string> file_patterns_;
100 std::vector<std::string> directory_patterns_;
101};
102
104
105/**
106 * Get a list of all files and/or directories in a given directory.
107 *
108 * @param dir The directory to examine.
109 * @param[out] files The files in @a dir. Won't be used if nullptr.
110 * @param[out] dirs The directories in @a dir. Won't be used if nullptr.
111 * @param mode Determines whether the entire path or just the filename is retrieved.
112 * @param filter Determines if we skip images and sounds directories.
113 * @param reorder Triggers the special handling of _main.cfg and _final.cfg.
114 * @param[out] checksum Can be used to store checksum info.
115 */
116void get_files_in_dir(const std::string &dir,
117 std::vector<std::string>* files,
118 std::vector<std::string>* dirs=nullptr,
122 file_tree_checksum* checksum = nullptr);
123
124std::string get_dir(const std::string &dir);
125
126/**
127 * Try to autodetect the location of the game data dir. Note that
128 * the root of the source tree currently doubles as the data dir.
129 */
130std::string autodetect_game_data_dir(std::string exe_dir);
131
132// The location of various important files/folders:
133/**
134 * location of preferences file containing preferences that are synced between computers
135 * note that wesnoth does not provide the syncing functionality itself
136 */
137std::string get_synced_prefs_file();
138/** location of preferences file containing preferences that aren't synced between computers */
139std::string get_unsynced_prefs_file();
140std::string get_credentials_file();
141std::string get_default_prefs_file();
142std::string get_save_index_file();
143std::string get_lua_history_file();
144/** location of the game manual file correponding to the given locale (default: en) */
145utils::optional<std::string> get_game_manual_file(const std::string& locale_code, const std::string& short_locale_code);
146/**
147 * parent directory for everything that should be synced between systems.
148 * implemented due to limitations of Steam's AutoCloud (non-SDK) syncing, but will also simplify things if it's ever added for any other platforms.
149 */
150std::string get_sync_dir();
151std::string get_saves_dir();
152std::string get_wml_persist_dir();
153std::string get_intl_dir();
154std::string get_screenshot_dir();
155std::string get_addons_data_dir();
156std::string get_addons_dir();
157std::string get_current_editor_dir(const std::string& addon_id);
158const std::string get_version_path_suffix(const version_info& version);
159const std::string& get_version_path_suffix();
160
161/**
162 * Get the next free filename using "name + number (3 digits) + extension"
163 * maximum 1000 files then start always giving 999
164 */
165std::string get_next_filename(const std::string& name, const std::string& extension);
166
168void set_user_data_dir(std::string path);
169void set_cache_dir(const std::string& path);
170
171std::string get_user_data_dir();
172std::string get_logs_dir();
173std::string get_cache_dir();
174std::string get_legacy_editor_dir();
175std::string get_core_images_dir();
176
177bool rename_dir(const std::string& old_dir, const std::string& new_dir);
178
180{
181 /**
182 * Here the version is given as a string instead of a version_info, because the
183 * logic of how many components are significant ("1.16" rather than
184 * "1.16.0") is encapsulated in find_other_version_saves_dirs().
185 */
186 std::string version;
187 std::string path;
188
189 // constructor because emplace_back() doesn't use aggregate initialization
190 other_version_dir(const std::string& v, const std::string& p)
191 : version(v)
192 , path(p)
193 {
194 }
195};
196
197/**
198 * Searches for directories containing saves created by other versions of Wesnoth.
199 *
200 * The directories returned will exist, but might not contain any saves. Changes to
201 * the filesystem (by running other versions or by deleting old directories) may
202 * change the results returned by the function.
203 */
204std::vector<other_version_dir> find_other_version_saves_dirs();
205
206std::string get_cwd();
207bool set_cwd(const std::string& dir);
208
209std::string get_exe_path();
210std::string get_exe_dir();
211std::string get_wesnothd_name();
212
213bool make_directory(const std::string& dirname);
214bool delete_directory(const std::string& dirname, const bool keep_pbl = false);
215bool delete_file(const std::string& filename);
216
217bool looks_like_pbl(const std::string& file);
218
219// Basic disk I/O:
220
221/** Basic disk I/O - read file. */
222std::string read_file(const std::string& fname);
223std::vector<uint8_t> read_file_binary(const std::string& fname);
224std::string read_file_as_data_uri(const std::string& fname);
225
226filesystem::scoped_istream istream_file(const std::string& fname, bool treat_failure_as_error = true);
227filesystem::scoped_ostream ostream_file(const std::string& fname, std::ios_base::openmode mode = std::ios_base::binary, bool create_directory = true);
228/** Throws io_exception if an error occurs. */
229void write_file(const std::string& fname, const std::string& data, std::ios_base::openmode mode = std::ios_base::binary);
230/**
231 * Read a file and then writes it back out.
232 *
233 * @param src The source file.
234 * @param dest The destination of the copied file.
235 */
236void copy_file(const std::string& src, const std::string& dest);
237
238std::string get_map_file(const std::string& name);
239std::string get_scenario_file(const std::string& name);
240
241std::string read_map(const std::string& name);
242std::string read_scenario(const std::string& name);
243
244/**
245 * Creates a directory if it does not exist already.
246 *
247 * @param dirname Path to directory. All parents should exist.
248 * @returns True if the directory exists or could be
249 * successfully created; false otherwise.
250 */
251bool create_directory_if_missing(const std::string& dirname);
252/**
253 * Creates a recursive directory tree if it does not exist already
254 * @param dirname Full path of target directory. Non existing parents
255 * will be created
256 * @return True if the directory exists or could be
257 * successfully created; false otherwise.
258 */
259bool create_directory_if_missing_recursive(const std::string& dirname);
260
261/** Returns true if the given file is a directory. */
262bool is_directory(const std::string& fname);
263
264/** Returns true if a file or directory with such name already exists. */
265bool file_exists(const std::string& name);
266
267/** Get the modification time of a file. */
268std::chrono::system_clock::time_point file_modified_time(const std::string& fname);
269
270/** Returns true if the file ends with the mapfile extension. */
271bool is_map(const std::string& filename);
272
273/** Returns true if the file ends with the wmlfile extension. */
274bool is_cfg(const std::string& filename);
275
276/** Returns true if the file ends with the maskfile extension. */
277bool is_mask(const std::string& filename);
278
279/** Returns true if the file ends with '.gz'. */
280bool is_gzip_file(const std::string& filename);
281
282/** Returns true if the file ends with '.bz2'. */
283bool is_bzip2_file(const std::string& filename);
284
285inline bool is_compressed_file(const std::string& filename) {
287}
288
289/**
290 * Returns whether the given filename is a legal name for a user-created file.
291 *
292 * This is meant to be used for any files created by Wesnoth where user input
293 * is required, including save files and add-on files for uploading to the
294 * add-ons server.
295 *
296 * @param name File name to verify.
297 * @param allow_whitespace Whether whitespace should be allowed.
298 */
299bool is_legal_user_file_name(const std::string& name, bool allow_whitespace = true);
300
302{
304 explicit file_tree_checksum(const config& cfg);
305 void write(config& cfg) const;
306 // @todo make variables private!
307 std::size_t nfiles{}, sum_size{};
308 std::chrono::system_clock::time_point modified{};
309 bool operator==(const file_tree_checksum &rhs) const;
310 bool operator!=(const file_tree_checksum &rhs) const
311 { return !operator==(rhs); }
312};
313
314/** Get the time at which the data/ tree was last modified at. */
315const file_tree_checksum& data_tree_checksum(bool reset = false);
316
317/** Returns the size of a file, or -1 if the file doesn't exist. */
318int file_size(const std::string& fname);
319
320/** Returns the sum of the sizes of the files contained in a directory. */
321int dir_size(const std::string& path);
322
323/**
324 * Returns the base filename of a file, with directory name stripped.
325 * Equivalent to a portable basename() function.
326 *
327 * If @a remove_extension is true, the filename extension will be stripped
328 * from the returned value.
329 */
330std::string base_name(const std::string& file, const bool remove_extension = false);
331
332/**
333 * Returns the directory name of a file, with filename stripped.
334 * Equivalent to a portable dirname()
335 */
336std::string directory_name(const std::string& file);
337
338/**
339 * Finds the nearest parent in existence for a file or directory.
340 *
341 * @note The file's own existence is not checked.
342 *
343 * @returns An absolute path to the closest parent of the given path, or an
344 * empty string if none could be found. While on POSIX platforms this
345 * cannot happen (unless the original path was already empty), on
346 * Windows it might be the case that the original path refers to a
347 * drive letter or network share that does not exist.
348 */
349std::string nearest_extant_parent(const std::string& file);
350
351/**
352 * Returns the absolute path of a file.
353 *
354 * @param path Original path.
355 * @param normalize_separators Whether to substitute path separators with the
356 * platform's preferred format.
357 * @param resolve_dot_entries Whether to resolve . and .. directory entries.
358 * This requires @a path to refer to a valid
359 * existing object.
360 *
361 * @returns An absolute path -- that is, a path that is independent of the
362 * current working directory for the process. If resolve_dot_entries
363 * is set to true, the returned path has . and .. components resolved;
364 * however, if resolution fails because a component does not exist, an
365 * empty string is returned instead.
366 */
367std::string normalize_path(const std::string& path,
368 bool normalize_separators = false,
369 bool resolve_dot_entries = false);
370
371/** Helper function to convert absolute path to wesnoth relative path */
372utils::optional<std::string> to_asset_path(const std::string& abs_path,
373 const std::string& addon_id,
374 const std::string& asset_type);
375
376/**
377 * Sanitizes a path to remove references to the user's name.
378 */
379std::string sanitize_path(const std::string& path);
380
381/**
382 * Returns whether the path is the root of the file hierarchy.
383 *
384 * @note This function is unreliable for paths that do not exist -- it will
385 * always return @a false for those.
386 */
387bool is_root(const std::string& path);
388
389/**
390 * Returns the name of the root device if included in the given path.
391 *
392 * This only properly makes sense on Windows with paths containing a drive
393 * letter or UNC at the start -- otherwise, it will return the empty string. To
394 * ensure that a suitable root name can be found you might want to use
395 * normalize_path() first with @a resolve_dot_entries set to true.
396 */
397std::string root_name(const std::string& path);
398
399/**
400 * Returns whether the path seems to be relative.
401 */
402bool is_relative(const std::string& path);
403
404/**
405 * Returns whether @a c is a path separator.
406 *
407 * @note / is always a path separator. Additionally, on Windows \\ is a
408 * path separator as well.
409 */
410bool is_path_sep(char c);
411
412/**
413 * Returns the standard path separator for the current platform.
414 */
416
417/**
418 * The paths manager is responsible for recording the various paths
419 * that binary files may be located at.
420 * It should be passed a config object which holds binary path information.
421 * This is in the format
422 *@verbatim
423 * [binary_path]
424 * path=<path>
425 * [/binary_path]
426 * Binaries will be searched for in [wesnoth-path]/data/<path>/images/
427 *@endverbatim
428 */
444
446
447/**
448 * Returns a vector with all possible paths to a given type of binary,
449 * e.g. 'images', 'sounds', etc,
450 */
451NOT_DANGLING const std::vector<std::string>& get_binary_paths(const std::string& type);
452
453/**
454 * Returns a complete path to the actual file of a given @a type, if it exists.
455 */
456utils::optional<std::string> get_binary_file_location(const std::string& type, const std::string& filename);
457
458/**
459 * Returns a complete path to the actual directory of a given @a type, if it exists.
460 */
461utils::optional<std::string> get_binary_dir_location(const std::string &type, const std::string &filename);
462
463/**
464 * Returns a translated path to the actual file or directory, if it exists. @a current_dir is needed to resolve a path starting with ".".
465 */
466utils::optional<std::string> get_wml_location(const std::string& path, const utils::optional<std::string>& current_dir = utils::nullopt);
467
468/**
469 * Returns a short path to @a filename, skipping the (user) data directory.
470 */
471std::string get_short_wml_path(const std::string &filename);
472
473/**
474 * Returns an asset path to @a filename for binary path-independent use in saved games.
475 *
476 * Example:
477 * images, units/konrad-fighter.png ->
478 * data/campaigns/Heir_To_The_Throne/images/units/konrad-fighter.png
479 */
480utils::optional<std::string> get_independent_binary_file_path(const std::string& type, const std::string &filename);
481
482/**
483 * Returns the appropriate invocation for a Wesnoth-related binary, assuming
484 * that it is located in the same directory as the running wesnoth binary.
485 * This is just a string-transformation based on argv[0], so the returned
486 * program is not guaranteed to actually exist. '-debug' variants are handled
487 * correctly.
488 */
489std::string get_program_invocation(const std::string &program_name);
490
491/**
492 * Returns the localized version of the given filename, if it exists.
493 */
494utils::optional<std::string> get_localized_path(const std::string& file, const std::string& suff = "");
495utils::optional<std::string> get_localized_path(const utils::optional<std::string>& base_path);
496
497/**
498 * Returns the add-on ID from a path.
499 * aka the directory directly following the "add-ons" folder, or an empty string if none is found.
500 */
501utils::optional<std::string> get_addon_id_from_path(const std::string& location);
502
503}
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
std::vector< std::string > file_patterns_
bool match_file(const std::string &name) const
void remove_blacklisted_files_and_dirs(std::vector< std::string > &files, std::vector< std::string > &directories) const
void add_file_pattern(std::string pattern)
std::vector< std::string > directory_patterns_
blacklist_pattern_list(std::vector< std::string > file_patterns, std::vector< std::string > directory_patterns)
void add_directory_pattern(std::string pattern)
bool match_dir(const std::string &name) const
A class grating read only view to a vector of config objects, viewed as one config with all children ...
Represents version numbers.
const config * cfg
Interfaces for manipulating version numbers of engine, add-ons, etc.
#define NOT_DANGLING
Definition global.hpp:65
void set_cache_dir(const std::string &path)
std::string get_legacy_editor_dir()
std::string get_cache_dir()
const std::string & get_version_path_suffix()
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with '.bz2'.
int dir_size(const std::string &path)
Returns the sum of the sizes of the files contained in a directory.
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs=nullptr, name_mode mode=name_mode::FILE_NAME_ONLY, filter_mode filter=filter_mode::NO_FILTER, reorder_mode reorder=reorder_mode::DONT_REORDER, file_tree_checksum *checksum=nullptr)
Get a list of all files and/or directories in a given directory.
const std::string wml_extension
bool is_cfg(const std::string &filename)
Returns true if the file ends with the wmlfile extension.
std::string get_user_data_dir()
std::string base_name(const std::string &file, const bool remove_extension=false)
Returns the base filename of a file, with directory name stripped.
std::string get_wml_persist_dir()
bool rename_dir(const std::string &old_dir, const std::string &new_dir)
std::string get_exe_path()
bool create_directory_if_missing(const std::string &dirname)
Creates a directory if it does not exist already.
void copy_file(const std::string &src, const std::string &dest)
Read a file and then writes it back out.
bool delete_file(const std::string &filename)
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with '.gz'.
std::string get_map_file(const std::string &name)
std::string get_exe_dir()
bool is_legal_user_file_name(const std::string &name, bool allow_whitespace=true)
Returns whether the given filename is a legal name for a user-created file.
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::string get_synced_prefs_file()
location of preferences file containing preferences that are synced between computers note that wesno...
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir=utils::nullopt)
Returns a translated path to the actual file or directory, if it exists.
std::string get_saves_dir()
const file_tree_checksum & data_tree_checksum(bool reset=false)
Get the time at which the data/ tree was last modified at.
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 read_file(const std::string &fname)
Basic disk I/O - read file.
std::string get_unsynced_prefs_file()
location of preferences file containing preferences that aren't synced between computers
std::string get_save_index_file()
const std::string map_extension
bool is_compressed_file(const std::string &filename)
utils::optional< 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, if it exists.
bool create_directory_if_missing_recursive(const std::string &dirname)
Creates a recursive directory tree if it does not exist already.
int file_size(const std::string &fname)
Returns the size of a file, or -1 if the file doesn't exist.
bool is_mask(const std::string &filename)
Returns true if the file ends with the maskfile extension.
utils::optional< std::string > get_addon_id_from_path(const std::string &location)
Returns the add-on ID from a path.
std::string get_lua_history_file()
std::string autodetect_game_data_dir(std::string exe_dir)
Try to autodetect the location of the game data dir.
std::string read_file_as_data_uri(const std::string &fname)
std::string get_dir(const std::string &dir)
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode=std::ios_base::binary, bool create_directory=true)
std::string read_scenario(const std::string &name)
const std::string mask_extension
std::unique_ptr< std::istream > scoped_istream
void clear_binary_paths_cache()
std::string get_screenshot_dir()
std::string get_credentials_file()
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode=std::ios_base::binary)
Throws io_exception if an error occurs.
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::string root_name(const std::string &path)
Returns the name of the root device if included in the given path.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
std::string get_logs_dir()
std::unique_ptr< std::ostream > scoped_ostream
utils::optional< 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, if it exists.
bool is_userdata_initialized()
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
char path_separator()
Returns the standard path separator for the current platform.
std::string get_sync_dir()
parent directory for everything that should be synced between systems.
bool looks_like_pbl(const std::string &file)
std::string get_addons_data_dir()
bool is_map(const std::string &filename)
Returns true if the file ends with the mapfile extension.
bool make_directory(const std::string &dirname)
utils::optional< std::string > get_independent_binary_file_path(const std::string &type, const std::string &filename)
Returns an asset path to filename for binary path-independent use in saved games.
bool delete_directory(const std::string &dirname, const bool keep_pbl=false)
std::string get_scenario_file(const std::string &name)
std::string get_wesnothd_name()
std::chrono::system_clock::time_point file_modified_time(const std::string &fname)
Get the modification time of a file.
std::string get_default_prefs_file()
utils::optional< std::string > get_game_manual_file(const std::string &locale_code, const std::string &short_locale_code)
location of the game manual file correponding to the given locale (default: en)
const blacklist_pattern_list default_blacklist
std::string get_addons_dir()
bool set_cwd(const std::string &dir)
utils::optional< std::string > get_localized_path(const std::string &file, const std::string &suff="")
Returns the localized version of the given filename, if it exists.
std::vector< other_version_dir > find_other_version_saves_dirs()
Searches for directories containing saves created by other versions of Wesnoth.
void set_user_data_dir(std::string path)
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...
std::string get_intl_dir()
std::string get_core_images_dir()
std::vector< uint8_t > read_file_binary(const std::string &fname)
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user's name.
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error=true)
std::string get_current_editor_dir(const std::string &addon_id)
bool is_path_sep(char c)
Returns whether c is a path separator.
std::string read_map(const std::string &name)
std::string get_cwd()
utils::optional< std::string > to_asset_path(const std::string &abs_path, const std::string &addon_id, const std::string &asset_type)
Helper function to convert absolute path to wesnoth relative path.
std::string normalize_path(const std::string &path, bool normalize_separators=false, bool resolve_dot_entries=false)
Returns the absolute path of a file.
NOT_DANGLING 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.
Game configuration data as global variables.
std::string path
std::string default_preferences_path
const std::string observer_team_name
observer team name used for observer team chat
int cache_compression_level
bool check_migration
STL namespace.
std::string_view data
Definition picture.cpp:188
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
The paths manager is responsible for recording the various paths that binary files may be located at.
std::vector< std::string > paths_
binary_paths_manager & operator=(const binary_paths_manager &o)=delete
binary_paths_manager(const binary_paths_manager &o)=delete
binary_paths_manager(const game_config_view &cfg)
void set_paths(const game_config_view &cfg)
bool operator==(const file_tree_checksum &rhs) const
std::chrono::system_clock::time_point modified
bool operator!=(const file_tree_checksum &rhs) const
An exception object used when an IO error occurs.
io_exception(const std::string &msg)
std::string version
Here the version is given as a string instead of a version_info, because the logic of how many compon...
other_version_dir(const std::string &v, const std::string &p)
Base class for all the errors encountered by the engine.
mock_party p
#define c