GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/configuration.cpp Lines: 257 319 80.6 %
Date: 2017-11-29 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-2017  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
101826
    mOptions[key] = value;
231
}
232
233
1002
void ConfigurationObject::deleteKey(const std::string &key)
234
{
235
2004
    mOptions.erase(key);
236
1002
}
237
238
50909
void Configuration::setValue(const std::string &key,
239
                             const std::string &value)
240
{
241
101818
    ConfigurationObject::setValue(key, value);
242
50909
    mUpdated = true;
243
244
    // Notify listeners
245
101818
    const ListenerMapIterator list = mListenerMap.find(key);
246
101818
    if (list != mListenerMap.end())
247
    {
248
1088
        Listeners listeners = list->second;
249
1632
        FOR_EACH (ListenerIterator, i, listeners)
250
4918
            (*i)->optionChanged(key);
251
    }
252
50909
}
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
17922
std::string ConfigurationObject::getValue(const std::string &key,
269
                                          const std::string &deflt) const
270
{
271
    GETLOG();
272
35844
    const Options::const_iterator iter = mOptions.find(key);
273
67589
    return ((iter != mOptions.end()) ? iter->second : deflt);
274
}
275
276
14876
int ConfigurationObject::getValue(const std::string &key,
277
                                  const int deflt) const
278
{
279
    GETLOG();
280
29752
    const Options::const_iterator iter = mOptions.find(key);
281
72733
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
282
}
283
284
14706
int ConfigurationObject::getValueInt(const std::string &key,
285
                                     const int deflt) const
286
{
287
    GETLOG();
288
29412
    const Options::const_iterator iter = mOptions.find(key);
289
72981
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
290
}
291
292
516
bool ConfigurationObject::getValueBool(const std::string &key,
293
                                       const bool deflt) const
294
{
295
    GETLOG();
296
1032
    const Options::const_iterator iter = mOptions.find(key);
297
1032
    if (iter != mOptions.end())
298
234
        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
724
void ConfigurationObject::deleteList(const std::string &name)
320
{
321
    for (ConfigurationList::const_iterator
322
2172
         it = mContainerOptions[name].begin();
323
1448
         it != mContainerOptions[name].end(); ++it)
324
    {
325
        delete *it;
326
    }
327
328
1448
    mContainerOptions[name].clear();
329
724
}
330
331
2472
void ConfigurationObject::clear()
332
{
333
    for (std::map<std::string, ConfigurationList>::const_iterator
334
7416
         it = mContainerOptions.begin();
335
5668
         it != mContainerOptions.end(); ++it)
336
    {
337
362
        deleteList(it->first);
338
    }
339
4944
    mOptions.clear();
340
4944
    mContainerOptions.clear();
341
2472
}
342
343
372
ConfigurationObject::ConfigurationObject() :
344
    mOptions(),
345
#ifdef DEBUG_CONFIG
346
    mContainerOptions(),
347
    mLogKeys(false),
348
    mIsMain(false)
349
#else  // DEBUG_CONFIG
350
351
1116
    mContainerOptions()
352
#endif  // DEBUG_CONFIG
353
{
354
362
}
355
356
1850
ConfigurationObject::~ConfigurationObject()
357
{
358
372
    clear();
359
734
}
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
}
376
377
2690
void Configuration::cleanDefaults()
378
{
379
8070
    for (DefaultsData::const_iterator iter = mDefaultsData.begin();
380
801584
         iter != mDefaultsData.end();
381
         ++iter)
382
    {
383
398102
        delete iter->second;
384
    }
385
5380
    mDefaultsData.clear();
386
2690
}
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
2504
int Configuration::getIntValue(const std::string &key) const
404
{
405
    GETLOG();
406
2504
    int defaultValue = 0;
407
5008
    const Options::const_iterator iter = mOptions.find(key);
408
5008
    if (iter == mOptions.end())
409
    {
410
        const DefaultsData::const_iterator itdef
411
4426
            = mDefaultsData.find(key);
412
413

6637
        if (itdef != mDefaultsData.end() && (itdef->second != nullptr))
414
        {
415
2211
            const VariableData *const data = itdef->second;
416
            const VariableData::DataType type = static_cast<
417
2211
                VariableData::DataType>(data->getType());
418
2211
            if (type == VariableData::DATA_INT)
419
            {
420
2203
                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
873
        defaultValue = atoi(iter->second.c_str());
452
    }
453
2502
    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
7563
std::string Configuration::getStringValue(const std::string &key) const
488
{
489
    GETLOG();
490
7563
    std::string defaultValue;
491
15126
    const Options::const_iterator iter = mOptions.find(key);
492
15126
    if (iter == mOptions.end())
493
    {
494
        const DefaultsData::const_iterator
495
14986
            itdef = mDefaultsData.find(key);
496
497

22477
        if (itdef != mDefaultsData.end() &&
498
7491
            (itdef->second != nullptr))
499
        {
500
7491
            const VariableData *const data = itdef->second;
501
            const VariableData::DataType type = static_cast<
502
14982
                VariableData::DataType>(data->getType());
503
7491
            if (type == VariableData::DATA_STRING)
504
            {
505
                defaultValue = (static_cast<const StringData*>(
506
7299
                    data))->getData();
507
            }
508
192
            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
184
            else if (type == VariableData::DATA_INT)
516
            {
517
356
                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
7561
    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
4770
bool Configuration::getBoolValue(const std::string &key) const
597
{
598
    GETLOG();
599
4770
    bool defaultValue = false;
600
9540
    const Options::const_iterator iter = mOptions.find(key);
601
9540
    if (iter == mOptions.end())
602
    {
603
        const DefaultsData::const_iterator itdef
604
9482
            = mDefaultsData.find(key);
605
606

14221
        if (itdef != mDefaultsData.end() &&
607
4739
            (itdef->second != nullptr))
608
        {
609
4739
            const VariableData *const data = itdef->second;
610
            const VariableData::DataType type = static_cast<
611
4739
                VariableData::DataType>(data->getType());
612
4739
            if (type == VariableData::DATA_BOOL)
613
            {
614
4729
                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
4739
            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
4768
    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
688
void ConfigurationObject::initFromXML(XmlNodeConstPtrConst parentNode)
699
{
700
688
    clear();
701
702
688
    if (parentNode == nullptr)
703
        return;
704
705
289038
    for_each_xml_child_node(node, parentNode)
706
    {
707
288350
        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
288350
        else if (xmlNameEqual(node, "option"))
725
        {
726
            // single option handling
727
            const std::string name = XML::getProperty(node,
728
431493
                "name", std::string());
729
143831
            if (!name.empty())
730
            {
731

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

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

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

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

368
}