GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/configuration.cpp Lines: 261 325 80.3 %
Date: 2021-03-17 Branches: 316 624 50.6 %

Line Branch Exec Source
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
33
#include "listeners/configlistener.h"
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
1
Configuration config;              // XML file configuration reader
53
1
Configuration serverConfig;        // XML file server configuration reader
54
1
Configuration features;            // XML file features
55
1
Configuration branding;            // XML branding information reader
56
1
Configuration paths;               // XML default paths information reader
57
58
3
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



















































































333
};
227
228
void ConfigurationObject::setValue(const std::string &key,
229
                                   const std::string &value)
230
{
231
58678
    mOptions[key] = value;
232
}
233
234
501
void ConfigurationObject::deleteKey(const std::string &key)
235
{
236
1002
    mOptions.erase(key);
237
501
}
238
239
29337
void Configuration::setValue(const std::string &key,
240
                             const std::string &value)
241
{
242
58674
    ConfigurationObject::setValue(key, value);
243
29337
    mUpdated = true;
244
245
    // Notify listeners
246
58674
    const ListenerMapIterator list = mListenerMap.find(key);
247
58674
    if (list != mListenerMap.end())
248
    {
249
590
        Listeners listeners = list->second;
250
885
        FOR_EACH (ListenerIterator, i, listeners)
251
2732
            (*i)->optionChanged(key);
252
    }
253
29337
}
254
255
1
void Configuration::incValue(const std::string &key)
256
{
257
    GETLOG();
258
3
    const Options::const_iterator iter = mOptions.find(key);
259
3
    setValue(key, (iter != mOptions.end())
260
4
        ? atoi(iter->second.c_str()) + 1 : 1);
261
1
}
262
263
2
void Configuration::setSilent(const std::string &key,
264
                              const std::string &value)
265
{
266
4
    ConfigurationObject::setValue(key, value);
267
2
}
268
269
10223
std::string ConfigurationObject::getValue(const std::string &key,
270
                                          const std::string &deflt) const
271
{
272
    GETLOG();
273
20446
    const Options::const_iterator iter = mOptions.find(key);
274
38708
    return ((iter != mOptions.end()) ? iter->second : deflt);
275
}
276
277
8637
int ConfigurationObject::getValue(const std::string &key,
278
                                  const int deflt) const
279
{
280
    GETLOG();
281
17274
    const Options::const_iterator iter = mOptions.find(key);
282
42270
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
283
}
284
285
8554
int ConfigurationObject::getValueInt(const std::string &key,
286
                                     const int deflt) const
287
{
288
    GETLOG();
289
17108
    const Options::const_iterator iter = mOptions.find(key);
290
42215
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
291
}
292
293
261
bool ConfigurationObject::getValueBool(const std::string &key,
294
                                       const bool deflt) const
295
{
296
    GETLOG();
297
522
    const Options::const_iterator iter = mOptions.find(key);
298
522
    if (iter != mOptions.end())
299
54
        return atoi(iter->second.c_str()) != 0 ? true : false;
300
    return deflt;
301
}
302
303
8
unsigned ConfigurationObject::getValue(const std::string &key,
304
                                       const unsigned deflt) const
305
{
306
    GETLOG();
307
16
    const Options::const_iterator iter = mOptions.find(key);
308
21
    return (iter != mOptions.end()) ? CAST_U32(
309
23
            atol(iter->second.c_str())) : deflt;
310
}
311
312
6
double ConfigurationObject::getValue(const std::string &key,
313
                                     const double deflt) const
