GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/configuration.cpp Lines: 258 320 80.6 %
Date: 2018-05-19 03:07:18 Branches: 304 604 50.3 %

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-2018  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "configuration.h"
24
25
#include "variabledata.h"
26
27
#include "fs/files.h"
28
#include "fs/paths.h"
29
30
#include "fs/virtfs/fs.h"
31
32
#include "listeners/configlistener.h"
33
34
#include "utils/cast.h"
35
#include "utils/checkutils.h"
36
#include "utils/foreach.h"
37
#ifdef DEBUG_CONFIG
38
#include "utils/stringmap.h"
39
#endif  // DEBUG_CONFIG
40
41
#include "debug.h"
42
43
#ifdef DEBUG_CONFIG
44
StringIntMap optionsCount;
45
#define GETLOG() if (logger) {logger->log("config get: " + key); \
46
    if (mIsMain) optionsCount[key] = 1; }
47
#else  // DEBUG_CONFIG
48
#define GETLOG()
49
#endif  // DEBUG_CONFIG
50
51
2
Configuration config;              // XML file configuration reader
52
2
Configuration serverConfig;        // XML file server configuration reader
53
2
Configuration features;            // XML file features
54
2
Configuration branding;            // XML branding information reader
55
2
Configuration paths;               // XML default paths information reader
56
57
6
const std::string unusedKeys[] =
58
{
59
    "BotCheckerWindowSticky",
60
    "afkmessage",
61
    "BotCheckerWindowVisible",
62
    "BotCheckerWindowWinX",
63
    "BotCheckerWindowWinY",
64
    "hideShield",
65
    "AttackRange",
66
    "emoteshortcut0",
67
    "screenshotDirectory2",
68
    "AttackRangeBorder",
69
    "AttackRangeBorderDelay",
70
    "AttackRangeBorderGradient",
71
    "AttackRangeDelay",
72
    "AttackRangeGradient",
73
    "Being",
74
    "BeingDelay",
75
    "BeingGradient",
76
    "BeingPopupSkin",
77
    "BotCheckerWindowSkin",
78
    "BuySellSkin",
79
    "BuySkin",
80
    "ChatSkin",
81
    "CollisionHighlight",
82
    "CollisionHighlightDelay",
83
    "CollisionHighlightGradient",
84
    "ColorCross",
85
    "ColorCrossDelay",
86
    "ColorCrossGradient",
87
    "ColorExperience",
88
    "ColorExperienceGradient",
89
    "ColorPickup",
90
    "ColorPickupGradient",
91
    "DebugSkin",
92
    "DropShortcutSkin",
93
    "EmoteShortcutSkin",
94
    "EquipmentSkin",
95
    "ExpInfo",
96
    "ExpInfoDelay",
97
    "ExpInfoGradient",
98
    "Experience",
99
    "ExperienceGradient",
100
    "GM",
101
    "GMDelay",
102
    "GMGradient",
103
    "Guild",
104
    "GuildDelay",
105
    "GuildGradient",
106
    "GuildSkin",
107
    "HelpSkin",
108
    "Hit CriticalDelay",
109
    "Hit CriticalGradient",
110
    "Hit Monster Player",
111
    "Hit Monster PlayerGradient",
112
    "Hit Player Monster",
113
    "Hit Player MonsterGradient",
114
    "HitCriticalDelay",
115
    "HitCriticalGradient",
116
    "HitLocalPlayerCriticalDelay",
117
    "HitLocalPlayerCriticalGradient",
118
    "HitLocalPlayerMiss",
119
    "HitLocalPlayerMissDelay",
120
    "HitLocalPlayerMissGradient",
121
    "HitLocalPlayerMonster",
122
    "HitLocalPlayerMonsterDelay",
123
    "HitLocalPlayerMonsterGradient",
124
    "HitMonsterPlayer",
125
    "HitMonsterPlayerDelay",
126
    "HitMonsterPlayerGradient",
127
    "HitPlayerMonster",
128
    "HitPlayerMonsterDelay",
129
    "HitPlayerMonsterGradient",
130
    "HomePlace",
131
    "HomePlaceBorder",
132
    "HomePlaceBorderDelay",
133
    "HomePlaceBorderGradient",
134
    "HomePlaceDelay",
135
    "HomePlaceGradient",
136
    "InventorySkin",
137
    "ItemPopupSkin",
138
    "ItemShortcutSkin",
139
    "Kill statsSkin",
140
    "MiniStatusSkin",
141
    "MinimapSkin",
142
    "Miss",
143
    "MissDelay",
144
    "MissGradient",
145
    "Monster",
146
    "MonsterAttackRange",
147
    "MonsterAttackRangeDelay",
148
    "MonsterAttackRangeGradient",
149
    "MonsterDelay",
150
    "MonsterGradient",
151
    "NPC",
152
    "NPCDelay",
153
    "NPCGradient",
154
    "NpcTextSkin",
155
    "OutfitsSkin",
156
    "Particle",
157
    "ParticleDelay",
158
    "ParticleGradient",
159
    "PartyDelay",
160
    "PartyGradient",
161
    "PartySkin",
162
    "Personal ShopSkin",
163
    "Pickup",
164
    "PickupGradient",
165
    "Player",
166
    "PlayerDelay",
167
    "PlayerGradient",
168
    "PopupMenuSkin",
169
    "PortalHighlight",
170
    "PortalHighlightDelay",
171
    "PortalHighlightGradient",
172
    "RecorderSkin",
173
    "RecorderWinX",
174
    "RecorderWinY",
175
    "RoadPoint",
176
    "RoadPointDelay",
177
    "RoadPointGradient",
178
    "Self",
179
    "SelfDelay",
180
    "SelfGradient",
181
    "SellSkin",
182
    "ServerDialogSkin",
183
    "ShopSkin",
184
    "SkillsSkin",
185
    "SocialCreatePopupSkin",
186
    "SocialSkin",
187
    "SpecialsSkin",
188
    "SpeechSkin",
189
    "SpellPopupSkin",
190
    "SpellShortcutSkin",
191
    "StatusPopupSkin",
192
    "StatusSkin",
193
    "StorageSkin",
194
    "TextCommandEditorSkin",
195
    "TextPopupSkin",
196
    "TradeSkin",
197
    "WhoIsOnlineSkin",
198
    "emoteshortcut1",
199
    "emoteshortcut2",
200
    "emoteshortcut3",
201
    "emoteshortcut4",
202
    "emoteshortcut5",
203
    "emoteshortcut6",
204
    "emoteshortcut7",
205
    "emoteshortcut8",
206
    "emoteshortcut9",
207
    "emoteshortcut10",
208
    "emoteshortcut11",
209
    "emoteshortcut12",
210
    "emoteshortcut13",
211
    "fastOpenGL",
212
    "keyAutoCompleteChat",
213
    "keyDeActivateChat",
214
    "keyTargetClosest",
215
    "keyWindowParty",
216
    "mapalpha",
217
    "port",
218
    "shopBuyList",
219
    "shopSellList",
220
    "OutfitAwayIndex",
221
    "playerHomes",
222
    "remember",
223
    "screenshotDirectory",
224
    ""
225



















































































666
};
226
227
void ConfigurationObject::setValue(const std::string &key,
228
                                   const std::string &value)
