GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/colordb.cpp Lines: 11 89 12.4 %
Date: 2021-03-17 Branches: 3 148 2.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2008  Aethyra Development Team
4
 *  Copyright (C) 2011-2019  The ManaPlus Developers
5
 *  Copyright (C) 2019-2021  Andrei Karas
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 "resources/db/colordb.h"
24
25
#include "configuration.h"
26
27
#include "utils/cast.h"
28
#include "utils/checkutils.h"
29
30
#include "resources/beingcommon.h"
31
32
#include "debug.h"
33
34
namespace
35
{
36
    int mHairColorsSize = 0;
37
    bool mLoaded = false;
38
3
    std::string mFail("#ffffff");
39
1
    ColorDB::ColorLists mColorLists;
40
}  // namespace
41
42
void ColorDB::load()
43
{
44
    if (mLoaded)
45
        unload();
46
47
    logger->log1("Initializing color database...");
48
49
    std::map<ItemColor, ItemColorData> colors;
50
    ColorListsIterator it = mColorLists.find("hair");
51
    if (it != mColorLists.end())
52
        colors = it->second;
53
    loadHair(paths.getStringValue("hairColorFile"),
54
        colors,
55
        SkipError_true);
56
    loadHair(paths.getStringValue("hairColorPatchFile"),
57
        colors,
58
        SkipError_true);
59
    StringVect list;
60
    VirtFs::getFilesInDir(paths.getStringValue(
61
        "hairColorPatchDir"), list, ".xml");
62
    FOR_EACH (StringVectCIter, it2, list)
63
        loadHair(*it2, colors, SkipError_true);
64
65
    mColorLists["hair"] = colors;
66
67
    loadColorLists(paths.getStringValue("itemColorsFile"),
68
        SkipError_false);
69
    loadColorLists(paths.getStringValue("itemColorsPatchFile"),
70
        SkipError_true);
71
    loadXmlDir("itemColorsPatchDir", loadColorLists)
72
73
    it = mColorLists.find("hair");
74
    if (it != mColorLists.end())
75
        mHairColorsSize = CAST_S32((*it).second.size());
76
    else
77
        mHairColorsSize = 0;
78
    mLoaded = true;
79
}
80
81
void ColorDB::loadHair(const std::string &fileName,
82
                       std::map<ItemColor, ItemColorData> &colors,
83
                       const SkipError skipError)
84
{
85
    XML::Document *doc = new XML::Document(fileName,
86
        UseVirtFs_true,
87
        skipError);
88
    XmlNodeConstPtrConst root = doc->rootNode();
89
90
    if ((root == nullptr) || !xmlNameEqual(root, "colors"))
91
    {
92
        logger->log("ColorDB: Failed to find hair colors file.");
93
        if (colors.find(ItemColor_zero) == colors.end())
94
            colors[ItemColor_zero] = ItemColorData(ItemColor_zero, "", "");
95
        delete doc;
96
        return;
97
    }
98
99
    reportAlways("Found legacy hair.xml")
100
    for_each_xml_child_node(node, root)
101
    {
102
        if (xmlNameEqual(node, "include"))
103
        {
104
            const std::string name = XML::getProperty(node, "name", "");
105
            if (!name.empty())
106
                loadHair(name, colors, skipError);
107
            continue;
108
        }
109
        else if (xmlNameEqual(node, "color"))
110
        {
111
            const ItemColor id = fromInt(XML::getProperty(
112
                node, "id", 0), ItemColor);
113
114
            if (colors.find(id) != colors.end())
115
            {
116
                reportAlways("ColorDB: Redefinition of dye ID %d",
117
                    toInt(id, int))
118
            }
119
120
            colors[id] = ItemColorData(id, XML::langProperty(node, "name", ""),
121
                XML::getProperty(node, "value", "#FFFFFF"));
122
        }
123
    }
124
125
    delete doc;
126
}
127
128
void ColorDB::loadColorLists(const std::string &fileName,
129
                             const SkipError skipError)
130
{
131
    XML::Document *doc = new XML::Document(fileName,
132
        UseVirtFs_true,
133
        skipError);
134
    XmlNodeConstPtrConst root = doc->rootNode();
135
    if (root == nullptr)
136
    {
137
        delete doc;
138
        return;
139
    }
140
141
    for_each_xml_child_node(node, root)
142
    {
143
        if (xmlNameEqual(node, "include"))
144
        {
145
            const std::string name = XML::getProperty(node, "name", "");
146
            if (!name.empty())
147
                loadColorLists(name, skipError);
148
            continue;
149
        }
150
        else if (xmlNameEqual(node, "list"))
151
        {
152
            const std::string name = XML::getProperty(node, "name", "");
153
            if (name.empty())
154
                continue;
155
156
            std::map <ItemColor, ItemColorData> colors;
157
            const ColorListsIterator it = mColorLists.find(name);
158
159
            if (it != mColorLists.end())
160
                colors = it->second;
161
162
            for_each_xml_child_node(colorNode, node)
163
            {
164
                if (xmlNameEqual(colorNode, "color"))
165
                {
166
                    const int id = XML::getProperty(colorNode, "id", -1);
167
                    if (id > -1)
168
                    {
169
                        ItemColorData c(fromInt(id, ItemColor),
170
                            XML::langProperty(colorNode, "name", ""),
171
                            XML::getProperty(colorNode, "value", ""));
172
                            colors[c.id] = c;
173
                    }
174
                }
175
            }
176
            mColorLists[name] = colors;
177
        }
178
    }
179
    delete doc;
180
}
181
182
204
void ColorDB::unload()
183
{
184
204
    logger->log1("Unloading color database...");
185
186
204
    mColorLists.clear();
187
204
    mLoaded = false;
188
204
}
189
190
std::string &ColorDB::getHairColorName(const ItemColor id)
191
{
192
    if (!mLoaded)
193
        load();
194
195
    const ColorListsIterator it = mColorLists.find("hair");
196
    if (it == mColorLists.end())
197
    {
198
        reportAlways("ColorDB: Error, hair colors list empty")
199
        return mFail;
200
    }
201
202
    const ColorIterator i = (*it).second.find(id);
203
204
    if (i == (*it).second.end())
205
    {
206
        reportAlways("ColorDB: Error, unknown dye ID# %d",
207
            toInt(id, int))
208
        return mFail;
209
    }
210
    return i->second.name;
211
}
212
213
int ColorDB::getHairSize()
214
{
215
    return mHairColorsSize;
216
}
217
218
const std::map <ItemColor, ItemColorData>
219
12
     *ColorDB::getColorsList(const std::string &name)
220
{
221
12
    const ColorListsIterator it = mColorLists.find(name);
222
223
12
    if (it != mColorLists.end())
224
        return &it->second;
225
    return nullptr;
226

3
}