314
{
315
    GETLOG();
316
12
    const Options::const_iterator iter = mOptions.find(key);
317
27
    return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt;
318
}
319
320
408
void ConfigurationObject::deleteList(const std::string &name)
321
{
322
408
    for (ConfigurationList::const_iterator
323
1224
         it = mContainerOptions[name].begin();
324
816
         it != mContainerOptions[name].end(); ++it)
325
    {
326
        delete *it;
327
    }
328
329
816
    mContainerOptions[name].clear();
330
408
}
331
332
1353
void ConfigurationObject::clear()
333
{
334
1557
    for (std::map<std::string, ConfigurationList>::const_iterator
335
4059
         it = mContainerOptions.begin();
336
3114
         it != mContainerOptions.end(); ++it)
337
    {
338
204
        deleteList(it->first);
339
    }
340
2706
    mOptions.clear();
341
2706
    mContainerOptions.clear();
342
1353
}
343
344
209
ConfigurationObject::ConfigurationObject() :
345
    mOptions(),
346
#ifdef DEBUG_CONFIG
347
    mContainerOptions(),
348
    mLogKeys(false),
349
    mIsMain(false)
350
#else  // DEBUG_CONFIG
351
352
627
    mContainerOptions()
353
#endif  // DEBUG_CONFIG
354
{
355
204
}
356
357
1040
ConfigurationObject::~ConfigurationObject()
358
{
359
209
    clear();
360
413
}
361
362
5
Configuration::Configuration() :
363
    ConfigurationObject(),
364
    mListenerMap(),
365
    mConfigPath(),
366
    mDefaultsData(),
367
    mDirectory(),
368
    mFilename(),
369
    mUseResManager(UseVirtFs_false),
370
35
    mUpdated(false)
