ManaPlus
configuration.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "configuration.h"
25 
26 #include "variabledata.h"
27 
28 #include "fs/files.h"
29 #include "fs/paths.h"
30 
31 #include "fs/virtfs/fs.h"
32 
34 
35 #include "utils/cast.h"
36 #include "utils/checkutils.h"
37 #include "utils/foreach.h"
38 #ifdef DEBUG_CONFIG
39 #include "utils/stringmap.h"
40 #endif // DEBUG_CONFIG
41 
42 #include "debug.h"
43 
44 #ifdef DEBUG_CONFIG
45 StringIntMap optionsCount;
46 #define GETLOG() if (logger) {logger->log("config get: " + key); \
47  if (mIsMain) optionsCount[key] = 1; }
48 #else // DEBUG_CONFIG
49 #define GETLOG()
50 #endif // DEBUG_CONFIG
51 
52 Configuration config; // XML file configuration reader
53 Configuration serverConfig; // XML file server configuration reader
54 Configuration features; // XML file features
55 Configuration branding; // XML branding information reader
56 Configuration paths; // XML default paths information reader
57 
58 const std::string unusedKeys[] =
59 {
60  "BotCheckerWindowSticky",
61  "afkmessage",
62  "BotCheckerWindowVisible",
63  "BotCheckerWindowWinX",
64  "BotCheckerWindowWinY",
65  "hideShield",
66  "AttackRange",
67  "emoteshortcut0",
68  "screenshotDirectory2",
69  "AttackRangeBorder",
70  "AttackRangeBorderDelay",
71  "AttackRangeBorderGradient",
72  "AttackRangeDelay",
73  "AttackRangeGradient",
74  "Being",
75  "BeingDelay",
76  "BeingGradient",
77  "BeingPopupSkin",
78  "BotCheckerWindowSkin",
79  "BuySellSkin",
80  "BuySkin",
81  "ChatSkin",
82  "CollisionHighlight",
83  "CollisionHighlightDelay",
84  "CollisionHighlightGradient",
85  "ColorCross",
86  "ColorCrossDelay",
87  "ColorCrossGradient",
88  "ColorExperience",
89  "ColorExperienceGradient",
90  "ColorPickup",
91  "ColorPickupGradient",
92  "DebugSkin",
93  "DropShortcutSkin",
94  "EmoteShortcutSkin",
95  "EquipmentSkin",
96  "ExpInfo",
97  "ExpInfoDelay",
98  "ExpInfoGradient",
99  "Experience",
100  "ExperienceGradient",
101  "GM",
102  "GMDelay",
103  "GMGradient",
104  "Guild",
105  "GuildDelay",
106  "GuildGradient",
107  "GuildSkin",
108  "HelpSkin",
109  "Hit CriticalDelay",
110  "Hit CriticalGradient",
111  "Hit Monster Player",
112  "Hit Monster PlayerGradient",
113  "Hit Player Monster",
114  "Hit Player MonsterGradient",
115  "HitCriticalDelay",
116  "HitCriticalGradient",
117  "HitLocalPlayerCriticalDelay",
118  "HitLocalPlayerCriticalGradient",
119  "HitLocalPlayerMiss",
120  "HitLocalPlayerMissDelay",
121  "HitLocalPlayerMissGradient",
122  "HitLocalPlayerMonster",
123  "HitLocalPlayerMonsterDelay",
124  "HitLocalPlayerMonsterGradient",
125  "HitMonsterPlayer",
126  "HitMonsterPlayerDelay",
127  "HitMonsterPlayerGradient",
128  "HitPlayerMonster",
129  "HitPlayerMonsterDelay",
130  "HitPlayerMonsterGradient",
131  "HomePlace",
132  "HomePlaceBorder",
133  "HomePlaceBorderDelay",
134  "HomePlaceBorderGradient",
135  "HomePlaceDelay",
136  "HomePlaceGradient",
137  "InventorySkin",
138  "ItemPopupSkin",
139  "ItemShortcutSkin",
140  "Kill statsSkin",
141  "MiniStatusSkin",
142  "MinimapSkin",
143  "Miss",
144  "MissDelay",
145  "MissGradient",
146  "Monster",
147  "MonsterAttackRange",
148  "MonsterAttackRangeDelay",
149  "MonsterAttackRangeGradient",
150  "MonsterDelay",
151  "MonsterGradient",
152  "NPC",
153  "NPCDelay",
154  "NPCGradient",
155  "NpcTextSkin",
156  "OutfitsSkin",
157  "Particle",
158  "ParticleDelay",
159  "ParticleGradient",
160  "PartyDelay",
161  "PartyGradient",
162  "PartySkin",
163  "Personal ShopSkin",
164  "Pickup",
165  "PickupGradient",
166  "Player",
167  "PlayerDelay",
168  "PlayerGradient",
169  "PopupMenuSkin",
170  "PortalHighlight",
171  "PortalHighlightDelay",
172  "PortalHighlightGradient",
173  "RecorderSkin",
174  "RecorderWinX",
175  "RecorderWinY",
176  "RoadPoint",
177  "RoadPointDelay",
178  "RoadPointGradient",
179  "Self",
180  "SelfDelay",
181  "SelfGradient",
182  "SellSkin",
183  "ServerDialogSkin",
184  "ShopSkin",
185  "SkillsSkin",
186  "SocialCreatePopupSkin",
187  "SocialSkin",
188  "SpecialsSkin",
189  "SpeechSkin",
190  "SpellPopupSkin",
191  "SpellShortcutSkin",
192  "StatusPopupSkin",
193  "StatusSkin",
194  "StorageSkin",
195  "TextCommandEditorSkin",
196  "TextPopupSkin",
197  "TradeSkin",
198  "WhoIsOnlineSkin",
199  "emoteshortcut1",
200  "emoteshortcut2",
201  "emoteshortcut3",
202  "emoteshortcut4",
203  "emoteshortcut5",
204  "emoteshortcut6",
205  "emoteshortcut7",
206  "emoteshortcut8",
207  "emoteshortcut9",
208  "emoteshortcut10",
209  "emoteshortcut11",
210  "emoteshortcut12",
211  "emoteshortcut13",
212  "fastOpenGL",
213  "keyAutoCompleteChat",
214  "keyDeActivateChat",
215  "keyTargetClosest",
216  "keyWindowParty",
217  "mapalpha",
218  "port",
219  "shopBuyList",
220  "shopSellList",
221  "OutfitAwayIndex",
222  "playerHomes",
223  "remember",
224  "screenshotDirectory",
225  ""
226 };
227 
228 void ConfigurationObject::setValue(const std::string &key,
229  const std::string &value)
230 {
231  mOptions[key] = value;
232 }
233 
234 void ConfigurationObject::deleteKey(const std::string &key)
235 {
236  mOptions.erase(key);
237 }
238 
239 void Configuration::setValue(const std::string &key,
240  const std::string &value)
241 {
242  ConfigurationObject::setValue(key, value);
243  mUpdated = true;
244 
245  // Notify listeners
246  const ListenerMapIterator list = mListenerMap.find(key);
247  if (list != mListenerMap.end())
248  {
249  Listeners listeners = list->second;
250  FOR_EACH (ListenerIterator, i, listeners)
251  (*i)->optionChanged(key);
252  }
253 }
254 
255 void Configuration::incValue(const std::string &key)
256 {
257  GETLOG();
258  const Options::const_iterator iter = mOptions.find(key);
259  setValue(key, (iter != mOptions.end())
260  ? atoi(iter->second.c_str()) + 1 : 1);
261 }
262 
263 void Configuration::setSilent(const std::string &key,
264  const std::string &value)
265 {
266  ConfigurationObject::setValue(key, value);
267 }
268 
269 std::string ConfigurationObject::getValue(const std::string &key,
270  const std::string &deflt) const
271 {
272  GETLOG();
273  const Options::const_iterator iter = mOptions.find(key);
274  return ((iter != mOptions.end()) ? iter->second : deflt);
275 }
276 
277 int ConfigurationObject::getValue(const std::string &key,
278  const int deflt) const
279 {
280  GETLOG();
281  const Options::const_iterator iter = mOptions.find(key);
282  return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
283 }
284 
285 int ConfigurationObject::getValueInt(const std::string &key,
286  const int deflt) const
287 {
288  GETLOG();
289  const Options::const_iterator iter = mOptions.find(key);
290  return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
291 }
292 
293 bool ConfigurationObject::getValueBool(const std::string &key,
294  const bool deflt) const
295 {
296  GETLOG();
297  const Options::const_iterator iter = mOptions.find(key);
298  if (iter != mOptions.end())
299  return atoi(iter->second.c_str()) != 0 ? true : false;
300  return deflt;
301 }
302 
303 unsigned ConfigurationObject::getValue(const std::string &key,
304  const unsigned deflt) const
305 {
306  GETLOG();
307  const Options::const_iterator iter = mOptions.find(key);
308  return (iter != mOptions.end()) ? CAST_U32(
309  atol(iter->second.c_str())) : deflt;
310 }
311 
312 double ConfigurationObject::getValue(const std::string &key,
313  const double deflt) const
314 {
315  GETLOG();
316  const Options::const_iterator iter = mOptions.find(key);
317  return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt;
318 }
319 
320 void ConfigurationObject::deleteList(const std::string &name)
321 {
322  for (ConfigurationList::const_iterator
323  it = mContainerOptions[name].begin();
324  it != mContainerOptions[name].end(); ++it)
325  {
326  delete *it;
327  }
328 
329  mContainerOptions[name].clear();
330 }
331 
333 {
334  for (std::map<std::string, ConfigurationList>::const_iterator
335  it = mContainerOptions.begin();
336  it != mContainerOptions.end(); ++it)
337  {
338  deleteList(it->first);
339  }
340  mOptions.clear();
341  mContainerOptions.clear();
342 }
343 
345  mOptions(),
346 #ifdef DEBUG_CONFIG
347  mContainerOptions(),
348  mLogKeys(false),
349  mIsMain(false)
350 #else // DEBUG_CONFIG
351 
352  mContainerOptions()
353 #endif // DEBUG_CONFIG
354 {
355 }
356 
358 {
359  clear();
360 }
361 
364  mListenerMap(),
365  mConfigPath(),
366  mDefaultsData(),
367  mDirectory(),
368  mFilename(),
369  mUseResManager(UseVirtFs_false),
370  mUpdated(false)
371 {
372 #ifdef DEBUG_CONFIG
373  mLogKeys = false;
374  mIsMain = false;
375 #endif // DEBUG_CONFIG
376 }
377 
379 {
380  for (DefaultsData::const_iterator iter = mDefaultsData.begin();
381  iter != mDefaultsData.end();
382  ++iter)
383  {
384  delete iter->second;
385  }
386  mDefaultsData.clear();
387 }
388 
390 {
391  cleanDefaults();
392 }
393 
395 {
396  cleanDefaults();
397  mConfigPath.clear();
398  mDirectory.clear();
399  mFilename.clear();
402 }
403 
404 int Configuration::getIntValue(const std::string &key) const
405 {
406  GETLOG();
407  int defaultValue = 0;
408  const Options::const_iterator iter = mOptions.find(key);
409  if (iter == mOptions.end())
410  {
411  const DefaultsData::const_iterator itdef
412  = mDefaultsData.find(key);
413 
414  if (itdef != mDefaultsData.end() && (itdef->second != nullptr))
415  {
416  const VariableData *const data = itdef->second;
417  const VariableData::DataType type = static_cast<
418  VariableData::DataType>(data->getType());
419  if (type == VariableData::DATA_INT)
420  {
421  defaultValue = (static_cast<const IntData*>(
422  data))->getData();
423  }
424  else if (type == VariableData::DATA_STRING)
425  {
426  defaultValue = atoi((static_cast<const StringData*>(
427  data))->getData().c_str());
428  }
429  else if (type == VariableData::DATA_BOOL)
430  {
431  if ((static_cast<const BoolData*>(data))->getData())
432  defaultValue = 1;
433  else
434  defaultValue = 0;
435  }
436  else if (type == VariableData::DATA_FLOAT)
437  {
438  defaultValue = CAST_S32(
439  (static_cast<const FloatData*>(data))->getData());
440  }
441  }
442  else
443  {
444  reportAlways(
445  "%s: No integer value in registry for key %s",
446  mConfigPath.c_str(),
447  key.c_str())
448  }
449  }
450  else
451  {
452  defaultValue = atoi(iter->second.c_str());
453  }
454  return defaultValue;
455 }
456 
457 int Configuration::resetIntValue(const std::string &key)
458 {
459  GETLOG();
460  int defaultValue = 0;
461  const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
462  if (itdef == mDefaultsData.end())
463  {
464  reportAlways("%s: No integer value in registry for key %s",
465  mConfigPath.c_str(),
466  key.c_str())
467  }
468  else
469  {
470  const VariableData *const data = itdef->second;
471  if (data != nullptr &&
472  data->getType() == VariableData::DATA_INT)
473  {
474  defaultValue = (static_cast<const IntData*>(
475  data))->getData();
476  }
477  else
478  {
479  reportAlways("%s: No integer value in registry for key %s",
480  mConfigPath.c_str(),
481  key.c_str())
482  }
483  }
484  setValue(key, defaultValue);
485  return defaultValue;
486 }
487 
488 std::string Configuration::getStringValue(const std::string &key) const
489 {
490  GETLOG();
491  std::string defaultValue;
492  const Options::const_iterator iter = mOptions.find(key);
493  if (iter == mOptions.end())
494  {
495  const DefaultsData::const_iterator
496  itdef = mDefaultsData.find(key);
497 
498  if (itdef != mDefaultsData.end() &&
499  (itdef->second != nullptr))
500  {
501  const VariableData *const data = itdef->second;
502  const VariableData::DataType type = static_cast<
503  VariableData::DataType>(data->getType());
504  if (type == VariableData::DATA_STRING)
505  {
506  defaultValue = (static_cast<const StringData*>(
507  data))->getData();
508  }
509  else if (type == VariableData::DATA_BOOL)
510  {
511  if ((static_cast<const BoolData*>(data))->getData())
512  defaultValue = "1";
513  else
514  defaultValue = "0";
515  }
516  else if (type == VariableData::DATA_INT)
517  {
518  defaultValue = toString((static_cast<const IntData*>(
519  data))->getData());
520  }
521  else if (type == VariableData::DATA_FLOAT)
522  {
523  defaultValue = toString((static_cast<const FloatData*>(
524  data))->getData());
525  }
526  }
527  else
528  {
529  reportAlways("%s: No string value in registry for key %s",
530  mConfigPath.c_str(),
531  key.c_str())
532  }
533  }
534  else
535  {
536  defaultValue = iter->second;
537  }
538  return defaultValue;
539 }
540 
541 
542 float Configuration::getFloatValue(const std::string &key) const
543 {
544  GETLOG();
545  float defaultValue = 0.0F;
546  const Options::const_iterator iter = mOptions.find(key);
547  if (iter == mOptions.end())
548  {
549  const DefaultsData::const_iterator itdef
550  = mDefaultsData.find(key);
551 
552  if (itdef != mDefaultsData.end() &&
553  (itdef->second != nullptr))
554  {
555  const VariableData *const data = itdef->second;
556  const VariableData::DataType type = static_cast<
557  VariableData::DataType>(data->getType());
558  if (type == VariableData::DATA_FLOAT)
559  {
560  defaultValue = static_cast<float>(
561  (static_cast<const FloatData*>(data))->getData());
562  }
563  else if (type == VariableData::DATA_STRING)
564  {
565  defaultValue = static_cast<float>(atof((
566  static_cast<const StringData*>(
567  data))->getData().c_str()));
568  }
569  else if (type == VariableData::DATA_BOOL)
570  {
571  if ((static_cast<const BoolData*>(data))->getData())
572  defaultValue = 1;
573  else
574  defaultValue = 0;
575  }
576  else if (type == VariableData::DATA_INT)
577  {
578  defaultValue = static_cast<float>((
579  static_cast<const IntData*>(
580  data))->getData());
581  }
582  }
583  else
584  {
585  reportAlways("%s: No float value in registry for key %s",
586  mConfigPath.c_str(),
587  key.c_str())
588  }
589  }
590  else
591  {
592  defaultValue = static_cast<float>(atof(iter->second.c_str()));
593  }
594  return defaultValue;
595 }
596 
597 bool Configuration::getBoolValue(const std::string &key) const
598 {
599  GETLOG();
600  bool defaultValue = false;
601  const Options::const_iterator iter = mOptions.find(key);
602  if (iter == mOptions.end())
603  {
604  const DefaultsData::const_iterator itdef
605  = mDefaultsData.find(key);
606 
607  if (itdef != mDefaultsData.end() &&
608  (itdef->second != nullptr))
609  {
610  const VariableData *const data = itdef->second;
611  const VariableData::DataType type = static_cast<
612  VariableData::DataType>(data->getType());
613  if (type == VariableData::DATA_BOOL)
614  {
615  defaultValue = (static_cast<const BoolData*>(
616  data))->getData();
617  }
618  else if (type == VariableData::DATA_INT)
619  {
620  if ((static_cast<const IntData*>(data))->getData() != 0)
621  defaultValue = true;
622  else
623  defaultValue = false;
624  }
625  else if (type == VariableData::DATA_STRING)
626  {
627  if ((static_cast<const StringData*>(
628  data))->getData() != "0")
629  {
630  defaultValue = true;
631  }
632  else
633  {
634  defaultValue = false;
635  }
636  }
637  if (type == VariableData::DATA_FLOAT)
638  {
639  if (CAST_S32((static_cast<const FloatData*>(
640  data))->getData()) != 0)
641  {
642  defaultValue = true;
643  }
644  else
645  {
646  defaultValue = false;
647  }
648  }
649  }
650  else
651  {
652  reportAlways(
653  "%s: No boolean value in registry for key %s",
654  mConfigPath.c_str(),
655  key.c_str())
656  }
657  }
658  else
659  {
660  defaultValue = getBoolFromString(iter->second);
661  }
662 
663  return defaultValue;
664 }
665 
666 bool Configuration::resetBoolValue(const std::string &key)
667 {
668  GETLOG();
669  bool defaultValue = false;
670  const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
671 
672  if (itdef == mDefaultsData.end())
673  {
674  reportAlways("%s: No boolean value in registry for key %s",
675  mConfigPath.c_str(),
676  key.c_str())
677  }
678  else
679  {
680  const VariableData *const data = itdef->second;
681  if (data != nullptr &&
682  data->getType() == VariableData::DATA_BOOL)
683  {
684  defaultValue = (static_cast<const BoolData*>(data))->getData();
685  }
686  else
687  {
688  reportAlways("%s: No boolean value in registry for key %s",
689  mConfigPath.c_str(),
690  key.c_str())
691  }
692  }
693 
694  setValue(key, defaultValue);
695  return defaultValue;
696 }
697 
698 
699 void ConfigurationObject::initFromXML(XmlNodeConstPtrConst parentNode)
700 {
701  clear();
702 
703  if (parentNode == nullptr)
704  return;
705 
706  for_each_xml_child_node(node, parentNode)
707  {
708  if (xmlNameEqual(node, "list"))
709  {
710  // list option handling
711  const std::string name = XML::getProperty(node,
712  "name", std::string());
713 
714  for_each_xml_child_node(subnode, node)
715  {
716  if (xmlNameEqual(subnode, name.c_str()) &&
717  xmlTypeEqual(subnode, XML_ELEMENT_NODE))
718  {
719  ConfigurationObject *const cobj = new ConfigurationObject;
720  cobj->initFromXML(subnode); // recurse
721  mContainerOptions[name].push_back(cobj);
722  }
723  }
724  }
725  else if (xmlNameEqual(node, "option"))
726  {
727  // single option handling
728  const std::string name = XML::getProperty(node,
729  "name", std::string());
730  if (!name.empty())
731  {
732  mOptions[name] = XML::getProperty(node,
733  "value", std::string());
734  }
735  } // otherwise ignore
736  }
737 }
738 
739 void Configuration::init(const std::string &filename,
740  const UseVirtFs useResManager,
741  const SkipError skipError)
742 {
743  cleanDefaults();
744  clear();
745  mFilename = filename;
746  mUseResManager = useResManager;
747 
748  if (useResManager == UseVirtFs_true)
749  {
750  mConfigPath = "virtfs://" + filename;
751  mDirectory.clear();
752  if (VirtFs::exists(filename) == false)
753  {
754  logger->log("Warning: No configuration file (%s)",
755  filename.c_str());
756  return;
757  }
758  }
759  else
760  {
761  mConfigPath = filename;
762  logger->log1("init 1");
763  mDirectory = getRealPath(getFileDir(filename));
764  if (Files::existsLocal(filename) == false)
765  {
766  logger->log("Warning: No configuration file (%s)",
767  filename.c_str());
768  return;
769  }
770  }
771 
772  XML::Document doc(filename,
773  useResManager,
774  skipError);
775  logger->log1("init 2");
776  if (doc.rootNode() == nullptr)
777  {
778  logger->log("Couldn't open configuration file: %s", filename.c_str());
779  return;
780  }
781 
782  XmlNodeConstPtrConst rootNode = doc.rootNode();
783 
784  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "configuration"))
785  {
786  logger->log("Warning: No configuration file (%s)", filename.c_str());
787  return;
788  }
789 
790  initFromXML(rootNode);
791 }
792 
794 {
796  if (doc.rootNode() == nullptr)
797  {
798  logger->log("Couldn't open configuration file: %s", mFilename.c_str());
799  return;
800  }
801 
802  XmlNodeConstPtrConst rootNode = doc.rootNode();
803 
804  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "configuration"))
805  {
806  logger->log("Warning: No configuration file (%s)", mFilename.c_str());
807  return;
808  }
809 
810  initFromXML(rootNode);
811 }
812 
813 void ConfigurationObject::writeToXML(XmlTextWriterPtr writer)
814 {
815  FOR_EACH (Options::const_iterator, i, mOptions)
816  {
817 #ifdef DEBUG_CONFIG
818  if (mLogKeys)
819  {
820  if (optionsCount.find(i->first) == optionsCount.end())
821  logger->log("unused configuration option: " + i->first);
822  }
823 #endif // DEBUG_CONFIG
824 
825  XmlTextWriterStartElement(writer, "option");
826  XmlTextWriterWriteAttribute(writer, "name", i->first.c_str());
827  XmlTextWriterWriteAttribute(writer, "value", i->second.c_str());
828  XmlTextWriterEndElement(writer);
829  }
830 
831  for (std::map<std::string, ConfigurationList>::const_iterator
832  it = mContainerOptions.begin(), it_fend = mContainerOptions.end();
833  it != it_fend; ++ it)
834  {
835  const char *const name = it->first.c_str();
836 
837  XmlTextWriterStartElement(writer, "list");
838  XmlTextWriterWriteAttribute(writer, "name", name);
839 
840  // recurse on all elements
841  FOR_EACH (ConfigurationList::const_iterator, elt_it, it->second)
842  {
843  XmlTextWriterStartElement(writer, name);
844  if (*elt_it != nullptr)
845  (*elt_it)->writeToXML(writer);
846  XmlTextWriterEndElement(writer);
847  }
848 
849  XmlTextWriterEndElement(writer);
850  }
851 }
852 
854 {
855  if (mUpdated)
856  write();
857 }
858 
860 {
861  BLOCK_START("Configuration::write")
862  if (mConfigPath.empty())
863  {
864  BLOCK_END("Configuration::write")
865  return;
866  }
867 
868  mUpdated = false;
869  // Do not attempt to write to file that cannot be opened for writing
870  FILE *const testFile = fopen(mConfigPath.c_str(), "w");
871  if (testFile == nullptr)
872  {
873  reportAlways("Configuration::write() couldn't open %s for writing",
874  mConfigPath.c_str())
875  BLOCK_END("Configuration::write")
876  return;
877  }
878  fclose(testFile);
879 
880  XmlTextWriterPtr writer = XmlNewTextWriterFilename(
881  mConfigPath.c_str(), 0);
882 
883  if (writer == nullptr)
884  {
885  logger->log1("Configuration::write() error while creating writer");
886  BLOCK_END("Configuration::write")
887  return;
888  }
889 
890  logger->log1("Configuration::write() writing configuration...");
891 
892  XmlTextWriterSetIndent(writer, 1);
893  XmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr);
894 // xmlTextWriterStartDocument(writer, nullptr, "utf8", nullptr);
895  XmlTextWriterStartRootElement(writer, "configuration");
896 
897  writeToXML(writer);
898 
899  XmlTextWriterEndDocument(writer);
900  XmlSaveTextWriterFilename(writer,
901  mConfigPath.c_str());
902  XmlFreeTextWriter(writer);
903  BLOCK_END("Configuration::write")
904 }
905 
906 void Configuration::addListener(const std::string &key,
907  ConfigListener *const listener)
908 {
909  mListenerMap[key].push_front(listener);
910 }
911 
912 void Configuration::removeListener(const std::string &key,
913  ConfigListener *const listener)
914 {
915  mListenerMap[key].remove(listener);
916 }
917 
918 #ifdef ENABLE_CHECKS
919 void Configuration::checkListeners(ConfigListener *const listener,
920  const char *const file,
921  const unsigned line)
922 {
924  {
925  Listeners listeners = it->second;
926  FOR_EACH (ListenerIterator, it2, listeners)
927  {
928  if (*it2 == listener)
929  {
930  logger->log("detected not cleaned listener: %p, %s:%u",
931  static_cast<void*>(listener), file, line);
932  exit(1);
933  }
934  }
935  }
936 }
937 #endif // ENABLE_CHECKS
938 
940 {
942  (it->second).remove(listener);
943 }
944 
946 {
947  if (mOptions.find(unusedKeys[0]) != mOptions.end() ||
948  mOptions.find(unusedKeys[1]) != mOptions.end() ||
949  mOptions.find(unusedKeys[2]) != mOptions.end())
950  {
951  int f = 0;
952  while (!unusedKeys[f].empty())
953  {
954  deleteKey(unusedKeys[f]);
955  logger->log("remove unused key: " + unusedKeys[f]);
956  f ++;
957  }
958  for (f = 0; f < 80; f ++)
959  {
960  const std::string str = toString(f);
961  deleteKey("Outfit" + str);
962  deleteKey("OutfitUnequip" + str);
963  deleteKey("commandShortcutCmd" + str);
964  deleteKey("commandShortcutFlags" + str);
965  deleteKey("commandShortcutSymbol" + str);
966  deleteKey("drop" + str);
967  deleteKey("shortcut" + str);
968  }
969  }
970 }
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define reportAlways(...)
Definition: checkutils.h:253
virtual void initFromXML(const xmlNode *const parentNode)
int getValueInt(const std::string &key, const int deflt) const
std::string getValue(const std::string &key, const std::string &deflt) const
virtual ~ConfigurationObject()
bool getValueBool(const std::string &key, const bool deflt) const
void deleteList(const std::string &name)
virtual void writeToXML(const xmlTextWriterPtr writer)
void deleteKey(const std::string &key)
virtual void setValue(const std::string &key, const std::string &value)
std::map< std::string, ConfigurationList > mContainerOptions
bool getBoolValue(const std::string &key) const
std::string getStringValue(const std::string &key) const
float getFloatValue(const std::string &key) const
void addListener(const std::string &key, ConfigListener *const listener)
std::string mDirectory
std::string mFilename
std::string mConfigPath
void setValue(const std::string &key, const std::string &value)
bool resetBoolValue(const std::string &key)
void incValue(const std::string &key)
Listeners::iterator ListenerIterator
UseVirtFs mUseResManager
ListenerMap::iterator ListenerMapIterator
void removeListener(const std::string &key, ConfigListener *const listener)
int resetIntValue(const std::string &key)
std::list< ConfigListener * > Listeners
ListenerMap mListenerMap
void setSilent(const std::string &key, const std::string &value)
void removeListeners(ConfigListener *const listener)
void init(const std::string &filename, const UseVirtFs useResManager, const SkipError skipError)
DefaultsData mDefaultsData
Defaults of value for a given key.
int getIntValue(const std::string &key) const
void log(const char *const log_text,...)
Definition: logger.cpp:269
void log1(const char *const log_text)
Definition: logger.cpp:238
xmlNodePtr rootNode()
Definition: libxml.cpp:169
Configuration config
Configuration features
Configuration paths
#define GETLOG()
Configuration serverConfig
Configuration branding
const std::string unusedKeys[]
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:161
Logger * logger
Definition: logger.cpp:89
uint32_t data
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
bool existsLocal(const std::string &path)
Definition: files.cpp:209
bool remove(const std::string &filename)
Definition: fs.cpp:780
bool exists(std::string name)
Definition: fs.cpp:124
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:174
ItemOptionDb::OptionInfos mOptions
std::string getRealPath(const std::string &str)
Definition: paths.cpp:84
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
std::string empty
Definition: podict.cpp:26
const bool SkipError_false
Definition: skiperror.h:30
bool SkipError
Definition: skiperror.h:30
std::map< std::string, int > StringIntMap
Definition: stringmap.h:28
std::string getFileDir(const std::string &path)
bool getBoolFromString(const std::string &text)
const bool UseVirtFs_false
Definition: usevirtfs.h:30
bool UseVirtFs
Definition: usevirtfs.h:30
const bool UseVirtFs_true
Definition: usevirtfs.h:30