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

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



















































































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

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

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

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


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

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

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

4
        if (data != nullptr &&
681
2
            data->getType() == VariableData::DATA_BOOL)
682
        {
683
2
            defaultValue = (static_cast<const BoolData*>(data))->getData();
684
        }
685
        else
686
        {
687
            reportAlways("%s: No boolean value in registry for key %s",
688
                mConfigPath.c_str(),
689
                key.c_str());
690
        }
691
    }
692
693
4
    setValue(key, defaultValue);
694
2
    return defaultValue;
695
}
696
697
698
378
void ConfigurationObject::initFromXML(XmlNodeConstPtrConst parentNode)
699
{
700
378
    clear();
701
702
378
    if (parentNode == nullptr)
703
        return;
704
705
117660
    for_each_xml_child_node(node, parentNode)
706
    {
707
117282
        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
117282
        else if (xmlNameEqual(node, "option"))
725
        {
726
            // single option handling
727
            const std::string name = XML::getProperty(node,
728
175356
                "name", std::string());
729
58452
            if (!name.empty())
730
            {
731

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

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


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

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

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

217
}