371
{
372
#ifdef DEBUG_CONFIG
373
    mLogKeys = false;
374
    mIsMain = false;
375
#endif  // DEBUG_CONFIG
376
}
377
378
1441
void Configuration::cleanDefaults()
379
{
380
221490
    for (DefaultsData::const_iterator iter = mDefaultsData.begin();
381
434334
         iter != mDefaultsData.end();
382
         ++iter)
383
    {
384
215726
        delete iter->second;
385
    }
386
2882
    mDefaultsData.clear();
387
1441
}
388
389
35
Configuration::~Configuration()
390
{
391
5
    cleanDefaults();
392
5
}
393
394
void Configuration::unload()
395
{
396
    cleanDefaults();
397
    mConfigPath.clear();
398
    mDirectory.clear();
399
    mFilename.clear();
400
    mUseResManager = UseVirtFs_false;
401
    ConfigurationObject::clear();
402
}
403
404
1033
int Configuration::getIntValue(const std::string &key) const
405
{
406
    GETLOG();
407
1033
    int defaultValue = 0;
408
2066
    const Options::const_iterator iter = mOptions.find(key);
409
2066
    if (iter == mOptions.end())
410
    {
411
        const DefaultsData::const_iterator itdef
412
1770
            = mDefaultsData.find(key);
413
414

2654
        if (itdef != mDefaultsData.end() && (itdef->second != nullptr))
415
        {
416
884
            const VariableData *const data = itdef->second;
417
            const VariableData::DataType type = static_cast<
418
884
                VariableData::DataType>(data->getType());
419
884
            if (type == VariableData::DATA_INT)
420
            {
421
                defaultValue = (static_cast<const IntData*>(
422
880
                    data))->getData();
423
            }
424
4
            else if (type == VariableData::DATA_STRING)
425
            {
426
1
                defaultValue = atoi((static_cast<const StringData*>(
427
2
                    data))->getData().c_str());
428
            }
429
3
            else if (type == VariableData::DATA_BOOL)
430
            {
431
2
                if ((static_cast<const BoolData*>(data))->getData())
432
                    defaultValue = 1;
433
                else
434
1
                    defaultValue = 0;
435
            }
436
1
            else if (type == VariableData::DATA_FLOAT)
437
            {
438
1
                defaultValue = CAST_S32(
439
1
                    (static_cast<const FloatData*>(data))->getData());
440
            }
441
        }
442
        else
443
        {
444
4
            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
444
        defaultValue = atoi(iter->second.c_str());
453
    }
454
1032
    return defaultValue;
455
}
456
457
1
int Configuration::resetIntValue(const std::string &key)
458
{
459
    GETLOG();
460
1
    int defaultValue = 0;
461
3
    const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
462
2
    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
1
        const VariableData *const data = itdef->second;
471

2
        if (data != nullptr &&
472
1
            data->getType() == VariableData::DATA_INT)
473
        {
474
            defaultValue = (static_cast<const IntData*>(
475
1
                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
1
    setValue(key, defaultValue);
485
1
    return defaultValue;
486
}
487
488
3975
std::string Configuration::getStringValue(const std::string &key) const
489
{
490
    GETLOG();
491
3975
    std::string defaultValue;
492
7950
    const Options::const_iterator iter = mOptions.find(key);
493
7950
    if (iter == mOptions.end())
494
    {
495
        const DefaultsData::const_iterator
496
7880
            itdef = mDefaultsData.find(key);
497
498

11819
        if (itdef != mDefaultsData.end() &&
499
3939
            (itdef->second != nullptr))
500
        {
501
3939
            const VariableData *const data = itdef->second;
502
            const VariableData::DataType type = static_cast<
503
3939
                VariableData::DataType>(data->getType());
504
3939
            if (type == VariableData::DATA_STRING)
505
            {
506
                defaultValue = (static_cast<const StringData*>(
507
3841
                    data))->getData();
508
            }
509
98
            else if (type == VariableData::DATA_BOOL)
510
            {
511
4
                if ((static_cast<const BoolData*>(data))->getData())
512
                    defaultValue = "1";
513
                else
514
                    defaultValue = "0";
515
            }
516
94
            else if (type == VariableData::DATA_INT)
517
            {
518
182
                defaultValue = toString((static_cast<const IntData*>(
519
91
                    data))->getData());
520
            }
521
3
            else if (type == VariableData::DATA_FLOAT)
522
            {
523
6
                defaultValue = toString((static_cast<const FloatData*>(
524
3
                    data))->getData());
525
            }
526
        }
527
        else
528
        {
529


4
            reportAlways("%s: No string value in registry for key %s",
530
                mConfigPath.c_str(),
531
                key.c_str())
532
        }
533
    }
534
    else
535
    {
536
35
        defaultValue = iter->second;
537
    }
538
3974
    return defaultValue;
539
}
540
541
542
70
float Configuration::getFloatValue(const std::string &key) const
543
{
544
    GETLOG();
545
70
    float defaultValue = 0.0F;
546
140
    const Options::const_iterator iter = mOptions.find(key);
547
140
    if (iter == mOptions.end())
548
    {
549
        const DefaultsData::const_iterator itdef
550
118
            = mDefaultsData.find(key);
551
552

176
        if (itdef != mDefaultsData.end() &&
553
58
            (itdef->second != nullptr))
554
        {
555
58
            const VariableData *const data = itdef->second;
556
            const VariableData::DataType type = static_cast<
557
58
                VariableData::DataType>(data->getType());
558
58
            if (type == VariableData::DATA_FLOAT)
559
            {
560
54
                defaultValue = static_cast<float>(
561
54
                    (static_cast<const FloatData*>(data))->getData());
562
            }
563
4
            else if (type == VariableData::DATA_STRING)
564
            {
565
2
                defaultValue = static_cast<float>(atof((
566
                    static_cast<const StringData*>(
567
1
                    data))->getData().c_str()));
568
            }
569
3
            else if (type == VariableData::DATA_BOOL)
570
            {
571
2
                if ((static_cast<const BoolData*>(data))->getData())
572
                    defaultValue = 1;
573
                else
574
1
                    defaultValue = 0;
575
            }
576
1
            else if (type == VariableData::DATA_INT)
577
            {
578
1
                defaultValue = static_cast<float>((
579
                    static_cast<const IntData*>(
580
1
                    data))->getData());
581
            }
582
        }
583
        else
584
        {
585
4
            reportAlways("%s: No float value in registry for key %s",
586
                mConfigPath.c_str(),
587
                key.c_str())
588
        }
589
    }
590
    else
591
    {
592
33
        defaultValue = static_cast<float>(atof(iter->second.c_str()));
593
    }
594
69
    return defaultValue;
595
}
596
597
2411
bool Configuration::getBoolValue(const std::string &key) const
598
{
599
    GETLOG();
600
2411
    bool defaultValue = false;
601
4822
    const Options::const_iterator iter = mOptions.find(key);
602
4822
    if (iter == mOptions.end())
603
    {
604
        const DefaultsData::const_iterator itdef
605
4794
            = mDefaultsData.find(key);
606
607

7190
        if (itdef != mDefaultsData.end() &&
608
2396
            (itdef->second != nullptr))
609
        {
610
2396
            const VariableData *const data = itdef->second;
611
            const VariableData::DataType type = static_cast<
612
2396
                VariableData::DataType>(data->getType());
613
2396
            if (type == VariableData::DATA_BOOL)
614
            {
615
                defaultValue = (static_cast<const BoolData*>(
616
2391
                    data))->getData();
617
            }
618
5
            else if (type == VariableData::DATA_INT)
619
            {
620
3
                if ((static_cast<const IntData*>(data))->getData() != 0)
621
                    defaultValue = true;
622
                else
623
2
                    defaultValue = false;
624
            }
625
2
            else if (type == VariableData::DATA_STRING)
626
            {
627
1
                if ((static_cast<const StringData*>(
628
1
                    data))->getData() != "0")
629
                {
630
                    defaultValue = true;
631
                }
632
                else
633
                {
634
                    defaultValue = false;
635
                }
636
            }
637
2396
            if (type == VariableData::DATA_FLOAT)
638
            {
639
1
                if (CAST_S32((static_cast<const FloatData*>(
640
1
                    data))->getData()) != 0)
641
                {
642
                    defaultValue = true;
643
                }
644
                else
645
                {
646
1
                    defaultValue = false;
647
                }
648
            }
649
        }
650
        else
651
        {
652
4
            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
14
        defaultValue = getBoolFromString(iter->second);
661
    }
662
663
2410
    return defaultValue;
664
}
665
666
2
bool Configuration::resetBoolValue(const std::string &key)
667
{
668
    GETLOG();
669
2
    bool defaultValue = false;
670
6
    const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
671
672
4
    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
2
        const VariableData *const data = itdef->second;
681

4
        if (data != nullptr &&
682
2
            data->getType() == VariableData::DATA_BOOL)
683
        {
684
2
            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
4
    setValue(key, defaultValue);
695
2
    return defaultValue;
696
}
697
698
699
368
void ConfigurationObject::initFromXML(XmlNodeConstPtrConst parentNode)
700
{
701
368
    clear();
702
703
368
    if (parentNode == nullptr)
704
        return;
705
706
114240
    for_each_xml_child_node(node, parentNode)
707
    {
708
113872
        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
113872
        else if (xmlNameEqual(node, "option"))
726
        {
727
            // single option handling
728
            const std::string name = XML::getProperty(node,
729
170256
                "name", std::string());
730
56752
            if (!name.empty())
731
            {
732

113504
                mOptions[name] = XML::getProperty(node,
733
170256
                    "value", std::string());
734
            }
735
        }  // otherwise ignore
736
    }
737
}
738
739
368
void Configuration::init(const std::string &filename,
740
                         const UseVirtFs useResManager,
741
                         const SkipError skipError)
742
{
743
368
    cleanDefaults();
744
368
    clear();
745
736
    mFilename = filename;
746
368
    mUseResManager = useResManager;
747
748
368
    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
736
        mConfigPath = filename;
762
368
        logger->log1("init 1");
763
1104
        mDirectory = getRealPath(getFileDir(filename));
764
368
        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
736
        skipError);
775
368
    logger->log1("init 2");
776

368
    if (doc.rootNode() == nullptr)
777
    {
778
        logger->log("Couldn't open configuration file: %s", filename.c_str());
779
        return;
780
    }
781
782
368
    XmlNodeConstPtrConst rootNode = doc.rootNode();
783
784


368
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "configuration"))
785
    {
786
        logger->log("Warning: No configuration file (%s)", filename.c_str());
787
        return;
788
    }
789
790
368
    initFromXML(rootNode);
791
}
792
793
void Configuration::reInit()
794
{
795
    XML::Document doc(mFilename, mUseResManager, SkipError_false);
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
358
void ConfigurationObject::writeToXML(XmlTextWriterPtr writer)
814
{
815
1790
    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
43081
        XmlTextWriterStartElement(writer, "option");
826
86162
        XmlTextWriterWriteAttribute(writer, "name", i->first.c_str());
827
86162
        XmlTextWriterWriteAttribute(writer, "value", i->second.c_str());
828
43081
        XmlTextWriterEndElement(writer);
829
    }
830
831
512
    for (std::map<std::string, ConfigurationList>::const_iterator
832
1790
         it = mContainerOptions.begin(), it_fend = mContainerOptions.end();
833
         it != it_fend; ++ it)
834
    {
835
308
        const char *const name = it->first.c_str();
836
837
154
        XmlTextWriterStartElement(writer, "list");
838
154
        XmlTextWriterWriteAttribute(writer, "name", name);
839
840
        // recurse on all elements
841
616
        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
154
        XmlTextWriterEndElement(writer);
850
    }
851
358
}
852
853
void Configuration::writeUpdated()
854
{
855
    if (mUpdated)
856
        write();
857
}
858
859
612
void Configuration::write()
860
{
861
    BLOCK_START("Configuration::write")
862
1224
    if (mConfigPath.empty())
863
    {
864
        BLOCK_END("Configuration::write")
865
        return;
866
    }
867
868
358
    mUpdated = false;
869
    // Do not attempt to write to file that cannot be opened for writing
870
716
    FILE *const testFile = fopen(mConfigPath.c_str(), "w");
871
358
    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
358
    fclose(testFile);
879
880
716
    XmlTextWriterPtr writer = XmlNewTextWriterFilename(
881
        mConfigPath.c_str(), 0);
882
883
358
    if (writer == nullptr)
884
    {
885
        logger->log1("Configuration::write() error while creating writer");
886
        BLOCK_END("Configuration::write")
887
        return;
888
    }
889
890
358
    logger->log1("Configuration::write() writing configuration...");
891
892
358
    XmlTextWriterSetIndent(writer, 1);
893
358
    XmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr);
894
//    xmlTextWriterStartDocument(writer, nullptr, "utf8", nullptr);
895
358
    XmlTextWriterStartRootElement(writer, "configuration");
896
897
358
    writeToXML(writer);
898
899
358
    XmlTextWriterEndDocument(writer);
900
    XmlSaveTextWriterFilename(writer,
901
        mConfigPath.c_str());
902
358
    XmlFreeTextWriter(writer);
903
    BLOCK_END("Configuration::write")
904
}
905
906
2817
void Configuration::addListener(const std::string &key,
907
                                ConfigListener *const listener)
908
{
909
5634
    mListenerMap[key].push_front(listener);
910
2817
}
911
912
470
void Configuration::removeListener(const std::string &key,
913
                                   ConfigListener *const listener)
914
{
915
470
    mListenerMap[key].remove(listener);
916
470
}
917
918
#ifdef ENABLE_CHECKS
919
void Configuration::checkListeners(ConfigListener *const listener,
920
                                   const char *const file,
921
                                   const unsigned line)
922
{
923
    FOR_EACH (ListenerMapIterator, it, mListenerMap)
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
939
1099
void Configuration::removeListeners(ConfigListener *const listener)
940
{
941
3297
    FOR_EACH (ListenerMapIterator, it, mListenerMap)
942
29071
        (it->second).remove(listener);
943
1099
}
944
945
204
void Configuration::removeOldKeys()
946
{
947

1428
    if (mOptions.find(unusedKeys[0]) != mOptions.end() ||
948

1428
        mOptions.find(unusedKeys[1]) != mOptions.end() ||
949
816
        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

207
}