229
{
230
125350
    mOptions[key] = value;
231
}
232
233
1002
void ConfigurationObject::deleteKey(const std::string &key)
234
{
235
2004
    mOptions.erase(key);
236
1002
}
237
238
62671
void Configuration::setValue(const std::string &key,
239
                             const std::string &value)
240
{
241
125342
    ConfigurationObject::setValue(key, value);
242
62671
    mUpdated = true;
243
244
    // Notify listeners
245
125342
    const ListenerMapIterator list = mListenerMap.find(key);
246
125342
    if (list != mListenerMap.end())
247
    {
248
1220
        Listeners listeners = list->second;
249
1830
        FOR_EACH (ListenerIterator, i, listeners)
250
5750
            (*i)->optionChanged(key);
251
    }
252
62671
}
253
254
2
void Configuration::incValue(const std::string &key)
255
{
256
    GETLOG();
257
6
    const Options::const_iterator iter = mOptions.find(key);
258
6
    setValue(key, (iter != mOptions.end())
259
6
        ? atoi(iter->second.c_str()) + 1 : 1);
260
2
}
261
262
4
void Configuration::setSilent(const std::string &key,
263
                              const std::string &value)
264
{
265
8
    ConfigurationObject::setValue(key, value);
266
4
}
267
268
21728
std::string ConfigurationObject::getValue(const std::string &key,
269
                                          const std::string &deflt) const
