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 * $Revision: 11901 $
6 * $Id: configmanager.cpp 11901 2019-11-04 19:35:26Z fuscated $
7 * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/sdk/configmanager.cpp $
8 */
9
10 #include "sdk_precomp.h"
11
12 #ifndef CB_PRECOMP
13 #include "configmanager.h"
14 #include "globals.h"
15 #include "personalitymanager.h"
16 #include "cbexception.h"
17 #include "logmanager.h"
18 #include <wx/file.h>
19 #include <wx/dir.h>
20 #include <wx/log.h> // for wxSafeShowMessage()
21 #endif
22
23 #include "crc32.h"
24
25 #include <wx/url.h>
26 #include <wx/stream.h>
27 #include <wx/stdpaths.h>
28 #include <wx/filename.h>
29
30 #ifdef __WXMSW__
31 #include <shlobj.h>
32 #endif
33
34 #include "annoyingdialog.h"
35
36 #if defined(__APPLE__) && defined(__MACH__)
37 #include <sys/param.h>
38 #include <mach-o/dyld.h>
39 #endif
40
41 #ifdef __WXMAC__
42 #if wxCHECK_VERSION(3, 0, 0)
43 #include "wx/osx/core/cfstring.h"
44 #else
45 #include "wx/mac/corefoundation/cfstring.h"
46 #endif
47 #include "wx/intl.h"
48
49 #include <CoreFoundation/CFBundle.h>
50 #include <CoreFoundation/CFURL.h>
51 #endif
52
53 #include "tinywxuni.h"
54 #include <stdlib.h>
55
56 #ifdef __linux__
57 #include <glib.h>
58 #endif // __linux__
59
60 template<> CfgMgrBldr* Mgr<CfgMgrBldr>::instance = nullptr;
61 template<> bool Mgr<CfgMgrBldr>::isShutdown = false;
62
63 wxString ConfigManager::alternate_user_data_path;
64 bool ConfigManager::has_alternate_user_data_path=false;
65
66 wxString ConfigManager::config_folder;
67 wxString ConfigManager::home_folder;
68 wxString ConfigManager::data_path_user;
69 wxString ConfigManager::data_path_global;
70 #ifdef CB_AUTOCONF
71 wxString ConfigManager::plugin_path_global;
72 #endif
73 wxString ConfigManager::app_path;
74 wxString ConfigManager::temp_folder;
75
76
77 namespace CfgMgrConsts
78 {
79 const wxString app_path(_T("app_path"));
80 const wxString data_path(_T("data_path"));
81 const wxString dotDot(_T(".."));
82 const int version = 1;
83 }
84
85
86 namespace
87 {
DetermineExecutablePath()88 wxString DetermineExecutablePath()
89 {
90 #ifdef __WXMSW__
91 wxChar name[MAX_PATH];
92 GetModuleFileName(0L, name, MAX_PATH);
93 wxFileName fname(name);
94 return fname.GetPath(wxPATH_GET_VOLUME);
95 #else
96 #ifdef __linux__
97 char c[PATH_MAX+1];
98 char *p = realpath("/proc/self/exe", &c[0]);
99 if (p == nullptr)
100 return _T(".");
101 wxFileName fname(cbC2U(p));
102 return fname.GetPath(wxPATH_GET_VOLUME);
103 #elif defined(sun) || defined(__sun)
104 wxFileName fname(cbC2U(getexecname()));
105 return fname.GetPath(wxPATH_GET_VOLUME);
106 #elif defined(__APPLE__) && defined(__MACH__)
107 char path[MAXPATHLEN+1];
108 uint32_t path_len = MAXPATHLEN;
109 // SPI first appeared in Mac OS X 10.2
110 _NSGetExecutablePath(path, &path_len);
111 wxFileName fname(wxString(path, wxConvUTF8));
112 return fname.GetPath(wxPATH_GET_VOLUME);
113 #else
114 return _T(".");
115 #endif
116 #endif
117 }
118
DetermineResourcesPath()119 wxString DetermineResourcesPath()
120 {
121 #if defined(__WXMAC__)
122 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
123 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(resourcesURL); // relative -> absolute
124 CFRelease(resourcesURL);
125 CFStringRef cfStrPath = CFURLCopyFileSystemPath(absoluteURL,kCFURLPOSIXPathStyle);
126 CFRelease(absoluteURL);
127 #if wxCHECK_VERSION(3, 0, 0)
128 wxString str = wxCFStringRef(cfStrPath).AsString(wxLocale::GetSystemEncoding());
129 #else
130 wxString str = wxMacCFStringHolder(cfStrPath).AsString(wxLocale::GetSystemEncoding());
131 #endif
132 if (!str.Contains(wxString(_T("/Resources"))))
133 return ::DetermineExecutablePath() + _T("/.."); // not a bundle, use relative path
134 return str;
135 #else
136 return _T(".");
137 #endif
138 }
139 }
140
141
Collapse(wxString & str) const142 inline void ConfigManager::Collapse(wxString& str) const
143 {
144 const wxChar *src = str.c_str();
145 wxChar *dst = (wxChar*) src;
146 wxChar c;
147 size_t len = 0;
148
149 while ((c = *src))
150 {
151 ++src;
152
153 *dst = c;
154 ++dst;
155 ++len;
156
157 if (c == _T('/'))
158 while (*src == _T('/'))
159 ++src;
160 }
161 str.Truncate(len);
162 }
163
ISerializable()164 ISerializable::ISerializable()
165 {}
166
~ISerializable()167 ISerializable::~ISerializable()
168 {}
169
170
171
172
173 /* ------------------------------------------------------------------------------------------------------------------
174 * "Builder pattern" class for ConfigManager
175 * Do not use this class - Manager::Get()->GetConfigManager() is a lot friendlier
176 */
177
CfgMgrBldr()178 CfgMgrBldr::CfgMgrBldr() : doc(nullptr), volatile_doc(nullptr), r(false)
179 {
180 ConfigManager::MigrateFolders();
181
182 TiXmlBase::SetCondenseWhiteSpace(false);
183 wxString personality(Manager::Get()->GetPersonalityManager()->GetPersonality());
184
185 if (personality.StartsWith(_T("http://")))
186 {
187 SwitchToR(personality);
188 return;
189 }
190
191 cfg = FindConfigFile(personality + _T(".conf"));
192
193 if (cfg.IsEmpty())
194 {
195 cfg = ConfigManager::GetConfigFolder() + wxFILE_SEP_PATH + personality + _T(".conf");
196 doc = new TiXmlDocument();
197 doc->InsertEndChild(TiXmlDeclaration("1.0", "UTF-8", "yes"));
198 doc->InsertEndChild(TiXmlElement("CodeBlocksConfig"));
199 doc->FirstChildElement("CodeBlocksConfig")->SetAttribute("version", CfgMgrConsts::version);
200 return;
201 }
202 SwitchTo(cfg);
203 }
204
205
FindConfigFile(const wxString & filename)206 wxString CfgMgrBldr::FindConfigFile(const wxString& filename)
207 {
208
209 wxString u(ConfigManager::GetUserDataFolder() + wxFILE_SEP_PATH + filename);
210 wxString exePath(::DetermineExecutablePath());
211 wxString e(exePath + wxFILE_SEP_PATH + filename);
212
213 if (!ConfigManager::has_alternate_user_data_path && ::wxFileExists(e))
214 {
215 ConfigManager::SetUserDataFolder(exePath);
216 return e;
217 }
218 if (::wxFileExists(u))
219 {
220 return u;
221 }
222 return wxEmptyString;
223 }
224
225 /// Print error message an allow the user to either discard the old config or close the application.
226 /// Call this function when you've detected an error while reading the config.
handleConfigError(TiXmlDocument & doc,const wxString & fileName,const wxString & additionalMessage)227 static void handleConfigError(TiXmlDocument &doc, const wxString &fileName, const wxString &additionalMessage)
228 {
229 wxString message;
230 if (doc.ErrorId())
231 {
232 message = wxString::Format(_("TinyXML error: %s\nIn file: %s\nAt row %d, column: %d.\n\n"),
233 cbC2U(doc.ErrorDesc()).c_str(), fileName.wx_str(),
234 doc.ErrorRow(), doc.ErrorCol());
235 }
236 message += additionalMessage;
237
238 // Show a message box and ask the user to either abort or discard the old config.
239 wxMessageDialog dlg(Manager::Get()->GetAppWindow(),
240 message + _("\n\nDiscard old config file?"), _("Config file read error"),
241 wxSTAY_ON_TOP|wxCENTRE|wxYES|wxNO|wxNO_DEFAULT|wxICON_ERROR);
242 #if wxCHECK_VERSION(3, 0, 0)
243 dlg.SetYesNoLabels(_("&Discard"), _("&Close"));
244 #endif
245 if (dlg.ShowModal() != wxID_YES)
246 cbThrow(message);
247
248 doc.ClearError();
249 doc.InsertEndChild(TiXmlDeclaration("1.0", "UTF-8", "yes"));
250 doc.InsertEndChild(TiXmlElement("CodeBlocksConfig"));
251 doc.FirstChildElement("CodeBlocksConfig")->SetAttribute("version", CfgMgrConsts::version);
252 }
253
SwitchTo(const wxString & fileName)254 void CfgMgrBldr::SwitchTo(const wxString& fileName)
255 {
256 doc = new TiXmlDocument();
257
258 if (!TinyXML::LoadDocument(fileName, doc))
259 {
260 const wxString message = wxString::Format(_("Error reading config file: %s"),
261 fileName.wx_str());
262 handleConfigError(*doc, fileName, message);
263 }
264
265 TiXmlElement* docroot = doc->FirstChildElement("CodeBlocksConfig");
266 if (!docroot)
267 {
268 const wxString message = wxString::Format(wxT("Cannot find docroot in config file '%s'"),
269 fileName.wx_str());
270 handleConfigError(*doc, fileName, message);
271 docroot = doc->FirstChildElement("CodeBlocksConfig");
272
273 if (!docroot)
274 cbThrow(wxT("Something really bad happened while reading the config file. Aborting!"));
275 }
276
277 const char *vers = docroot->Attribute("version");
278 if (!vers || atoi(vers) != 1)
279 cbMessageBox(_("ConfigManager encountered an unknown config file version. Continuing happily."), _("Warning"), wxICON_WARNING);
280
281 doc->ClearError();
282
283 wxString info;
284 info.Printf(_T(" application info:\n"
285 "\t svn_revision:\t%u\n"
286 "\t build_date:\t%s, %s\n"), ConfigManager::GetRevisionNumber(), wxT(__DATE__), wxT(__TIME__));
287 #if defined(__clang__)
288 info += wxString::Format(wxT("\t compiler_version:\tclang %d.%d.%d\n"), __clang_major__,
289 __clang_minor__, __clang_patchlevel__);
290 #elif defined(__GNUC__)
291 info += wxString::Format(wxT("\t compiler_version:\tgcc %d.%d.%d\n"), __GNUC__, __GNUC_MINOR__,
292 __GNUC_PATCHLEVEL__);
293 #endif
294
295 if (platform::windows)
296 info.append(_T("\t Windows "));
297 else if (platform::Linux)
298 info.append(_T("\t Linux "));
299 else if (platform::macosx)
300 info.append(_T("\t Mac OS X "));
301 else if (platform::Unix)
302 info.append(_T("\t Unix "));
303
304 info.append(platform::unicode ? _T("Unicode") : _T("ANSI"));
305 info.append(wxT("\n"));
306 TiXmlComment c;
307 c.SetValue((const char*) info.mb_str());
308
309 TiXmlNode *firstchild = docroot->FirstChild();
310 if (firstchild && firstchild->ToComment())
311 {
312 docroot->RemoveChild(firstchild);
313 firstchild = docroot->FirstChild();
314 }
315
316 if (firstchild)
317 docroot->InsertBeforeChild(firstchild, c);
318 else
319 docroot->InsertEndChild(c);
320 }
321
SwitchToR(const wxString & absFileName)322 void CfgMgrBldr::SwitchToR(const wxString& absFileName)
323 {
324 if (doc)
325 delete doc;
326 doc = new TiXmlDocument();
327 doc->ClearError();
328
329 cfg = absFileName;
330
331 wxURL url(absFileName);
332 url.SetProxy(ConfigManager::GetProxy());
333 if (url.GetError() == wxURL_NOERR)
334 {
335 wxInputStream *is = url.GetInputStream();
336 if (is && is->IsOk())
337 {
338 size_t size = is->GetSize();
339 wxString str;
340 #if wxCHECK_VERSION(3, 0, 0)
341 wxChar* c = wxStringBuffer(str, size);
342 #else
343 wxChar* c = str.GetWriteBuf(size);
344 #endif
345 is->Read(c, size);
346 #if !wxCHECK_VERSION(3, 0, 0)
347 str.UngetWriteBuf(size);
348 #endif
349
350 doc = new TiXmlDocument();
351
352 if (doc->Parse(cbU2C(str)))
353 {
354 doc->ClearError();
355 delete is;
356 return;
357 }
358 if (Manager::Get()->GetLogManager())
359 {
360 Manager::Get()->GetLogManager()->DebugLog(_T("##### Error loading or parsing remote config file"));
361 Manager::Get()->GetLogManager()->DebugLog(cbC2U(doc->ErrorDesc()));
362 doc->ClearError();
363 }
364 }
365 delete is;
366 }
367 cfg.Empty();
368 SwitchTo(wxEmptyString); // fall back
369 }
370
~CfgMgrBldr()371 CfgMgrBldr::~CfgMgrBldr()
372 {
373 NamespaceMap::iterator it;
374 for ( it = namespaces.begin(); it != namespaces.end(); ++it )
375 delete it->second;
376
377 namespaces.clear();
378 Close();
379 delete volatile_doc;
380 }
381
Flush()382 void CfgMgrBldr::Flush()
383 {
384 if (doc)
385 {
386 if (!cfg.StartsWith(_T("http://")))
387 {
388 bool done = false;
389 do
390 {
391 if (TinyXML::SaveDocument(cfg, doc))
392 done = true;
393 else
394 {
395 AnnoyingDialog dlg(_("Error"),
396 F(_T("Could not save config file '%s'!"), cfg.wx_str()),
397 wxART_ERROR, AnnoyingDialog::TWO_BUTTONS,
398 AnnoyingDialog::rtTWO, _("&Retry"), _("&Close"));
399 PlaceWindow(&dlg);
400 switch (dlg.ShowModal())
401 {
402 case AnnoyingDialog::rtONE:
403 done = false;
404 break;
405 case AnnoyingDialog::rtTWO:
406 default:
407 done = true;
408 }
409 }
410 } while (!done);
411 }
412 else
413 {
414 // implement WebDAV another time
415 }
416 }
417 }
418
Close()419 void CfgMgrBldr::Close()
420 {
421 Flush();
422
423 if (doc)
424 delete doc;
425
426 doc = nullptr;
427 }
428
429
GetConfigManager(const wxString & name_space)430 ConfigManager* CfgMgrBldr::GetConfigManager(const wxString& name_space)
431 {
432 return Get()->Build(name_space);
433 }
434
435
Build(const wxString & name_space)436 ConfigManager* CfgMgrBldr::Build(const wxString& name_space)
437 {
438 if (name_space.IsEmpty())
439 cbThrow(_T("You attempted to get a ConfigManager instance without providing a namespace."));
440
441 wxCriticalSectionLocker locker(cs);
442 NamespaceMap::iterator it = namespaces.find(name_space);
443 if (it != namespaces.end())
444 return it->second;
445
446 TiXmlElement* docroot;
447
448 if (name_space.StartsWith(_T("volatile:")))
449 {
450 if (!volatile_doc)
451 {
452 volatile_doc = new TiXmlDocument();
453 volatile_doc->InsertEndChild(TiXmlElement("CodeBlocksConfig"));
454 volatile_doc->SetCondenseWhiteSpace(false);
455 }
456 docroot = volatile_doc->FirstChildElement("CodeBlocksConfig");
457 }
458 else
459 {
460 docroot = doc->FirstChildElement("CodeBlocksConfig");
461 if (!docroot)
462 {
463 wxString err(_("Fatal error parsing supplied configuration file.\nParser error message:\n"));
464 err << wxString::Format(_T("%s\nAt row %d, column: %d."), cbC2U(doc->ErrorDesc()).c_str(), doc->ErrorRow(), doc->ErrorCol());
465 cbThrow(err);
466 }
467 }
468
469 TiXmlElement* root = docroot->FirstChildElement(cbU2C(name_space));
470
471 if (!root) // namespace does not exist
472 {
473 docroot->InsertEndChild(TiXmlElement(cbU2C(name_space)));
474 root = docroot->FirstChildElement(cbU2C(name_space));
475 }
476
477 if (!root) // now what!
478 cbThrow(_T("Unable to create namespace in document tree (actually not possible..?)"));
479
480 ConfigManager *c = new ConfigManager(root);
481 namespaces[name_space] = c;
482
483 return c;
484 }
485
GetConfigFile() const486 wxString CfgMgrBldr::GetConfigFile() const
487 {
488 return cfg;
489 }
490
491 /*
492 * Hack to enable Turkish language. wxString::Upper will convert lowercase 'i' to \u0130 instead of \u0069 in Turkish locale,
493 * which will break the config file when used in a tag
494 */
to_upper(wxString & s)495 inline void to_upper(wxString& s)
496 {
497 #if wxCHECK_VERSION(3, 0, 0)
498 wxStringCharType *p = const_cast<wxStringCharType*>(s.wx_str());
499 wxStringCharType q;
500 #else
501 wxChar *p = (wxChar*) s.c_str();
502 wxChar q;
503 #endif
504 size_t len = s.length()+1;
505 for (;--len;++p)
506 {
507 q = *p;
508 if (q >= 'a' && q <= 'z')
509 *p = q - 32;
510 }
511 }
512
to_lower(wxString & s)513 inline void to_lower(wxString& s)
514 {
515 #if wxCHECK_VERSION(3, 0, 0)
516 wxStringCharType *p = const_cast<wxStringCharType*>(s.wx_str());
517 wxStringCharType q;
518 #else
519 wxChar *p = (wxChar*) s.c_str();
520 wxChar q;
521 #endif
522 size_t len = s.length()+1;
523 for (;--len;++p)
524 {
525 q = *p;
526 if (q >= 'A' && q <= 'Z')
527 *p = q + 32;
528 }
529 }
530
531
532 /* ------------------------------------------------------------------------------------------------------------------
533 * Functions to retrieve system paths and locate data files in a defined, consistent way.
534 * Please note that the application determines app_path and data_path at runtime and passes the results
535 * to ConfigManager. GetExecutableFolder() and GetDataFolder() are therefore under normal conditions
536 * simply more efficient shortcuts for Read("app_path") and Read("data_path").
537 */
538
GetProxy()539 wxString ConfigManager::GetProxy()
540 {
541 return Manager::Get()->GetConfigManager(_T("app"))->Read(_T("network_proxy"));
542 }
543
544
GetFolder(SearchDirs dir)545 wxString ConfigManager::GetFolder(SearchDirs dir)
546 {
547 static bool once = 1;
548
549 if (once)
550 {
551 InitPaths();
552 once = false;
553 }
554
555 switch (dir)
556 {
557 case sdHome:
558 return ConfigManager::home_folder;
559
560 case sdBase:
561 return ConfigManager::app_path;
562
563 case sdTemp:
564 return ConfigManager::temp_folder;
565
566 case sdConfig:
567 return ConfigManager::config_folder;
568
569 case sdCurrent:
570 return ::wxGetCwd();
571
572 case sdPluginsGlobal:
573 #ifndef CB_AUTOCONF
574 return ConfigManager::data_path_global + wxFILE_SEP_PATH + _T("plugins");
575 #else
576 return ConfigManager::plugin_path_global;
577 #endif
578
579 case sdPluginsUser:
580 return ConfigManager::data_path_user + wxFILE_SEP_PATH + _T("plugins");
581
582 case sdScriptsGlobal:
583 return ConfigManager::data_path_global + wxFILE_SEP_PATH + _T("scripts");
584
585 case sdScriptsUser:
586 return ConfigManager::data_path_user + wxFILE_SEP_PATH + _T("scripts");
587
588 case sdDataGlobal:
589 return ConfigManager::data_path_global;
590
591 case sdDataUser:
592 return ConfigManager::data_path_user;
593
594 case sdPath:
595 case sdAllUser:
596 case sdAllGlobal:
597 case sdAllKnown:
598 default:
599 return wxEmptyString;
600 }
601 }
602
GetUserDataFolder()603 inline wxString ConfigManager::GetUserDataFolder()
604 {
605 if (has_alternate_user_data_path)
606 return alternate_user_data_path;
607 #ifdef __WINDOWS__
608 TCHAR buffer[MAX_PATH];
609 if (!ConfigManager::has_alternate_user_data_path && ::GetEnvironmentVariable(_T("APPDATA"), buffer, MAX_PATH))
610 return wxString::Format(_T("%s\\CodeBlocks"), buffer);
611 else
612 return wxStandardPathsBase::Get().GetUserDataDir();
613 #else
614 #ifdef __linux__
615 return wxString::FromUTF8(g_build_filename (g_get_user_config_dir(), "codeblocks", NULL));
616 #else
617 return wxStandardPathsBase::Get().GetUserDataDir();
618 #endif // __linux__
619 #endif // __WINDOWS__
620 }
621
622
SetUserDataFolder(const wxString & user_data_path)623 bool ConfigManager::SetUserDataFolder(const wxString &user_data_path)
624 {
625 wxString udp = wxFileName::DirName(user_data_path).GetFullPath();
626 if (!CreateDirRecursively(udp))
627 {
628 cbMessageBox(wxString::Format(_("The --user-data-dir directory %s does not exist and could not be created. Please check the path and try again"),
629 user_data_path.c_str()), _("Command Line Error"));
630 return false;
631 }
632 has_alternate_user_data_path = true;
633 ConfigManager::alternate_user_data_path = udp;
634 return true;
635 }
636
LocateDataFile(const wxString & filename,int search_dirs)637 wxString ConfigManager::LocateDataFile(const wxString& filename, int search_dirs)
638 {
639 wxPathList searchPaths;
640
641 // user dirs have precedence
642 if (search_dirs & sdPluginsUser)
643 searchPaths.Add(GetPluginsFolder(false));
644 if (search_dirs & sdScriptsUser)
645 searchPaths.Add(GetScriptsFolder(false));
646 if (search_dirs & sdDataUser)
647 searchPaths.Add(GetDataFolder(false));
648
649 // then we have global dirs
650 if (search_dirs & sdPluginsGlobal)
651 searchPaths.Add(GetPluginsFolder(true));
652 if (search_dirs & sdScriptsGlobal)
653 searchPaths.Add(GetScriptsFolder(true));
654 if (search_dirs & sdDataGlobal)
655 searchPaths.Add(GetDataFolder(true));
656
657 // rest of the dirs
658 if (search_dirs & sdCurrent)
659 searchPaths.Add(::wxGetCwd());
660 if (search_dirs & sdConfig)
661 searchPaths.Add(GetConfigFolder());
662 if (search_dirs & sdHome)
663 searchPaths.Add(GetHomeFolder());
664 if (search_dirs & sdBase)
665 searchPaths.Add(GetExecutableFolder());
666 if (search_dirs & sdTemp)
667 searchPaths.Add(GetTempFolder());
668
669 // PATH env. var
670 if (search_dirs & sdPath)
671 searchPaths.AddEnvList(_T("PATH"));
672
673 return searchPaths.FindValidPath(filename);
674 }
675
676
677
678 /* ------------------------------------------------------------------------------------------------------------------
679 * ConfigManager
680 */
681
ConfigManager(TiXmlElement * r)682 ConfigManager::ConfigManager(TiXmlElement* r) : doc(r->GetDocument()), root(r), pathNode(r)
683 {
684 }
685
686
687
688
689 /* ------------------------------------------------------------------------------------------------------------------
690 * Configuration path handling
691 * Note that due to namespaces, you do no longer need to care about saving/restoring the current path in the normal case.
692 * Mostly, there will be only one module working with one namespace, and every namespace keeps track of its own path.
693 * Also, please note that GetPath() is more expensive than it seems (not a mere accessor to a member variable!), while
694 * SetPath() not only sets the current path, but also creates the respective nodes in the XML document if these don't exist.
695 */
696
GetPath() const697 wxString ConfigManager::GetPath() const
698 {
699 TiXmlElement *e = pathNode;
700 wxString ret;
701 ret.Alloc(64);
702
703 ret = cbC2U(e->Value());
704 while ((e = e->Parent()->ToElement()) && e != root)
705 {
706 ret.Prepend(_T('/'));
707 ret.Prepend(cbC2U(e->Value()));
708 }
709 ret.Prepend(_T('/'));
710 return ret;
711 }
712
SetPath(const wxString & path)713 void ConfigManager::SetPath(const wxString& path)
714 {
715 wxString p(path + _T('/'));
716 pathNode = AssertPath(p);
717 }
718
InvalidNameMessage(const wxString & what,const wxString & sub,TiXmlElement * localPath) const719 wxString ConfigManager::InvalidNameMessage(const wxString& what, const wxString& sub, TiXmlElement *localPath) const
720 {
721 wxString s;
722 s.Printf(_T("The %s %s (child of node \"%s\" in namespace \"%s\") does not meet the standard for path naming (must start with a letter)."),
723 what.c_str(),
724 sub.c_str(),
725 cbC2U(localPath->Value()).c_str(),
726 cbC2U(root->Value()).c_str());
727
728 return s;
729 }
730
731
AssertPath(wxString & path)732 TiXmlElement* ConfigManager::AssertPath(wxString& path)
733 {
734 Collapse(path);
735
736 wxString illegal(_T(" -:.\"\'$&()[]<>+#"));
737 size_t i = 0;
738 while ((i = path.find_first_of(illegal, i)) != wxString::npos)
739 path[i] = _T('_');
740
741 TiXmlElement *localPath = pathNode ? pathNode : root;
742
743 if (path.GetChar(0) == '/') // absolute path
744 {
745 localPath = root;
746 path = path.Mid(1);
747 }
748
749 if (path.find(_T('/')) != wxString::npos) // need for path walking
750 to_lower(path);
751
752 wxString sub;
753
754 while (path.find(_T('/')) != wxString::npos)
755 {
756 sub = path.BeforeFirst(_T('/'));
757 path = path.AfterFirst(_T('/'));
758
759 if (localPath != root && sub.IsSameAs(CfgMgrConsts::dotDot))
760 localPath = localPath->Parent()->ToElement();
761 else if (sub.GetChar(0) < _T('a') || sub.GetChar(0) > _T('z'))
762 {
763 cbThrow(InvalidNameMessage(_T("subpath"), sub, localPath));
764 }
765 else
766 {
767 TiXmlElement* n = localPath->FirstChildElement(cbU2C(sub));
768 if (n)
769 localPath = n;
770 else
771 localPath = (TiXmlElement*) localPath->InsertEndChild(TiXmlElement(cbU2C(sub)));
772 }
773 }
774
775 to_upper(path);
776
777 if (!path.IsEmpty() && (path.GetChar(0) < _T('A') || path.GetChar(0) > _T('Z')))
778 cbThrow(InvalidNameMessage(_T("key"), path, localPath));
779
780 return localPath;
781 }
782
783
784 /* -----------------------------------------------------------------------------------------------------
785 * Clear all nodes from your namespace or delete the namespace alltogether (removing it from the config file).
786 * After Delete() returns, the pointer to your instance is invalid.
787 */
788
Clear()789 void ConfigManager::Clear()
790 {
791 root->Clear();
792 }
793
Delete()794 void ConfigManager::Delete()
795 {
796 CfgMgrBldr * bld = CfgMgrBldr::Get();
797 const wxString ns(cbC2U(root->Value()));
798
799 root->Clear();
800 doc->RootElement()->RemoveChild(root);
801
802 wxCriticalSectionLocker(bld->cs);
803 NamespaceMap::iterator it = bld->namespaces.find(ns);
804 if (it != bld->namespaces.end())
805 bld->namespaces.erase(it);
806
807 delete this;
808 }
809
DeleteAll()810 void ConfigManager::DeleteAll()
811 {
812 CfgMgrBldr * bld = CfgMgrBldr::Get();
813 const wxString ns(cbC2U(root->Value()));
814
815 if (!ns.IsSameAs(_T("app")))
816 cbThrow(_T("Illegal attempt to invoke DeleteAll()."));
817
818 wxCriticalSectionLocker(bld->cs);
819 doc->RootElement()->Clear();
820 for (NamespaceMap::iterator it = bld->namespaces.begin(); it != bld->namespaces.end(); ++it)
821 delete it->second;
822
823 bld->namespaces.clear();
824 }
825
Flush()826 void ConfigManager::Flush()
827 {
828 CfgMgrBldr * bld = CfgMgrBldr::Get();
829 wxCriticalSectionLocker(bld->cs);
830 bld->Flush();
831 }
832
833 /* ------------------------------------------------------------------------------------------------------------------
834 * Utility functions for writing nodes
835 */
836
GetUniqElement(TiXmlElement * p,const wxString & q)837 TiXmlElement* ConfigManager::GetUniqElement(TiXmlElement* p, const wxString& q)
838 {
839 TiXmlElement* r;
840 if ((r = p->FirstChildElement(cbU2C(q))))
841 return r;
842
843 return (TiXmlElement*)(p->InsertEndChild(TiXmlElement(cbU2C(q))));
844 }
845
SetNodeText(TiXmlElement * n,const TiXmlText & t)846 void ConfigManager::SetNodeText(TiXmlElement* n, const TiXmlText& t)
847 {
848 TiXmlNode *c = n->FirstChild();
849 if (c)
850 n->ReplaceChild(c, t);
851 else
852 n->InsertEndChild(t);
853 }
854
855
856
857 /* ------------------------------------------------------------------------------------------------------------------
858 * Write and read values
859 * Regardless of namespaces, the string keys app_path and data_path always refer to the location of the application's executable
860 * and the data path, respectively. These values are never saved to the configuration, but kept in static variables.
861 * The application makes use of this by "writing" to the configuration file after determining these values at runtime.
862 */
Write(const wxString & name,const wxString & value,bool ignoreEmpty)863 void ConfigManager::Write(const wxString& name, const wxString& value, bool ignoreEmpty)
864 {
865 if (name.IsSameAs(CfgMgrConsts::app_path))
866 {
867 return;
868 }
869 else if (name.IsSameAs(CfgMgrConsts::data_path))
870 {
871 data_path_global = value;
872 return;
873 }
874 if (ignoreEmpty && value.IsEmpty())
875 {
876 UnSet(name);
877 return;
878 }
879
880 wxString key(name);
881 TiXmlElement* e = AssertPath(key);
882
883 TiXmlElement *str = GetUniqElement(e, key);
884
885 TiXmlElement *s = GetUniqElement(str, _T("str"));
886
887 TiXmlText t(value.mb_str(wxConvUTF8));
888 t.SetCDATA(true);
889 SetNodeText(s, t);
890 }
891
Write(const wxString & key,const char * str)892 void ConfigManager::Write(const wxString& key, const char* str)
893 {
894 /* NOTE (mandrav#1#): Do *not* remove 'false' from the call because in ANSI builds,
895 it matches this very function and overflows the stack... */
896 Write(key, cbC2U(str), false);
897 }
898
Read(const wxString & name,const wxString & defaultVal)899 wxString ConfigManager::Read(const wxString& name, const wxString& defaultVal)
900 {
901 if (name.IsSameAs(CfgMgrConsts::app_path))
902 return app_path;
903 else if (name.IsSameAs(CfgMgrConsts::data_path))
904 return data_path_global;
905
906 wxString ret;
907
908 if (Read(name, &ret))
909 return ret;
910 else
911 return defaultVal;
912 }
913
Read(const wxString & name,wxString * str)914 bool ConfigManager::Read(const wxString& name, wxString* str)
915 {
916 if (name.IsSameAs(CfgMgrConsts::app_path))
917 {
918 str->assign(app_path);
919 return true;
920 }
921 else if (name.IsSameAs(CfgMgrConsts::data_path))
922 {
923 str->assign(data_path_global);
924 return true;
925 }
926
927 wxString key(name);
928 TiXmlElement* e = AssertPath(key);
929
930 TiXmlHandle parentHandle(e);
931 TiXmlText *t = (TiXmlText *) parentHandle.FirstChild(cbU2C(key)).FirstChild("str").FirstChild().Node();
932
933 if (t)
934 {
935 str->assign(cbC2U(t->Value()));
936 return true;
937 }
938 return false;
939 }
940
Write(const wxString & name,const wxColour & c)941 void ConfigManager::Write(const wxString& name, const wxColour& c)
942 {
943 wxString key(name);
944 TiXmlElement* e = AssertPath(key);
945
946 TiXmlElement *leaf = GetUniqElement(e, key);
947
948 TiXmlElement *s = GetUniqElement(leaf, _T("colour"));
949 if (c == wxNullColour)
950 {
951 s->SetAttribute("null", "true");
952 s->SetAttribute("r", 0);
953 s->SetAttribute("g", 0);
954 s->SetAttribute("b", 0);
955 }
956 else
957 {
958 s->SetAttribute("r", c.Red());
959 s->SetAttribute("g", c.Green());
960 s->SetAttribute("b", c.Blue());
961 }
962 }
963
ReadColour(const wxString & name,const wxColour & defaultVal)964 wxColour ConfigManager::ReadColour(const wxString& name, const wxColour& defaultVal)
965 {
966 wxColour ret;
967
968 if (Read(name, &ret))
969 return ret;
970 else
971 return defaultVal;
972 }
973
Read(const wxString & name,wxColour * ret)974 bool ConfigManager::Read(const wxString& name, wxColour* ret)
975 {
976 wxString key(name);
977 TiXmlElement* e = AssertPath(key);
978
979 TiXmlHandle parentHandle(e);
980 TiXmlElement *c = (TiXmlElement *) parentHandle.FirstChild(cbU2C(key)).FirstChild("colour").Element();
981
982 if (c)
983 {
984 const char *isNull = c->Attribute("null");
985 if (isNull && strcmp(isNull, "true") == 0)
986 {
987 *ret = wxNullColour;
988 return true;
989 }
990 else
991 {
992 int r, g, b;
993 if (c->QueryIntAttribute("r", &r) == TIXML_SUCCESS
994 && c->QueryIntAttribute("g", &g) == TIXML_SUCCESS
995 && c->QueryIntAttribute("b", &b) == TIXML_SUCCESS)
996 {
997 ret->Set(r, g, b);
998 return true;
999 }
1000 }
1001 }
1002 *ret = wxNullColour;
1003 return false;
1004 }
1005
Write(const wxString & name,int value)1006 void ConfigManager::Write(const wxString& name, int value)
1007 {
1008 wxString key(name);
1009 TiXmlElement* e = AssertPath(key);
1010 TiXmlElement *leaf = GetUniqElement(e, key);
1011
1012 leaf->SetAttribute("int", value);
1013 }
1014
ReadInt(const wxString & name,int defaultVal)1015 int ConfigManager::ReadInt(const wxString& name, int defaultVal)
1016 {
1017 int ret;
1018
1019 if (Read(name, &ret))
1020 return ret;
1021 else
1022 return defaultVal;
1023 }
1024
Read(const wxString & name,int * value)1025 bool ConfigManager::Read(const wxString& name, int* value)
1026 {
1027 wxString key(name);
1028 TiXmlElement* e = AssertPath(key);
1029
1030 TiXmlHandle parentHandle(e);
1031 TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
1032
1033 if (leaf)
1034 return leaf->QueryIntAttribute("int", value) == TIXML_SUCCESS;
1035 return false;
1036 }
1037
1038
Write(const wxString & name,bool value)1039 void ConfigManager::Write(const wxString& name, bool value)
1040 {
1041 wxString key(name);
1042 TiXmlElement* e = AssertPath(key);
1043 TiXmlElement *leaf = GetUniqElement(e, key);
1044
1045 leaf->SetAttribute("bool", value ? "1" : "0");
1046 }
1047
ReadBool(const wxString & name,bool defaultVal)1048 bool ConfigManager::ReadBool(const wxString& name, bool defaultVal)
1049 {
1050 bool ret;
1051
1052 if (Read(name, &ret))
1053 return ret;
1054 else
1055 return defaultVal;
1056 }
1057
Read(const wxString & name,bool * value)1058 bool ConfigManager::Read(const wxString& name, bool* value)
1059 {
1060 wxString key(name);
1061 TiXmlElement* e = AssertPath(key);
1062
1063 TiXmlHandle parentHandle(e);
1064 TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
1065
1066 if (leaf && leaf->Attribute("bool"))
1067 {
1068 *value = leaf->Attribute("bool")[0] == '1';
1069 return true;
1070 }
1071 return false;
1072 }
1073
1074
Write(const wxString & name,double value)1075 void ConfigManager::Write(const wxString& name, double value)
1076 {
1077 wxString key(name);
1078 TiXmlElement* e = AssertPath(key);
1079 TiXmlElement *leaf = GetUniqElement(e, key);
1080
1081 leaf->SetDoubleAttribute("double", value);
1082 }
1083
ReadDouble(const wxString & name,double defaultVal)1084 double ConfigManager::ReadDouble(const wxString& name, double defaultVal)
1085 {
1086 double ret;
1087
1088 if (Read(name, &ret))
1089 return ret;
1090 else
1091 return defaultVal;
1092 }
1093
Read(const wxString & name,double * value)1094 bool ConfigManager::Read(const wxString& name, double* value)
1095 {
1096 wxString key(name);
1097 TiXmlElement* e = AssertPath(key);
1098
1099 TiXmlHandle parentHandle(e);
1100 TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
1101
1102 if (leaf)
1103 return leaf->QueryDoubleAttribute("double", value) == TIXML_SUCCESS;
1104 return false;
1105 }
1106
1107
Set(const wxString & name)1108 void ConfigManager::Set(const wxString& name)
1109 {
1110 wxString key(name);
1111 TiXmlElement* e = AssertPath(key);
1112 GetUniqElement(e, key);
1113 }
1114
UnSet(const wxString & name)1115 void ConfigManager::UnSet(const wxString& name)
1116 {
1117 wxString key(name);
1118 TiXmlElement* e = AssertPath(key);
1119
1120 TiXmlNode *leaf = GetUniqElement(e, key);
1121 e->RemoveChild(leaf);
1122 }
1123
Exists(const wxString & name)1124 bool ConfigManager::Exists(const wxString& name)
1125 {
1126 wxString key(name);
1127 TiXmlElement* e = AssertPath(key);
1128
1129 TiXmlHandle parentHandle(e);
1130 TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
1131
1132 return leaf;
1133 }
1134
1135
1136
Write(const wxString & name,const wxArrayString & arrayString)1137 void ConfigManager::Write(const wxString& name, const wxArrayString& arrayString)
1138 {
1139 wxString key(name);
1140 TiXmlElement* e = AssertPath(key);
1141
1142 TiXmlElement *leaf = GetUniqElement(e, key);
1143
1144 TiXmlElement *as;
1145 as = GetUniqElement(leaf, _T("astr"));
1146 leaf->RemoveChild(as);
1147 as = GetUniqElement(leaf, _T("astr"));
1148
1149 for (unsigned int i = 0; i < arrayString.GetCount(); ++i)
1150 {
1151 TiXmlElement s("s");
1152
1153 TiXmlText t(arrayString[i].mb_str(wxConvUTF8));
1154 t.SetCDATA(true);
1155
1156 s.InsertEndChild(t);
1157 as->InsertEndChild(s);
1158 }
1159 }
1160
Read(const wxString & name,wxArrayString * arrayString)1161 void ConfigManager::Read(const wxString& name, wxArrayString *arrayString)
1162 {
1163 wxString key(name);
1164 TiXmlElement* e = AssertPath(key);
1165
1166 TiXmlHandle parentHandle(e);
1167 TiXmlNode *asNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("astr").Node();
1168
1169 TiXmlNode *curr = nullptr;
1170 if (asNode)
1171 {
1172 while ((curr = asNode->IterateChildren("s", curr)))
1173 arrayString->Add(cbC2U(curr->FirstChild()->ToText()->Value()));
1174 }
1175 }
1176
ReadArrayString(const wxString & name)1177 wxArrayString ConfigManager::ReadArrayString(const wxString& name)
1178 {
1179 wxArrayString as;
1180 Read(name, &as);
1181 return as;
1182 }
1183
WriteBinary(const wxString & name,const wxString & source)1184 void ConfigManager::WriteBinary(const wxString& name, const wxString& source)
1185 {
1186 wxString key(name);
1187 TiXmlElement* e = AssertPath(key);
1188
1189 TiXmlElement *str = GetUniqElement(e, key);
1190
1191 TiXmlElement *s = GetUniqElement(str, _T("bin"));
1192 s->SetAttribute("crc", wxCrc32::FromString(source));
1193 SetNodeText(s, TiXmlText(wxBase64::Encode(source).mb_str(wxConvUTF8)));
1194 }
1195
WriteBinary(const wxString & name,void * ptr,size_t len)1196 void ConfigManager::WriteBinary(const wxString& name, void* ptr, size_t len)
1197 {
1198 wxString s((wxChar*)ptr, len);
1199 WriteBinary(name, s);
1200 }
1201
ReadBinary(const wxString & name)1202 wxString ConfigManager::ReadBinary(const wxString& name)
1203 {
1204 wxString str;
1205 wxString key(name);
1206 TiXmlElement* e = AssertPath(key);
1207 unsigned int crc = 0;
1208
1209 TiXmlHandle parentHandle(e);
1210 TiXmlElement* bin = parentHandle.FirstChild(cbU2C(key)).FirstChild("bin").Element();
1211
1212 if (!bin)
1213 return wxEmptyString;
1214
1215 if (bin->QueryIntAttribute("crc", (int*)&crc) != TIXML_SUCCESS)
1216 return wxEmptyString;
1217
1218 if (const TiXmlText* t = bin->FirstChild()->ToText())
1219 {
1220 str.assign(cbC2U(t->Value()));
1221 str = wxBase64::Decode(str);
1222 if (crc == wxCrc32::FromString(str))
1223 return str;
1224 }
1225 return wxEmptyString;
1226 }
1227
1228
EnumerateSubPaths(const wxString & path)1229 wxArrayString ConfigManager::EnumerateSubPaths(const wxString& path)
1230 {
1231 wxString key(path + _T('/')); // the trailing slash hack is required because AssertPath expects a key name
1232 TiXmlNode* e = AssertPath(key);
1233 wxArrayString ret;
1234
1235 TiXmlElement *curr = nullptr;
1236 if (e)
1237 {
1238 while (e->IterateChildren(curr) && (curr = e->IterateChildren(curr)->ToElement()))
1239 {
1240 #if wxCHECK_VERSION(3, 0, 0)
1241 wxUniChar c = cbC2U(curr->Value())[0];
1242 #else
1243 wxChar c = *(cbC2U(curr->Value()));
1244 #endif
1245 if (c < _T('A') || c > _T('Z')) // first char must be a letter, uppercase letters are key names
1246 ret.Add(cbC2U(curr->Value()));
1247 }
1248 }
1249 return ret;
1250 }
1251
DeleteSubPath(const wxString & thePath)1252 void ConfigManager::DeleteSubPath(const wxString& thePath)
1253 {
1254 if (doc->ErrorId())
1255 {
1256 cbMessageBox(wxString(_T("### TinyXML error:\n")) << cbC2U(doc->ErrorDesc()));
1257 doc->ClearError();
1258 }
1259
1260 wxString path(thePath);
1261 to_lower(path);
1262
1263 Collapse(path);
1264
1265 wxString illegal(_T(" :.,;!\"\'$%&()[]<>{}?*+-|#"));
1266 size_t i;
1267 while ((i = path.find_first_of(illegal)) != wxString::npos)
1268 path[i] = _T('_');
1269
1270 if (path.Last() == _T('/'))
1271 path.RemoveLast();
1272
1273 if (path.IsSameAs(_T("/"))) // this function will refuse to remove root!
1274 return;
1275
1276 TiXmlElement* parent = pathNode ? pathNode : root;
1277
1278 if (path.find(_T('/')) != wxString::npos)
1279 {
1280 wxString sub;
1281 do
1282 {
1283 sub = path.BeforeFirst(_T('/'));
1284 path = path.AfterFirst(_T('/'));
1285
1286 if (sub.IsEmpty())
1287 parent = root;
1288 else if (sub.IsSameAs(_T(".")))
1289 ;
1290 else if (parent != root && sub.IsSameAs(_T("..")))
1291 parent = parent->Parent()->ToElement();
1292 else
1293 {
1294 TiXmlElement* n = parent->FirstChildElement(cbU2C(sub));
1295 if (n)
1296 parent = n;
1297 else
1298 return;
1299 }
1300 }
1301 while (path.find(_T('/')) != wxString::npos);
1302 }
1303
1304 if (!path.IsEmpty())
1305 {
1306 if (TiXmlNode *toRemove = parent->FirstChild(cbU2C(path)))
1307 {
1308 toRemove->Clear();
1309 parent->RemoveChild(toRemove);
1310 }
1311 }
1312 }
1313
1314
EnumerateKeys(const wxString & path)1315 wxArrayString ConfigManager::EnumerateKeys(const wxString& path)
1316 {
1317 wxString key(path + _T('/')); // the trailing slash hack is required because AssertPath expects a key name
1318 TiXmlNode* e = AssertPath(key);
1319 wxArrayString ret;
1320
1321 TiXmlElement *curr = nullptr;
1322 if (e)
1323 {
1324 while (e->IterateChildren(curr) && (curr = e->IterateChildren(curr)->ToElement()))
1325 {
1326 #if wxCHECK_VERSION(3, 0, 0)
1327 wxUniChar c = cbC2U(curr->Value())[0];
1328 #else
1329 wxChar c = *(cbC2U(curr->Value()));
1330 #endif
1331 if (c >= _T('A') && c <= _T('Z')) // opposite of the above
1332 ret.Add(cbC2U(curr->Value()));
1333 }
1334 }
1335 return ret;
1336 }
1337
Write(const wxString & name,const ISerializable & object)1338 void ConfigManager::Write(const wxString& name, const ISerializable& object)
1339 {
1340 wxString key(name);
1341 TiXmlElement* e = AssertPath(key);
1342
1343 TiXmlElement *obj = GetUniqElement(e, key);
1344
1345 TiXmlElement *s = GetUniqElement(obj, _T("obj"));
1346 SetNodeText(s, TiXmlText(cbU2C(wxBase64::Encode(object.SerializeOut()))));
1347 }
1348
Read(const wxString & name,ISerializable * object)1349 bool ConfigManager::Read(const wxString& name, ISerializable* object)
1350 {
1351 wxString str;
1352 wxString key(name);
1353 TiXmlElement* e = AssertPath(key);
1354
1355 TiXmlHandle parentHandle(e);
1356 TiXmlText *t = (TiXmlText *) parentHandle.FirstChild(cbU2C(key)).FirstChild("obj").FirstChild().Node();
1357
1358 if (t)
1359 {
1360 str.assign(cbC2U(t->Value()));
1361 object->SerializeIn(wxBase64::Decode(str));
1362 }
1363 return wxEmptyString;
1364 }
1365
Write(const wxString & name,const ConfigManagerContainer::StringToStringMap & map)1366 void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::StringToStringMap& map)
1367 {
1368 wxString key(name);
1369 TiXmlElement* e = AssertPath(key);
1370
1371 TiXmlElement *leaf = GetUniqElement(e, key);
1372
1373 TiXmlElement *mNode;
1374 mNode = GetUniqElement(leaf, _T("ssmap"));
1375 leaf->RemoveChild(mNode);
1376 mNode = GetUniqElement(leaf, _T("ssmap"));
1377
1378 for (ConfigManagerContainer::StringToStringMap::const_iterator it = map.begin(); it != map.end(); ++it)
1379 {
1380 TiXmlElement s(cbU2C(it->first));
1381
1382 TiXmlText t(cbU2C(it->second));
1383 t.SetCDATA(true);
1384
1385 s.InsertEndChild(t);
1386 mNode->InsertEndChild(s);
1387 }
1388 }
1389
Read(const wxString & name,ConfigManagerContainer::StringToStringMap * map)1390 void ConfigManager::Read(const wxString& name, ConfigManagerContainer::StringToStringMap* map)
1391 {
1392 wxString key(name);
1393 TiXmlElement* e = AssertPath(key);
1394
1395 TiXmlHandle parentHandle(e);
1396 TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("ssmap").Node();
1397
1398 TiXmlNode *curr = nullptr;
1399 if (mNode)
1400 {
1401 while ((curr = mNode->IterateChildren(curr)))
1402 (*map)[cbC2U(curr->Value())] = cbC2U(curr->FirstChild()->ToText()->Value());
1403 }
1404 }
1405
ReadSSMap(const wxString & name)1406 ConfigManagerContainer::StringToStringMap ConfigManager::ReadSSMap(const wxString& name)
1407 {
1408 ConfigManagerContainer::StringToStringMap ret;
1409 Read(name, &ret);
1410 return ret;
1411 }
1412
Write(const wxString & name,const ConfigManagerContainer::IntToStringMap & map)1413 void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::IntToStringMap& map)
1414 {
1415 wxString key(name);
1416 TiXmlElement* e = AssertPath(key);
1417
1418 TiXmlElement *leaf = GetUniqElement(e, key);
1419
1420 TiXmlElement *mNode;
1421 mNode = GetUniqElement(leaf, _T("ismap"));
1422 leaf->RemoveChild(mNode);
1423 mNode = GetUniqElement(leaf, _T("ismap"));
1424
1425 wxString tmp;
1426 for (ConfigManagerContainer::IntToStringMap::const_iterator it = map.begin(); it != map.end(); ++it)
1427 {
1428 tmp.Printf(_T("x%d"), (int) it->first);
1429 TiXmlElement s(tmp.mb_str());
1430
1431 TiXmlText t(cbU2C(it->second));
1432 t.SetCDATA(true);
1433
1434 s.InsertEndChild(t);
1435 mNode->InsertEndChild(s);
1436 }
1437 }
1438
Read(const wxString & name,ConfigManagerContainer::IntToStringMap * map)1439 void ConfigManager::Read(const wxString& name, ConfigManagerContainer::IntToStringMap* map)
1440 {
1441 wxString key(name);
1442 TiXmlElement* e = AssertPath(key);
1443
1444 TiXmlHandle parentHandle(e);
1445 TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("ismap").Node();
1446
1447 TiXmlNode *curr = nullptr;
1448 long tmp;
1449 if (mNode)
1450 {
1451 while ((curr = mNode->IterateChildren(curr)))
1452 {
1453 cbC2U(curr->Value()).Mid(1).ToLong(&tmp);
1454 (*map)[tmp] = cbC2U(curr->FirstChild()->ToText()->Value());
1455 }
1456 }
1457 }
1458
ReadISMap(const wxString & name)1459 ConfigManagerContainer::IntToStringMap ConfigManager::ReadISMap(const wxString& name)
1460 {
1461 ConfigManagerContainer::IntToStringMap ret;
1462 Read(name, &ret);
1463 return ret;
1464 }
1465
1466
1467
1468
1469
1470
Write(const wxString & name,const ConfigManagerContainer::StringSet & set)1471 void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::StringSet& set)
1472 {
1473 wxString key(name);
1474 TiXmlElement* e = AssertPath(key);
1475
1476 TiXmlElement *leaf = GetUniqElement(e, key);
1477
1478 TiXmlElement *mNode;
1479 mNode = GetUniqElement(leaf, _T("sset"));
1480 leaf->RemoveChild(mNode);
1481 mNode = GetUniqElement(leaf, _T("sset"));
1482
1483 for (ConfigManagerContainer::StringSet::const_iterator it = set.begin(); it != set.end(); ++it)
1484 {
1485 TiXmlElement s("s");
1486
1487 TiXmlText t(cbU2C(*it));
1488 t.SetCDATA(true);
1489
1490 s.InsertEndChild(t);
1491 mNode->InsertEndChild(s);
1492 }
1493 }
1494
1495
Read(const wxString & name,ConfigManagerContainer::StringSet * set)1496 void ConfigManager::Read(const wxString& name, ConfigManagerContainer::StringSet* set)
1497 {
1498 wxString key(name);
1499 TiXmlElement* e = AssertPath(key);
1500
1501 TiXmlHandle parentHandle(e);
1502 TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("sset").Node();
1503
1504 TiXmlNode *curr = nullptr;
1505 if (mNode)
1506 {
1507 while ((curr = mNode->IterateChildren(curr)))
1508 set->insert(cbC2U(curr->FirstChild()->ToText()->Value()));
1509 }
1510 }
1511
ReadSSet(const wxString & name)1512 ConfigManagerContainer::StringSet ConfigManager::ReadSSet(const wxString& name)
1513 {
1514 ConfigManagerContainer::StringSet ret;
1515 Read(name, &ret);
1516 return ret;
1517 }
1518
1519
Write(const wxString & name,const ConfigManagerContainer::SerializableObjectMap * map)1520 void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::SerializableObjectMap* map)
1521 {
1522 wxString key(name);
1523 TiXmlElement* e = AssertPath(key);
1524
1525 TiXmlElement *leaf = GetUniqElement(e, key);
1526
1527 TiXmlElement *mNode;
1528 mNode = GetUniqElement(leaf, _T("objmap"));
1529 leaf->RemoveChild(mNode);
1530 mNode = GetUniqElement(leaf, _T("objmap"));
1531
1532 for (ConfigManagerContainer::SerializableObjectMap::const_iterator it = map->begin(); it != map->end(); ++it)
1533 {
1534 TiXmlElement s(cbU2C(it->first));
1535 s.InsertEndChild(TiXmlText(cbU2C(wxBase64::Encode(it->second->SerializeOut()))));
1536 mNode->InsertEndChild(s);
1537 }
1538 }
1539
1540
InitPaths()1541 void ConfigManager::InitPaths()
1542 {
1543 ConfigManager::config_folder = ConfigManager::GetUserDataFolder();
1544 ConfigManager::home_folder = wxStandardPathsBase::Get().GetUserConfigDir();
1545 ConfigManager::app_path = ::DetermineExecutablePath();
1546 wxString res_path = ::DetermineResourcesPath();
1547
1548 // if non-empty, the app has overriden it (e.g. "--prefix" was passed in the command line)
1549 if (data_path_global.IsEmpty())
1550 {
1551 if (platform::windows)
1552 ConfigManager::data_path_global = app_path + _T("\\share\\codeblocks");
1553 else if (platform::macosx)
1554 ConfigManager::data_path_global = res_path + _T("/share/codeblocks");
1555 else
1556 ConfigManager::data_path_global = wxStandardPathsBase::Get().GetDataDir();
1557 }
1558 else
1559 ConfigManager::data_path_global = UnixFilename(data_path_global);
1560
1561 #ifdef CB_AUTOCONF
1562 if (plugin_path_global.IsEmpty())
1563 {
1564 if (platform::windows)
1565 ConfigManager::plugin_path_global = data_path_global;
1566 else if (platform::macosx)
1567 ConfigManager::plugin_path_global = data_path_global + _T("/plugins");
1568 else
1569 {
1570 #ifdef __WXGTK__
1571 // It seems we can not longer rely on wxStandardPathsBase::Get().GetPluginsDir(),
1572 // because its behaviour has changed on some systems (at least Fedora 14 64-bit).
1573 // So we create the pathname manually
1574 ConfigManager::plugin_path_global = ((const wxStandardPaths&)wxStandardPaths::Get()).GetInstallPrefix() + _T("/lib/codeblocks/plugins");
1575 // first assume, we use standard-paths
1576 if (!wxDirExists(ConfigManager::plugin_path_global) && wxIsPlatform64Bit())
1577 {
1578 // if standard-path does not exist and we are on 64-bit system, use lib64 instead
1579 ConfigManager::plugin_path_global = ((const wxStandardPaths&)wxStandardPaths::Get()).GetInstallPrefix() + _T("/lib64/codeblocks/plugins");
1580 }
1581 #endif // __WXGTK__
1582 }
1583 }
1584 #endif
1585
1586 wxString dataPathUser = ConfigManager::config_folder + wxFILE_SEP_PATH + _T("share");
1587 #ifdef __linux__
1588 if (!has_alternate_user_data_path)
1589 dataPathUser = wxString::FromUTF8(g_build_filename (g_get_user_data_dir(), NULL));
1590 #endif // __linux__
1591
1592 ConfigManager::data_path_user = dataPathUser + wxFILE_SEP_PATH + _T("codeblocks");
1593
1594 // if user- and global-datapath are the same (can happen in portable mode) we run in conflicts
1595 // so we extend the user-datapath with the users name
1596 if (wxFileName(ConfigManager::data_path_user) == wxFileName(ConfigManager::data_path_global))
1597 ConfigManager::data_path_user.append(_(".")+wxGetUserId());
1598
1599 CreateDirRecursively(ConfigManager::config_folder);
1600 CreateDirRecursively(ConfigManager::data_path_user + _T("/plugins/"));
1601 CreateDir(ConfigManager::data_path_user + _T("/scripts/"));
1602
1603 ConfigManager::temp_folder = wxStandardPathsBase::Get().GetTempDir();
1604 }
1605
MigrateFolders()1606 void ConfigManager::MigrateFolders()
1607 {
1608 #ifdef __linux__
1609 // if the old config-folder (~/.codeblocks) does not exist, we have nothing to do.
1610 if (!wxDirExists(wxStandardPaths::Get().GetUserDataDir()))
1611 return;
1612
1613 // ConfigManager::config_folder might be the portable-path but we want to migrate the standard-conform folder,
1614 // but only if it not already exists
1615 wxString newConfigFolder = wxString::FromUTF8(g_build_filename (g_get_user_config_dir(), "codeblocks", NULL));
1616 // if the new config folder already exist, we step out immediately
1617 if (wxDirExists(newConfigFolder))
1618 return;
1619
1620 wxString oldConfigFolder = wxStandardPaths::Get().GetUserDataDir();
1621 wxString oldDataFolder = oldConfigFolder + wxFILE_SEP_PATH + _T("share") + wxFILE_SEP_PATH + _T("codeblocks");
1622 wxString newDataFolder = wxString::FromUTF8(g_build_filename (g_get_user_data_dir(), NULL)) + wxFILE_SEP_PATH + _T("codeblocks");
1623 wxString msg;
1624 msg = F(_("The places where the configuration files and user-data files are stored\n"
1625 "have been changed to be more standard-conform.\n"
1626 "\n"
1627 "Now moving \"%s\"\n"
1628 "to \"%s\"\n"
1629 "and \"%s\"\n"
1630 "to \"%s\".\n"),
1631 oldDataFolder.wx_str(),
1632 newDataFolder.wx_str(),
1633 oldConfigFolder.wx_str(),
1634 newConfigFolder.wx_str());
1635 cbMessageBox(msg, _("Try to migrate config-folder ..."), wxICON_INFORMATION);
1636
1637 bool success = true;
1638 if (wxDirExists(oldDataFolder))
1639 {
1640 // make sure the target-folder exists
1641 CreateDirRecursively(newDataFolder);
1642 success = wxRenameFile(oldDataFolder, newDataFolder);
1643 wxRmdir(oldConfigFolder + wxFILE_SEP_PATH + _T("share"));
1644 }
1645 if (success)
1646 {
1647 // make sure the target-folder exists
1648 CreateDirRecursively(newConfigFolder);
1649 success = wxRenameFile(oldConfigFolder, newConfigFolder);
1650 }
1651 if (!success)
1652 {
1653 msg = F(_("Error moving \"%s\"\n"
1654 "to \"%s\"\n"
1655 "or \"%s\"\n"
1656 "to \"%s\".\n\n"
1657 "Please check the folders manually (access rights?) !\n"
1658 "A new configuration will be created from scratch!"),
1659 oldDataFolder.wx_str(),
1660 newDataFolder.wx_str(),
1661 oldConfigFolder.wx_str(),
1662 newConfigFolder.wx_str());
1663 cbMessageBox(msg, _("Error migrating config-folder ..."), wxICON_ERROR);
1664 }
1665 #endif // __linux__
1666 }
1667
Write(const wxString & name,const wxString & value,bool ignoreEmpty)1668 void ConfigManagerWrapper::Write(const wxString& name, const wxString& value, bool ignoreEmpty)
1669 {
1670 if (m_namespace.empty())
1671 return;
1672 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1673 c->Write(m_basepath + name, value, ignoreEmpty);
1674 }
1675
Read(const wxString & key,const wxString & defaultVal)1676 wxString ConfigManagerWrapper::Read(const wxString& key, const wxString& defaultVal)
1677 {
1678 if (m_namespace.empty())
1679 return defaultVal;
1680 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1681 return c->Read(m_basepath + key, defaultVal);
1682 }
1683
Read(const wxString & key,wxString * str)1684 bool ConfigManagerWrapper::Read(const wxString& key, wxString* str)
1685 {
1686 if (m_namespace.empty())
1687 return false;
1688 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1689 return c->Read(key, str);
1690 }
Write(const wxString & key,const char * str)1691 void ConfigManagerWrapper::Write(const wxString& key, const char* str)
1692 {
1693 if (m_namespace.empty())
1694 return;
1695 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1696 c->Write(key, str);
1697 }
1698
Write(const wxString & name,int value)1699 void ConfigManagerWrapper::Write(const wxString& name, int value)
1700 {
1701 if (m_namespace.empty())
1702 return;
1703 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1704 c->Write(m_basepath + name, value);
1705 }
Read(const wxString & name,int * value)1706 bool ConfigManagerWrapper::Read(const wxString& name, int* value)
1707 {
1708 if (m_namespace.empty())
1709 return false;
1710 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1711 return c->Read(m_basepath + name, value);
1712 }
1713
ReadInt(const wxString & name,int defaultVal)1714 int ConfigManagerWrapper::ReadInt(const wxString& name, int defaultVal)
1715 {
1716 if (m_namespace.empty())
1717 return defaultVal;
1718 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1719 return c->ReadInt(m_basepath + name, defaultVal);
1720 }
1721
Write(const wxString & name,bool value)1722 void ConfigManagerWrapper::Write(const wxString& name, bool value)
1723 {
1724 if (m_namespace.empty())
1725 return;
1726 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1727 c->Write(m_basepath + name, value);
1728 }
Read(const wxString & name,bool * value)1729 bool ConfigManagerWrapper::Read(const wxString& name, bool* value)
1730 {
1731 if (m_namespace.empty())
1732 return false;
1733 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1734 return c->Read(m_basepath + name, value);
1735 }
ReadBool(const wxString & name,bool defaultVal)1736 bool ConfigManagerWrapper::ReadBool(const wxString& name, bool defaultVal)
1737 {
1738 if (m_namespace.empty())
1739 return defaultVal;
1740 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1741 return c->ReadBool(m_basepath + name, defaultVal);
1742 }
1743
Write(const wxString & name,double value)1744 void ConfigManagerWrapper::Write(const wxString& name, double value)
1745 {
1746 if (m_namespace.empty())
1747 return;
1748 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1749 c->Write(m_basepath + name, value);
1750 }
Read(const wxString & name,double * value)1751 bool ConfigManagerWrapper::Read(const wxString& name, double* value)
1752 {
1753 if (m_namespace.empty())
1754 return false;
1755 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1756 return c->Read(m_basepath + name, value);
1757 }
ReadDouble(const wxString & name,double defaultVal)1758 double ConfigManagerWrapper::ReadDouble(const wxString& name, double defaultVal)
1759 {
1760 if (m_namespace.empty())
1761 return defaultVal;
1762 ConfigManager *c = Manager::Get()->GetConfigManager(m_namespace);
1763 return c->ReadDouble(m_basepath + name, defaultVal);
1764 }
1765
getCompilerPluginFilename()1766 static wxString getCompilerPluginFilename()
1767 {
1768 if (platform::windows)
1769 return wxT("compiler.dll");
1770 else if (platform::darwin || platform::macosx)
1771 return wxT("libcompiler.dylib");
1772 else
1773 return wxT("libcompiler.so");
1774 }
1775
cbReadBatchBuildPlugins()1776 wxArrayString cbReadBatchBuildPlugins()
1777 {
1778 ConfigManager *bbcfg = Manager::Get()->GetConfigManager(_T("plugins"));
1779 wxArrayString bbplugins = bbcfg->ReadArrayString(_T("/batch_build_plugins"));
1780
1781 if (!bbplugins.GetCount())
1782 bbplugins.Add(getCompilerPluginFilename());
1783
1784 return bbplugins;
1785 }
1786
cbWriteBatchBuildPlugins(wxArrayString bbplugins,wxWindow * messageBoxParent)1787 void cbWriteBatchBuildPlugins(wxArrayString bbplugins, wxWindow *messageBoxParent)
1788 {
1789 const wxString &compiler = getCompilerPluginFilename();
1790
1791 if (bbplugins.Index(compiler) == wxNOT_FOUND)
1792 {
1793 bbplugins.Add(compiler);
1794 cbMessageBox(_("The compiler plugin must always be loaded for batch builds!\n"
1795 "Automatically re-enabled."),
1796 _("Warning"), wxICON_WARNING, messageBoxParent);
1797 }
1798 ConfigManager *bbcfg = Manager::Get()->GetConfigManager(_T("plugins"));
1799 bbcfg->Write(_T("/batch_build_plugins"), bbplugins);
1800 }
1801