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

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



















































































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

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

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

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


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

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

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

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

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

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


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

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

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

218
}