270
{
271
    GETLOG();
272
43456
    const Options::const_iterator iter = mOptions.find(key);
273
82527
    return ((iter != mOptions.end()) ? iter->second : deflt);
274
}
275
276
18528
int ConfigurationObject::getValue(const std::string &key,
277
                                  const int deflt) const
278
{
279
    GETLOG();
280
37056
    const Options::const_iterator iter = mOptions.find(key);
281
90981
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
282
}
283
284
18362
int ConfigurationObject::getValueInt(const std::string &key,
285
                                     const int deflt) const
286
{
287
    GETLOG();
288
36724
    const Options::const_iterator iter = mOptions.find(key);
289
91249
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
290
}
291
292
522
bool ConfigurationObject::getValueBool(const std::string &key,
293
                                       const bool deflt) const
294
{
295
    GETLOG();
296
1044
    const Options::const_iterator iter = mOptions.find(key);
297
1044
    if (iter != mOptions.end())
298
240
        return atoi(iter->second.c_str()) != 0 ? true : false;
299
    return deflt;
300
}
301
302
16
unsigned ConfigurationObject::getValue(const std::string &key,
303
                                       const unsigned deflt) const
304
{
305
    GETLOG();
306
32
    const Options::const_iterator iter = mOptions.find(key);
307
42
    return (iter != mOptions.end()) ? CAST_U32(
308
46
            atol(iter->second.c_str())) : deflt;
309
}
310
311
12
double ConfigurationObject::getValue(const std::string &key,
312
                                     const double deflt) const
313
{
314
    GETLOG();
315
24
    const Options::const_iterator iter = mOptions.find(key);
316
54
    return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt;
317
}
318
319
856
void ConfigurationObject::deleteList(const std::string &name)
320
{
321
    for (ConfigurationList::const_iterator
322
2568
         it = mContainerOptions[name].begin();
323
1712
         it != mContainerOptions[name].end(); ++it)
324
    {
325
        delete *it;
326
    }
327
328
1712
    mContainerOptions[name].clear();
329
856
}
330
331
2806
void ConfigurationObject::clear()
332
{
333
    for (std::map<std::string, ConfigurationList>::const_iterator
334
8418
         it = mContainerOptions.begin();
335
6468
         it != mContainerOptions.end(); ++it)
336
    {
337
428
        deleteList(it->first);
338
    }
339
5612
    mOptions.clear();
340
5612
    mContainerOptions.clear();
341
2806
}
342
343
438
ConfigurationObject::ConfigurationObject() :
344
    mOptions(),
345
#ifdef DEBUG_CONFIG
346
    mContainerOptions(),
347
    mLogKeys(false),
348
    mIsMain(false)
349
#else  // DEBUG_CONFIG
350
351
1314
    mContainerOptions()
352
#endif  // DEBUG_CONFIG
353
{
354
428
}
355
356
2180
ConfigurationObject::~ConfigurationObject()
357
{
358
438
    clear();
359
866
}
360
361
10
Configuration::Configuration() :
362
    ConfigurationObject(),
363
    mListenerMap(),
364
    mConfigPath(),
365
    mDefaultsData(),
366
    mDirectory(),
367
    mFilename(),
368
    mUseResManager(UseVirtFs_false),
369
70
    mUpdated(false)
