GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/configuration.cpp Lines: 261 325 80.3 %
Date: 2018-11-12 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-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
1
Configuration config;              // XML file configuration reader
52
1
Configuration serverConfig;        // XML file server configuration reader
53
1
Configuration features;            // XML file features
54
1
Configuration branding;            // XML branding information reader
55
1
Configuration paths;               // XML default paths information reader
56
57
3
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



















































































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

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

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

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


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

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

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

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

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

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


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

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

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

207
}