1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  */
5 
6 #ifndef X_CONFIGMANAGER_H
7 #define X_CONFIGMANAGER_H
8 
9 #include <wx/hashmap.h>
10 #include <wx/hashset.h>
11 
12 #include "settings.h"
13 #include "globals.h"
14 
15 #include <tinyxml.h>
16 #include "manager.h"
17 #include "base64.h"
18 
19 #undef new
20 #include <map>
21 #include <set>
22 
23 
24 /* ------------------------------------------------------------------------------------------------------------------
25 *  Interface Serializable
26 *  ConfigManager can save arbitrary objects and even sets/maps of objects, provided they implement Serializable.
27 *
28 *  Usage:
29 *  ------
30 *   class MySerializableLongIntClass : public ISerializable
31 *   {
32 *   //...
33 *   wxString SerializeOut() const {wxString tmp; tmp << m_int; return tmp;};
34 *   void SerializeIn(const wxString& s){s.ToLong(&m_int);};
35 *   //...
36 *   long int m_int;
37 *   };
38 */
39 class ISerializable
40 {
41 public:
42     ISerializable();
43     virtual ~ISerializable();
44     virtual wxString SerializeOut() const = 0;
45     virtual void SerializeIn(const wxString& s) = 0;
46 };
47 
48 
49 /* ------------------------------------------------------------------------------------------------------------------
50 *  Containers supported by ConfigManager
51 */
52 namespace ConfigManagerContainer
53 {
54     typedef std::map<wxString, wxString> StringToStringMap;
55     typedef std::map<int, wxString> IntToStringMap;
56     typedef std::set<wxString> StringSet;
57 
58     typedef std::map<wxString, ISerializable*> SerializableObjectMap;
59 }
60 
61 
62 /* ------------------------------------------------------------------------------------------------------------------*/
63 /** Search dirs values. Used as a bitmask in ConfigManager::LocateDataFile() and friends.*/
64 enum SearchDirs
65 {
66     sdHome            = 0x0001, ///< User's home directory
67     sdBase            = 0x0002, ///< Code::Blocks' installation base
68     sdTemp            = 0x0004, ///< System-wide temp folder
69     sdPath            = 0x0008, ///< All dirs in the PATH environment variable
70     sdConfig          = 0x0010, ///< Config folder
71     sdCurrent         = 0x0020, ///< Current working folder
72 
73     sdPluginsUser     = 0x0100, ///< Plugins folder in user's dir
74     sdScriptsUser     = 0x0200, ///< Scripts folder in user's dir
75     sdDataUser        = 0x0400, ///< Data folder in user's dir
76 
77     sdAllUser         = 0x0f00, ///< Convenience value meaning "all sd*User values"
78 
79     sdPluginsGlobal   = 0x1000, ///< Plugins folder in base dir
80     sdScriptsGlobal   = 0x2000, ///< Scripts folder in base dir
81     sdDataGlobal      = 0x4000, ///< Data folder in base dir
82 
83     sdAllGlobal       = 0xf000, ///< Convenience value meaning "all sd*Global values"
84 
85     sdAllKnown        = 0xffff  ///< All known dirs (i.e. all of the above)
86 };
87 
88 
89 class CodeBlocksApp;
90 
91 /* ------------------------------------------------------------------------------------------------------------------
92 *  ConfigManager class
93 */
94 class DLLIMPORT ConfigManager
95 {
96     friend class CfgMgrBldr;
97     friend class CodeBlocksApp;
98 
99     TiXmlDocument *doc;
100     TiXmlElement* root;
101     TiXmlElement* pathNode;
102 
103     ConfigManager(TiXmlElement* r);
104     TiXmlElement* AssertPath(wxString& path);
105     TiXmlElement* GetUniqElement(TiXmlElement* p, const wxString& q);
106     void SetNodeText(TiXmlElement *n, const TiXmlText& t);
107     inline void Collapse(wxString& str) const;
108     wxString InvalidNameMessage(const wxString& what, const wxString& sub, TiXmlElement *localPath) const;
109     static void InitPaths();
110     static void MigrateFolders();
111 
112     static wxString config_folder;
113     static wxString home_folder;
114     static wxString data_path_user;
115     static wxString data_path_global;
116 
117 #ifdef CB_AUTOCONF
118     static wxString plugin_path_global;
119 #endif
120     static wxString app_path;
121     static wxString temp_folder;
122     static wxString alternate_user_data_path;
123     static bool has_alternate_user_data_path;
124 
125 protected:
126     //For use by the CodeBlocksApp when the --user-data-dir switch is set
127     //all of the user config and user plugin data will be set relative to this path
128     static bool SetUserDataFolder(const wxString &user_data_path);
129 
130     //Used by CfgMgrBldr internally by ConfigManager
131     static wxString GetUserDataFolder();
132 
133 public:
134 
135     /* -----------------------------------------------------------------------------------------------------
136     *  Utility functions for accessing files/folders in a system-wide, consistent way
137     * -----------------------------------------------------------------------------------------------------*/
138 
139 
140     /** @brief Locate a file in an installation- and platform-independent way.
141     *
142     * You should always use this function if you are looking for "some arbitrary file that belongs to Code::Blocks",
143     * as it works across platforms without any additional effort from your side, and it has some builtin redundancy.
144     * @par
145     * So, code that looked like this in the old days:
146     * @code
147     * wxString some_file = ConfigManager::GetScriptsFolder() + wxFILE_SEP_PATH + _T("startup.script");
148     * @endcode
149     * should be converted to this:
150     * @code
151     * wxString some_file = ConfigManager::LocateDataFile(_T("startup.script"), sdScriptsUser | sdScriptsGlobal);
152     * @endcode
153     * This would try to locate the file named "startup.script" in the global and also in the user's scripts folders.
154     * @note User's dirs @b always have precedence over global dirs.
155     *
156     * @param filename name of the file to search for
157     * @param search_dirs A bit-mask of the folders to include in the search.
158     */
159     static wxString LocateDataFile(const wxString& filename, int search_dirs = sdAllKnown);
160 
161     /** @brief Access one of Code::Blocks' folders.
162       * @param dir The directory to return.
163       */
164     static wxString GetFolder(SearchDirs dir);
165 
166     /* Backwards compatible functions. For new code, please use GetFolder() instead.
167     *
168     * Query "standard" paths that work across platforms.
169     * NEVER hard-code a path like "C:\CodeBlocks\share\data". Always use one of the following functions to compose a path.
170     */
GetHomeFolder()171     static wxString GetHomeFolder() { return GetFolder(sdHome); }
GetConfigFolder()172     static wxString GetConfigFolder(){ return GetFolder(sdConfig); }
173     static wxString GetPluginsFolder(bool global = true){ return GetFolder(global ? sdPluginsGlobal : sdPluginsUser); }
174     static wxString GetScriptsFolder(bool global = true){ return GetFolder(global ? sdScriptsGlobal : sdScriptsUser); }
175     static wxString GetDataFolder(bool global = true){ return GetFolder(global ? sdDataGlobal : sdDataUser); }
GetExecutableFolder()176     static wxString GetExecutableFolder(){ return GetFolder(sdBase); }
GetTempFolder()177     static wxString GetTempFolder(){ return GetFolder(sdTemp); }
178 
179     /*
180     *  Network proxy for HTTP/FTP transfers
181     */
182     static wxString GetProxy();
183 
184     /*
185     *  Builtin revision information
186     */
187     static wxString GetRevisionString();
188     static unsigned int GetRevisionNumber();
189     static wxString GetSvnDate();
190 
ReadDataPath()191     static inline wxString ReadDataPath(){return GetDataFolder();}      // use instead of cfg->Read("data_path");
ReadAppPath()192     static inline wxString ReadAppPath(){return GetExecutableFolder();} // use instead of cfg->Read("app_path");
193 
194 
195 
196     /* -----------------------------------------------------------------------------------------------------
197     *  Path functions for navigation within your configuration namespace
198     */
199     wxString GetPath() const;
200     void SetPath(const wxString& strPath);
201     wxArrayString EnumerateSubPaths(const wxString& path);
202     wxArrayString EnumerateKeys(const wxString& path);
203     void DeleteSubPath(const wxString& strPath);
204 
205     /* -----------------------------------------------------------------------------------------------------
206     *  Clear all nodes from your namespace or delete the namespace (removing it from the config file).
207     *  WARNING: After Delete() returns, the pointer to your instance is invalid. Before you can call ANY member
208     *  function of this class, you have to call Manager::Get()->GetConfigManager() for a valid reference again.
209     *  Note that Delete() is inherently thread-unsafe. You delete an entire namespace of data as well as the object
210     *  responsible of handling that data! Make sure you know what you do.
211     *  This is even more true for DeleteAll() which you should really NEVER use.
212     */
213     void Clear();
214     void Delete();
215     void DeleteAll();
216     void Flush();
217 
218     /* -----------------------------------------------------------------------------------------------------
219     *  Standard primitives
220     */
221     void Write(const wxString& name,  const wxString& value, bool ignoreEmpty = false);
222     wxString Read(const wxString& key, const wxString& defaultVal = wxEmptyString);
223     bool Read(const wxString& key, wxString* str);
224     void Write(const wxString& key, const char* str);
225 
226     void Write(const wxString& name,  int value);
227     bool Read(const wxString& name,  int* value);
228     int  ReadInt(const wxString& name,  int defaultVal = 0);
229 
230     void Write(const wxString& name,  bool value);
231     bool Read(const wxString& name,  bool* value);
232     bool ReadBool(const wxString& name,  bool defaultVal = false);
233 
234     void Write(const wxString& name,  double value);
235     bool Read(const wxString& name,  double* value);
236     double ReadDouble(const wxString& name,  double defaultVal = 0.0f);
237 
238     /* -----------------------------------------------------------------------------------------------------
239     *  Set and unset keys, or test for existence. Note that these functions cannot be used to remove paths
240     *  or test existence of paths (it may be used to implicitly create paths, though).
241     */
242     bool Exists(const wxString& name);
243     void Set(const wxString& name);
244     void UnSet(const wxString& name);
245 
246     /* -----------------------------------------------------------------------------------------------------
247     *  Compound objects
248     */
249     void Write(const wxString& name,  const wxArrayString& as);
250     void Read(const wxString& name,  wxArrayString* as);
251     wxArrayString ReadArrayString(const wxString& name);
252 
253     void WriteBinary(const wxString& name,  const wxString& source);
254     void WriteBinary(const wxString& name,  void* ptr, size_t len);
255     wxString ReadBinary(const wxString& name);
256 
257     void Write(const wxString& name,  const wxColour& c);
258     bool Read(const wxString& name, wxColour* value);
259     wxColour ReadColour(const wxString& name, const wxColour& defaultVal = *wxBLACK);
260 
261 
262     /* -----------------------------------------------------------------------------------------------------
263     *  Single serializable objects
264     */
265     void Write(const wxString& name, const ISerializable& object);
266     bool Read(const wxString& name, ISerializable* object);
267 
268 
269     /* -----------------------------------------------------------------------------------------------------
270     *  Maps and sets of primitive types
271     */
272     void Write(const wxString& name, const ConfigManagerContainer::StringToStringMap& map);
273     void Read(const wxString& name, ConfigManagerContainer::StringToStringMap* map);
274     ConfigManagerContainer::StringToStringMap ReadSSMap(const wxString& name);
275 
276     void Write(const wxString& name, const ConfigManagerContainer::IntToStringMap& map);
277     void Read(const wxString& name, ConfigManagerContainer::IntToStringMap* map);
278     ConfigManagerContainer::IntToStringMap ReadISMap(const wxString& name);
279 
280     void Write(const wxString& name, const ConfigManagerContainer::StringSet& set);
281     void Read(const wxString& name, ConfigManagerContainer::StringSet* map);
282     ConfigManagerContainer::StringSet ReadSSet(const wxString& name);
283 
284 
285     /* -----------------------------------------------------------------------------------------------------
286     *  Maps of serialized objects. You are responsible for deleting the objects in the map/set.
287     *
288     *  Usage:
289     *  ------
290     *  typedef std::map<wxString, MySerializableClass *> MyMap;
291     *  MyMap objMap;
292     *  cfg->Read("name", &objMap);
293     *  map["somekey"]->DoSomething();
294     */
295     void Write(const wxString& name, const ConfigManagerContainer::SerializableObjectMap* map);
296 
Read(const wxString & name,std::map<wxString,T * > * map)297     template <typename T> void Read(const wxString& name, std::map<wxString, T*> *map)
298     {
299         wxString key(name);
300         TiXmlHandle ph(AssertPath(key));
301         TiXmlElement* e = 0;
302         if(TiXmlNode *n = ph.FirstChild(key.mb_str(wxConvUTF8)).FirstChild("objmap").Node())
303             while(n->IterateChildren(e) && (e = n->IterateChildren(e)->ToElement()))
304             {
305                 T *obj = new T;
306                 obj->SerializeIn(wxBase64::Decode(cbC2U(e->FirstChild()->ToText()->Value())));
307                 (*map)[cbC2U(e->Value())] = obj;
308             }
309     }
310 };
311 
312 /** Wrapper class for reading or writing config values, without the need for the full path.
313   * It provides a way to sandbox a part of the code from the namespace details
314   * or the full path used to access the config values.
315   */
316 class DLLIMPORT ConfigManagerWrapper
317 {
318 public:
ConfigManagerWrapper()319     ConfigManagerWrapper() {}
ConfigManagerWrapper(wxString namespace_,wxString basepath)320     ConfigManagerWrapper(wxString namespace_, wxString basepath) : m_namespace(namespace_), m_basepath(basepath)
321     {
322         if (!m_basepath.EndsWith(wxT("/")))
323             m_basepath += wxT("/");
324     }
IsValid()325     bool IsValid() const { return !m_namespace.empty(); }
GetBasepath()326     const wxString& GetBasepath() const { return m_basepath; }
327 
328     void Write(const wxString& name, const wxString& value, bool ignoreEmpty = false);
329     wxString Read(const wxString& key, const wxString& defaultVal = wxEmptyString);
330 
331     bool Read(const wxString& key, wxString* str);
332     void Write(const wxString& key, const char* str);
333 
334     void Write(const wxString& name,  int value);
335     bool Read(const wxString& name,  int* value);
336     int  ReadInt(const wxString& name,  int defaultVal = 0);
337 
338     void Write(const wxString& name,  bool value);
339     bool Read(const wxString& name,  bool* value);
340     bool ReadBool(const wxString& name,  bool defaultVal = false);
341 
342     void Write(const wxString& name, double value);
343     bool Read(const wxString& name, double* value);
344     double ReadDouble(const wxString& name, double defaultVal = 0.0f);
345 
346 private:
347     wxString m_namespace;
348     wxString m_basepath;
349 };
350 
351 /// Read the list of batch build plugins and return them. The list won't be empty; at least the compiler plugin will be
352 /// added to the to it. The list contain the library names of the plugins and differs on every OS.
353 DLLIMPORT wxArrayString cbReadBatchBuildPlugins();
354 /// Write the list of batch build plugins in the config.
355 /// @param bbpluigns List of library plugin names.
356 /// @param messageBoxParent Set as a parent to the message box that will be shown in case of errors.
357 DLLIMPORT void cbWriteBatchBuildPlugins(wxArrayString bbplugins, wxWindow *messageBoxParent);
358 
359 /* ------------------------------------------------------------------------------------------------------------------
360 *  "Builder pattern" class for ConfigManager
361 *
362 *  ################################################################
363 *  ###### Do not use this class. Do not even think about it. ######
364 *  ################################################################
365 *
366 *  --->  use Manager::Get()->GetConfigManager("yournamespace") instead.
367 *
368 *  Manager::Get()->GetConfigManager("yournamespace") is guaranteed to always work while
369 *  the builder class and its interfaces may be changed any time without prior notice.
370 */
371 
372 WX_DECLARE_STRING_HASH_MAP(ConfigManager*, NamespaceMap);
373 
374 class DLLIMPORT CfgMgrBldr : public Mgr<CfgMgrBldr>
375 {
376     friend class ConfigManager;
377     friend class Mgr<CfgMgrBldr>;
378     NamespaceMap namespaces;
379     TiXmlDocument *doc;
380     TiXmlDocument *volatile_doc;
381     wxCriticalSection cs;
382     bool r;
383     wxString cfg;
384 
385     void Flush();
386     void Close();
387     void SwitchTo(const wxString& absFN);
388     void SwitchToR(const wxString& absFN);
389     ConfigManager* Build(const wxString& name_space);
390     wxString FindConfigFile(const wxString& filename);
391     wxString DetermineExecutablePath();
392 protected:
393     CfgMgrBldr();
394     ~CfgMgrBldr() override;
395 
396 public:
397     static ConfigManager* GetConfigManager(const wxString& name_space);
398 
399     /// Return the path to the current configuration file.
400     /// This should be used only to print it in the log during start up.
401     wxString GetConfigFile() const;
402 };
403 
404 #endif
405 
406