370
{
371
#ifdef DEBUG_CONFIG
372
    mLogKeys = false;
373
    mIsMain = false;
374
#endif  // DEBUG_CONFIG
375
10
}
376
377
2962
void Configuration::cleanDefaults()
378
{
379
8886
    for (DefaultsData::const_iterator iter = mDefaultsData.begin();
380
889912
         iter != mDefaultsData.end();
381
         ++iter)
382
    {
383
441994
        delete iter->second;
384
    }
385
5924
    mDefaultsData.clear();
386
2962
}
387
388
70
Configuration::~Configuration()
389
{
390
10
    cleanDefaults();
391
10
}
392
393
void Configuration::unload()
394
{
395
    cleanDefaults();
396
    mConfigPath.clear();
397
    mDirectory.clear();
398
    mFilename.clear();
399
    mUseResManager = UseVirtFs_false;
400
    ConfigurationObject::clear();
401
}
402
403
2058
int Configuration::getIntValue(const std::string &key) const
404
{
405
    GETLOG();
406
2058
    int defaultValue = 0;
407
4116
    const Options::const_iterator iter = mOptions.find(key);
408
4116
    if (iter == mOptions.end())
409
    {
410
        const DefaultsData::const_iterator itdef
411
3526
            = mDefaultsData.find(key);
412
413

5287
        if (itdef != mDefaultsData.end() && (itdef->second != nullptr))
414
        {
415
1761
            const VariableData *const data = itdef->second;
416
            const VariableData::DataType type = static_cast<
417
1761
                VariableData::DataType>(data->getType());
418
1761
            if (type == VariableData::DATA_INT)
419
            {
420
1753
                defaultValue = (static_cast<const IntData*>(
421
                    data))->getData();
422
            }
423
8
            else if (type == VariableData::DATA_STRING)
424
            {
425
4
                defaultValue = atoi((static_cast<const StringData*>(
426
2
                    data))->getData().c_str());
427
            }
428
6
            else if (type == VariableData::DATA_BOOL)
429
            {
430
4
                if ((static_cast<const BoolData*>(data))->getData())
431
                    defaultValue = 1;
432
                else
433
2
                    defaultValue = 0;
434
            }
435
2
            else if (type == VariableData::DATA_FLOAT)
436
            {
437
2
                defaultValue = CAST_S32(
438
2
                    (static_cast<const FloatData*>(data))->getData());
439
            }
440
        }
441
        else
442
        {
443
10
            reportAlways(
444
                "%s: No integer value in registry for key %s",
445
                mConfigPath.c_str(),
446
                key.c_str());
447
        }
448
    }
449
    else
450
    {
451
885
        defaultValue = atoi(iter->second.c_str());
452
    }
453
2056
    return defaultValue;
454
}
455
456
2
int Configuration::resetIntValue(const std::string &key)
457
{
458
    GETLOG();
459
2
    int defaultValue = 0;
460
6
    const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
461
4
    if (itdef == mDefaultsData.end())
462
    {
463
        reportAlways("%s: No integer value in registry for key %s",
464
            mConfigPath.c_str(),
465
            key.c_str());
466
    }
467
    else
468
    {
469
2
        const VariableData *const data = itdef->second;
470

4
        if (data != nullptr &&
471
2
            data->getType() == VariableData::DATA_INT)
472
        {
473
2
            defaultValue = (static_cast<const IntData*>(
474
                data))->getData();
475
        }
476
        else
477
        {
478
            reportAlways("%s: No integer value in registry for key %s",
479
                mConfigPath.c_str(),
480
                key.c_str());
481
        }
482
    }
483
2
    setValue(key, defaultValue);
484
2
    return defaultValue;
485
}
486
487
7473
std::string Configuration::getStringValue(const std::string &key) const
488
{
489
    GETLOG();
490
7473
    std::string defaultValue;
491
14946
    const Options::const_iterator iter = mOptions.find(key);
492
14946
    if (iter == mOptions.end())
493
    {
494
        const DefaultsData::const_iterator
495
14806
            itdef = mDefaultsData.find(key);
496
497

22207
        if (itdef != mDefaultsData.end() &&
498
7401
            (itdef->second != nullptr))
499
        {
500
7401
            const VariableData *const data = itdef->second;
501
            const VariableData::DataType type = static_cast<
502
14802
                VariableData::DataType>(data->getType());
503
7401
            if (type == VariableData::DATA_STRING)
504
            {
505
                defaultValue = (static_cast<const StringData*>(
506
7213
                    data))->getData();
507
            }
508
188
            else if (type == VariableData::DATA_BOOL)
509
            {
510
8
                if ((static_cast<const BoolData*>(data))->getData())
511
                    defaultValue = "1";
512
                else
513
                    defaultValue = "0";
514
            }
515
180
            else if (type == VariableData::DATA_INT)
516
            {
517
348
                defaultValue = toString((static_cast<const IntData*>(
518
                    data))->getData());
519
            }
520
6
            else if (type == VariableData::DATA_FLOAT)
521
            {
522
12
                defaultValue = toString((static_cast<const FloatData*>(
523
                    data))->getData());
524
            }
525
        }
526
        else
527
        {
528


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

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

14365
        if (itdef != mDefaultsData.end() &&
607
4787
            (itdef->second != nullptr))
608
        {
609
4787
            const VariableData *const data = itdef->second;
610
            const VariableData::DataType type = static_cast<
611
4787
                VariableData::DataType>(data->getType());
612
4787
            if (type == VariableData::DATA_BOOL)
613
            {
614
4777
                defaultValue = (static_cast<const BoolData*>(
615
                    data))->getData();
616
            }
617
10
            else if (type == VariableData::DATA_INT)
618
            {
619
6
                if ((static_cast<const IntData*>(data))->getData() != 0)
620
                    defaultValue = true;
621
                else
622
4
                    defaultValue = false;
623
            }
624
4
            else if (type == VariableData::DATA_STRING)
625
            {
626
2
                if ((static_cast<const StringData*>(
627
4
                    data))->getData() != "0")
628
                {
629
                    defaultValue = true;
630
                }
631
                else
632
                {
633
                    defaultValue = false;
634
                }
635
            }
636
4787
            if (type == VariableData::DATA_FLOAT)
637
            {
638
2
                if (CAST_S32((static_cast<const FloatData*>(
639
2
                    data))->getData()) != 0)
640
                {
641
                    defaultValue = true;
642
                }
643
                else
644
                {
645
2
                    defaultValue = false;
646
                }
647
            }
648
        }
649
        else
650
        {
651
10
            reportAlways(
652
                "%s: No boolean value in registry for key %s",
653
                mConfigPath.c_str(),
654
                key.c_str());
655
        }
656
    }
657
    else
658
    {
659
29
        defaultValue = getBoolFromString(iter->second);
660
    }
661
662
4816
    return defaultValue;
663
}
664
665
4
bool Configuration::resetBoolValue(const std::string &key)
666
{
667
    GETLOG();
668
4
    bool defaultValue = false;
669
12
    const DefaultsData::const_iterator itdef = mDefaultsData.find(key);
670
671
8
    if (itdef == mDefaultsData.end())
672
    {
673
        reportAlways("%s: No boolean value in registry for key %s",
674
            mConfigPath.c_str(),
675
            key.c_str());
676
    }
677
    else
678
    {
679
4
        const VariableData *const data = itdef->second;
680

8
        if (data != nullptr &&
681
4
            data->getType() == VariableData::DATA_BOOL)
682
        {
683
4
            defaultValue = (static_cast<const BoolData*>(data))->getData();
684
        }
685
        else
686
        {
687
            reportAlways("%s: No boolean value in registry for key %s",
688
                mConfigPath.c_str(),
689
                key.c_str());
690
        }
691
    }
692
693
8
    setValue(key, defaultValue);
694
4
    return defaultValue;
695
}
696
697
698
756
void ConfigurationObject::initFromXML(XmlNodeConstPtrConst parentNode)
699
{
700
756
    clear();
701
702
756
    if (parentNode == nullptr)
703
        return;
704
705
327310
    for_each_xml_child_node(node, parentNode)
706
    {
707
326554
        if (xmlNameEqual(node, "list"))
708
        {
709
            // list option handling
710
            const std::string name = XML::getProperty(node,
711
                "name", std::string());
712
713
            for_each_xml_child_node(subnode, node)
714
            {
715
                if (xmlNameEqual(subnode, name.c_str()) &&
716
                    xmlTypeEqual(subnode, XML_ELEMENT_NODE))
717
                {
718
                    ConfigurationObject *const cobj = new ConfigurationObject;
719
                    cobj->initFromXML(subnode);  // recurse
720
                    mContainerOptions[name].push_back(cobj);
721
                }
722
            }
723
        }
724
326554
        else if (xmlNameEqual(node, "option"))
725
        {
726
            // single option handling
727
            const std::string name = XML::getProperty(node,
728
488697
                "name", std::string());
729
162899
            if (!name.empty())
730
            {
731

325798
                mOptions[name] = XML::getProperty(node,
732
325798
                    "value", std::string());
733
            }
734
        }  // otherwise ignore
735
    }
736
}
737
738
756
void Configuration::init(const std::string &filename,
739
                         const UseVirtFs useResManager,
740
                         const SkipError skipError)
741
{
742
756
    cleanDefaults();
743
756
    clear();
744
1512
    mFilename = filename;
745
756
    mUseResManager = useResManager;
746
747
756
    if (useResManager == UseVirtFs_true)
748
    {
749
        mConfigPath = "virtfs://" + filename;
750
        mDirectory.clear();
751
        if (VirtFs::exists(filename) == false)
752
        {
753
            logger->log("Warning: No configuration file (%s)",
754
                filename.c_str());
755
            return;
756
        }
757
    }
758
    else
759
    {
760
1512
        mConfigPath = filename;
761
756
        logger->log1("init 1");
762
2268
        mDirectory = getRealPath(getFileDir(filename));
763
756
        if (Files::existsLocal(filename) == false)
764
        {
765
            logger->log("Warning: No configuration file (%s)",
766
                filename.c_str());
767
            return;
768
        }
769
    }
770
771
    XML::Document doc(filename,
772
        useResManager,
773
1512
        skipError);
774
756
    logger->log1("init 2");
775

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

756
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "configuration"))
784
    {
785
        logger->log("Warning: No configuration file (%s)", filename.c_str());
786
        return;
787
    }
