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
109878
    mOptions[key] = value;
231
}
232
233
1002
void ConfigurationObject::deleteKey(const std::string &key)
234
{
235
2004
    mOptions.erase(key);
236
1002
}
237
238
54935
void Configuration::setValue(const std::string &key,
239
                             const std::string &value)
240
{
241
109870
    ConfigurationObject::setValue(key, value);
242
54935
    mUpdated = true;
243
244
    // Notify listeners
245
109870
    const ListenerMapIterator list = mListenerMap.find(key);
246
109870
    if (list != mListenerMap.end())
247
    {
248
1132
        Listeners listeners = list->second;
249
1698
        FOR_EACH (ListenerIterator, i, listeners)
250
5204
            (*i)->optionChanged(key);
251
    }
252
54935
}
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
19220
std::string ConfigurationObject::getValue(const std::string &key,
269
                                          const std::string &deflt) const
270
{
271
    GETLOG();
272
38440
    const Options::const_iterator iter = mOptions.find(key);
273
72693
    return ((iter != mOptions.end()) ? iter->second : deflt);
274
}
275
276
16130
int ConfigurationObject::getValue(const std::string &key,
277
                                  const int deflt) const
278
{
279
    GETLOG();
280
32260
    const Options::const_iterator iter = mOptions.find(key);
281
79003
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
282
}
283
284
15960
int ConfigurationObject::getValueInt(const std::string &key,
285
                                     const int deflt) const
286
{
287
    GETLOG();
288
31920
    const Options::const_iterator iter = mOptions.find(key);
289
79251
    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
768
void ConfigurationObject::deleteList(const std::string &name)
320
{
321
    for (ConfigurationList::const_iterator
322
2304
         it = mContainerOptions[name].begin();
323
1536
         it != mContainerOptions[name].end(); ++it)
324
    {
325
        delete *it;
326
    }
327
328
1536
    mContainerOptions[name].clear();
329
768
}
330
331
2582
void ConfigurationObject::clear()
332
{
333
    for (std::map<std::string, ConfigurationList>::const_iterator
334
7746
         it = mContainerOptions.begin();
335
5932
         it != mContainerOptions.end(); ++it)
336
    {
337
384
        deleteList(it->first);
338
    }
339
5164
    mOptions.clear();
340
5164
    mContainerOptions.clear();
341
2582
}
342
343
394
ConfigurationObject::ConfigurationObject() :
344
    mOptions(),
345
#ifdef DEBUG_CONFIG
346
    mContainerOptions(),
347
    mLogKeys(false),
348
    mIsMain(false)
349
#else  // DEBUG_CONFIG
350
351
1182
    mContainerOptions()
352
#endif  // DEBUG_CONFIG
353
{
354
384
}
355
356
1960
ConfigurationObject::~ConfigurationObject()
357
{
358
394
    clear();
359
778
}
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
2778
void Configuration::cleanDefaults()
378
{
379
8334
    for (DefaultsData::const_iterator iter = mDefaultsData.begin();
380
828160
         iter != mDefaultsData.end();
381
         ++iter)
382
    {
383
411302
        delete iter->second;
384
    }
385
5556
    mDefaultsData.clear();
386
2778
}
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
7175
std::string Configuration::getStringValue(const std::string &key) const
488
{
489
    GETLOG();
490
7175
    std::string defaultValue;
491
14350
    const Options::const_iterator iter = mOptions.find(key);
492
14350
    if (iter == mOptions.end())
493
    {
494
        const DefaultsData::const_iterator
495
14210
            itdef = mDefaultsData.find(key);
496
497

21313
        if (itdef != mDefaultsData.end() &&
498
7103
            (itdef->second != nullptr))
499
        {
500
7103
            const VariableData *const data = itdef->second;
501
            const VariableData::DataType type = static_cast<
502
14206
                VariableData::DataType>(data->getType());
503
7103
            if (type == VariableData::DATA_STRING)
504
            {
505
                defaultValue = (static_cast<const StringData*>(
506
6915
                    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
7173
    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
4774
bool Configuration::getBoolValue(const std::string &key) const
597
{
598
    GETLOG();
599
4774
    bool defaultValue = false;
600
9548
    const Options::const_iterator iter = mOptions.find(key);
601
9548
    if (iter == mOptions.end())
602
    {
603
        const DefaultsData::const_iterator itdef
604
9490
            = mDefaultsData.find(key);
605
606

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

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

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

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

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

390
}