1 /*
2  * Copyright (C) 2002-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_LOGIC_GENERIC_SAVE_HANDLER_H
21 #define WL_LOGIC_GENERIC_SAVE_HANDLER_H
22 
23 #include <functional>
24 
25 #include "io/filesystem/filesystem.h"
26 
27 /**
28  * Class that provides handling all errors for generic file saving.
29  * It stores error codes and error messages.
30  * It can also generate an overview message aimed at a human user.
31  *
32  * The saving routine (what actually writes data to a file system)
33  * must be provided.
34  */
35 // TODO(Arty): Possibly make it more generic, allowing to provide options
36 // whether to overwrite files, whether to make backups, maybe allow
37 // to provide a naming scheme, etc.
38 class GenericSaveHandler {
39 public:
40 	// error constants; also usable as bit masks
41 	enum class Error : uint32_t {
42 		kNone = 0,
43 		kSuccess = 0,
44 		kCreatingDirFailed = 1,
45 		kBackupFailed = 2,
46 		kDeletingBackupFailed = 4,
47 		kSavingDataFailed = 8,
48 		kCorruptFileLeft = 16,
49 		kRestoringBackupFailed = 32,
50 		kUnexpectedError = 64,
51 		kAllErrors = 127
52 	};
53 
GenericSaveHandler(std::function<void (FileSystem &)> do_save,std::string complete_filename,FileSystem::Type type)54 	explicit GenericSaveHandler(std::function<void(FileSystem&)>
55 	                               do_save,  // function that actually saves data to the filesystem
56 	                            std::string complete_filename,
57 	                            FileSystem::Type type)
58 	   : do_save_(do_save),
59 	     complete_filename_(complete_filename),
60 	     dir_(FileSystem::fs_dirname(complete_filename.c_str())),
61 	     filename_(FileSystem::fs_filename(complete_filename.c_str())),
62 	     type_(type),
63 	     error_(static_cast<Error>(1132)) {
64 	}
65 
66 	/**
67 	 * Tries to save a file.
68 	 *
69 	 * If the file already exists, it will be overwritten but a temporary backup
70 	 * is made, which will be restored if saving fails and deleted otherwise.
71 	 *
72 	 * Catches ALL errors.
73 	 *
74 	 * Error messages for all errors are written to the log but also stored.
75 	 * Stores and returns an error code (bit mask of all occurred errors).
76 	 */
77 	Error save();
78 
79 	// returns the stored error code (of the last saving operation)
error()80 	Error error() {
81 		return error_;
82 	}
83 
84 	// Returns the combination of error_messages (of occurred errors)
85 	// specified by a bit mask.
86 	std::string error_message(Error error_mask = Error::kAllErrors);
87 
88 	// Generates a localized formatted message describing the result of
89 	// the last saving attempt.
90 	// Aimed to be sufficiently informative for a human user.
91 	std::string localized_formatted_result_message();
92 
93 private:
94 	std::function<void(FileSystem&)> do_save_;
95 	std::string complete_filename_;
96 	std::string dir_;
97 	std::string filename_;
98 	FileSystem::Type type_;
99 
100 	// Backup filename is automatically generated when saving but is also
101 	// stored for generating messages containing backup-related things.
102 	std::string backup_filename_;
103 
104 	Error error_;
105 
106 	static constexpr uint32_t maxErrors_ = 7;
107 	static_assert((1ul << maxErrors_) == static_cast<uint32_t>(Error::kAllErrors) + 1,
108 	              "value of maxErrors_ doesn't match!");
109 	std::string error_msg_[maxErrors_];
110 
111 	// Returns the lowest array index of the an error.
112 	// Intended for use with single errors to get their array index.
113 	uint32_t get_index(Error);
114 
115 	void clear();
116 
117 	// Finds a suitable backup filename and tries to rename a file.
118 	// Stores an errorcode and error message (if applicable).
119 	void make_backup();
120 
121 	// Saves a file. Assumes file doesn't exist yet.
122 	// Stores an errorcode and error message (if applicable).
123 	void save_file();
124 };
125 
126 inline constexpr GenericSaveHandler::Error operator|(GenericSaveHandler::Error e1,
127                                                      GenericSaveHandler::Error e2) {
128 	return static_cast<GenericSaveHandler::Error>(static_cast<uint32_t>(e1) |
129 	                                              static_cast<uint32_t>(e2));
130 }
131 
132 inline constexpr GenericSaveHandler::Error operator&(GenericSaveHandler::Error e1,
133                                                      GenericSaveHandler::Error e2) {
134 	return static_cast<GenericSaveHandler::Error>(static_cast<uint32_t>(e1) &
135 	                                              static_cast<uint32_t>(e2));
136 }
137 
138 inline GenericSaveHandler::Error& operator|=(GenericSaveHandler::Error& e1,
139                                              GenericSaveHandler::Error e2) {
140 	return e1 = e1 | e2;
141 }
142 
143 inline GenericSaveHandler::Error& operator&=(GenericSaveHandler::Error& e1,
144                                              GenericSaveHandler::Error e2) {
145 	return e1 = e1 & e2;
146 }
147 
148 #endif  // end of include guard: WL_LOGIC_GENERIC_SAVE_HANDLER_H
149