788
789
756
    initFromXML(rootNode);
790
}
791
792
void Configuration::reInit()
793
{
794
    XML::Document doc(mFilename, mUseResManager, SkipError_false);
795
    if (doc.rootNode() == nullptr)
796
    {
797
        logger->log("Couldn't open configuration file: %s", mFilename.c_str());
798
        return;
799
    }
800
801
    XmlNodeConstPtrConst rootNode = doc.rootNode();
802
803
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "configuration"))
804
    {
805
        logger->log("Warning: No configuration file (%s)", mFilename.c_str());
806
        return;
807
    }
808
809
    initFromXML(rootNode);
810
}
811
812
736
void ConfigurationObject::writeToXML(XmlTextWriterPtr writer)
813
{
814
3680
    FOR_EACH (Options::const_iterator, i, mOptions)
815
    {
816
#ifdef DEBUG_CONFIG
817
        if (mLogKeys)
818
        {
819
            if (optionsCount.find(i->first) == optionsCount.end())
820
                logger->log("unused configuration option: " + i->first);
821
        }
822
#endif  // DEBUG_CONFIG
823
824
119811
        XmlTextWriterStartElement(writer, "option");
825
239622
        XmlTextWriterWriteAttribute(writer, "name", i->first.c_str());
826
239622
        XmlTextWriterWriteAttribute(writer, "value", i->second.c_str());
827
119811
        XmlTextWriterEndElement(writer);
828
    }
829
830
    for (std::map<std::string, ConfigurationList>::const_iterator
831
3680
         it = mContainerOptions.begin(), it_fend = mContainerOptions.end();
832
1044
         it != it_fend; ++ it)
833
    {
834
616
        const char *const name = it->first.c_str();
835
836
308
        XmlTextWriterStartElement(writer, "list");
837
308
        XmlTextWriterWriteAttribute(writer, "name", name);
838
839
        // recurse on all elements
840
1232
        FOR_EACH (ConfigurationList::const_iterator, elt_it, it->second)
841
        {
842
            XmlTextWriterStartElement(writer, name);
843
            if (*elt_it != nullptr)
844
                (*elt_it)->writeToXML(writer);
845
            XmlTextWriterEndElement(writer);
846
        }
847
848
308
        XmlTextWriterEndElement(writer);
849
    }
850
736
}
851
852
void Configuration::writeUpdated()
853
{
854
    if (mUpdated)
855
        write();
856
}
857
858
1284
void Configuration::write()
859
{
860
    BLOCK_START("Configuration::write")
861
2568
    if (mConfigPath.empty())
862
    {
863
        BLOCK_END("Configuration::write")
864
        return;
865
    }
866
867
736
    mUpdated = false;
868
    // Do not attempt to write to file that cannot be opened for writing
869
1472
    FILE *const testFile = fopen(mConfigPath.c_str(), "w");
870
736
    if (testFile == nullptr)
871
    {
872
        reportAlways("Configuration::write() couldn't open %s for writing",
873
            mConfigPath.c_str());
874
        BLOCK_END("Configuration::write")
875
        return;
876
    }
877
736
    fclose(testFile);
878
879
1472
    XmlTextWriterPtr writer = XmlNewTextWriterFilename(
880
        mConfigPath.c_str(), 0);
881
882
736
    if (writer == nullptr)
883
    {
884
        logger->log1("Configuration::write() error while creating writer");
885
        BLOCK_END("Configuration::write")
886
        return;
887
    }
888
889
736
    logger->log1("Configuration::write() writing configuration...");
890
891
736
    XmlTextWriterSetIndent(writer, 1);
892
736
    XmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr);
893
//    xmlTextWriterStartDocument(writer, nullptr, "utf8", nullptr);
894
736
    XmlTextWriterStartRootElement(writer, "configuration");
895
896
736
    writeToXML(writer);
897
898
736
    XmlTextWriterEndDocument(writer);
899
    XmlSaveTextWriterFilename(writer,
900
        mConfigPath.c_str());
901
736
    XmlFreeTextWriter(writer);
902
    BLOCK_END("Configuration::write")
903
}
904
905
5462
void Configuration::addListener(const std::string &key,
906
                                ConfigListener *const listener)
907
{
908
10924
    mListenerMap[key].push_front(listener);
909
5462
}
910
911
960
void Configuration::removeListener(const std::string &key,
912
                                   ConfigListener *const listener)
913
{
914
960
    mListenerMap[key].remove(listener);
915
960
}
916
917
#ifdef ENABLE_CHECKS
918
void Configuration::checkListeners(ConfigListener *const listener,
919
                                   const char *const file,
920
                                   const unsigned line)
921
{
922
    FOR_EACH (ListenerMapIterator, it, mListenerMap)
923
    {
924
        Listeners listeners = it->second;
925
        FOR_EACH (ListenerIterator, it2, listeners)
926
        {
927
            if (*it2 == listener)
928
            {
929
                logger->log("detected not cleaned listener: %p, %s:%u",
930
                    static_cast<void*>(listener), file, line);
931
                exit(1);
932
            }
933
        }
934
    }
935
}
936
#endif  // ENABLE_CHECKS
937
938
2276
void Configuration::removeListeners(ConfigListener *const listener)
939
{
940
6828
    FOR_EACH (ListenerMapIterator, it, mListenerMap)
941
59020
        (it->second).remove(listener);
942
2276
}
943
944
428
void Configuration::removeOldKeys()
945
{
946
1712
    if (mOptions.find(unusedKeys[0]) != mOptions.end() ||
947

1712
        mOptions.find(unusedKeys[1]) != mOptions.end() ||
948
1284
        mOptions.find(unusedKeys[2]) != mOptions.end())
949
    {
950
        int f = 0;
951
        while (!unusedKeys[f].empty())
952
        {
953
            deleteKey(unusedKeys[f]);
954
            logger->log("remove unused key: " + unusedKeys[f]);
955
            f ++;
956
        }
957
        for (f = 0; f < 80; f ++)
958
        {
959
            const std::string str = toString(f);
960
            deleteKey("Outfit" + str);
961
            deleteKey("OutfitUnequip" + str);
962
            deleteKey("commandShortcutCmd" + str);
963
            deleteKey("commandShortcutFlags" + str);
964
            deleteKey("commandShortcutSymbol" + str);
965
            deleteKey("drop" + str);
966
            deleteKey("shortcut" + str);
967
        }
968
    }
969

434
}