]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/preferencedictionary.h
q3map2: fix prt loading for vis computation when using -prtfile
[xonotic/netradiant.git] / radiant / preferencedictionary.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_PREFERENCEDICTIONARY_H )
23 #define INCLUDED_PREFERENCEDICTIONARY_H
24
25 #include "preferencesystem.h"
26 #include "xml/ixml.h"
27 #include "stream/stringstream.h"
28 #include "generic/callback.h"
29 #include "versionlib.h"
30 #include <map>
31
32 class PreferenceDictionary : public PreferenceSystem {
33     class PreferenceEntry {
34         Property<const char *> m_cb;
35     public:
36         PreferenceEntry(const Property<const char *> &cb)
37                 : m_cb(cb)
38         {
39         }
40
41         void importString(const char *string)
42         {
43             m_cb.set(string);
44         }
45
46         void exportString(const Callback<void(const char *)> &importer)
47         {
48             m_cb.get(importer);
49         }
50     };
51
52     typedef std::map<CopiedString, PreferenceEntry> PreferenceEntries;
53     PreferenceEntries m_preferences;
54
55     typedef std::map<CopiedString, CopiedString> PreferenceCache;
56     PreferenceCache m_cache;
57
58 public:
59     typedef PreferenceEntries::iterator iterator;
60
61     iterator begin()
62     {
63         return m_preferences.begin();
64     }
65
66     iterator end()
67     {
68         return m_preferences.end();
69     }
70
71     iterator find(const char *name)
72     {
73         return m_preferences.find(name);
74     }
75
76     void registerPreference(const char *name, const Property<const char *> &cb)
77     {
78         m_preferences.insert(PreferenceEntries::value_type(name, PreferenceEntry(cb)));
79         PreferenceCache::iterator i = m_cache.find(name);
80         if (i != m_cache.end()) {
81             cb.set(i->second.c_str());
82             m_cache.erase(i);
83         }
84     }
85
86     void importPref(const char *name, const char *value)
87     {
88         PreferenceEntries::iterator i = m_preferences.find(name);
89         if (i != m_preferences.end()) {
90             (*i).second.importString(value);
91         } else {
92             m_cache.erase(name);
93             m_cache.insert(PreferenceCache::value_type(name, value));
94         }
95     }
96 };
97
98 inline void XMLPreference_importString(XMLImporter &importer, const char *value)
99 {
100     importer.write(value, string_length(value));
101 }
102
103 typedef ReferenceCaller<XMLImporter, void(const char *), XMLPreference_importString> XMLPreferenceImportStringCaller;
104
105 class XMLPreferenceDictionaryExporter : public XMLExporter {
106     class XMLQPrefElement : public XMLElement {
107         const char *m_version;
108     public:
109         XMLQPrefElement(const char *version) : m_version(version)
110         {
111         }
112
113         const char *name() const
114         {
115             return "qpref";
116         }
117
118         const char *attribute(const char *name) const
119         {
120             if (string_equal(name, "version")) {
121                 return m_version;
122             }
123             return "";
124         }
125
126         void forEachAttribute(XMLAttrVisitor &visitor) const
127         {
128             visitor.visit("version", m_version);
129         }
130     };
131
132     class XMLPreferenceElement : public XMLElement {
133         const char *m_name;
134     public:
135         XMLPreferenceElement(const char *name)
136                 : m_name(name)
137         {
138         }
139
140         const char *name() const
141         {
142             return "epair";
143         }
144
145         const char *attribute(const char *name) const
146         {
147             if (string_equal(name, "name")) {
148                 return m_name;
149             }
150             return "";
151         }
152
153         void forEachAttribute(XMLAttrVisitor &visitor) const
154         {
155             visitor.visit("name", m_name);
156         }
157     };
158
159     typedef PreferenceDictionary PreferenceEntries;
160     PreferenceEntries &m_preferences;
161     const char *m_version;
162 public:
163     XMLPreferenceDictionaryExporter(PreferenceDictionary &preferences, const char *version)
164             : m_preferences(preferences), m_version(version)
165     {
166     }
167
168     void exportXML(XMLImporter &importer)
169     {
170         importer.write("\n", 1);
171
172         XMLQPrefElement qpref_element(m_version);
173         importer.pushElement(qpref_element);
174         importer.write("\n", 1);
175
176         for (PreferenceEntries::iterator i = m_preferences.begin(); i != m_preferences.end(); ++i) {
177             XMLPreferenceElement epair_element((*i).first.c_str());
178
179             importer.pushElement(epair_element);
180
181             (*i).second.exportString(XMLPreferenceImportStringCaller(importer));
182
183             importer.popElement(epair_element.name());
184             importer.write("\n", 1);
185         }
186
187         importer.popElement(qpref_element.name());
188         importer.write("\n", 1);
189     }
190 };
191
192 class XMLPreferenceDictionaryImporter : public XMLImporter {
193     struct xml_state_t {
194         enum ETag {
195             tag_qpref,
196             tag_qpref_ignore,
197             tag_epair,
198             tag_epair_ignore
199         };
200
201         xml_state_t(ETag tag)
202                 : m_tag(tag)
203         {
204         }
205
206         ETag m_tag;
207         CopiedString m_name;
208         StringOutputStream m_ostream;
209     };
210
211     typedef std::vector<xml_state_t> xml_stack_t;
212     xml_stack_t m_xml_stack;
213
214     typedef PreferenceDictionary PreferenceEntries;
215     PreferenceEntries &m_preferences;
216     Version m_version;
217 public:
218     XMLPreferenceDictionaryImporter(PreferenceDictionary &preferences, const char *version)
219             : m_preferences(preferences), m_version(version_parse(version))
220     {
221     }
222
223     void pushElement(const XMLElement &element)
224     {
225         if (m_xml_stack.empty()) {
226             if (string_equal(element.name(), "qpref")) {
227                 Version dataVersion(version_parse(element.attribute("version")));
228                 if (!version_compatible(m_version, dataVersion)) {
229                     globalOutputStream() << "qpref import: data version " << dataVersion
230                                          << " is not compatible with code version " << m_version << "\n";
231                     m_xml_stack.push_back(xml_state_t::tag_qpref_ignore);
232                 } else {
233                     globalOutputStream() << "qpref import: data version " << dataVersion
234                                          << " is compatible with code version " << m_version << "\n";
235                     m_xml_stack.push_back(xml_state_t::tag_qpref);
236                 }
237             } else {
238                 // not valid
239             }
240         } else {
241             switch (m_xml_stack.back().m_tag) {
242                 case xml_state_t::tag_qpref:
243                     if (string_equal(element.name(), "epair")) {
244                         m_xml_stack.push_back(xml_state_t::tag_epair);
245                         m_xml_stack.back().m_name = element.attribute("name");
246                     } else {
247                         // not valid
248                     }
249                     break;
250                 case xml_state_t::tag_qpref_ignore:
251                     if (string_equal(element.name(), "epair")) {
252                         m_xml_stack.push_back(xml_state_t::tag_epair_ignore);
253                     } else {
254                         // not valid
255                     }
256                     break;
257                 case xml_state_t::tag_epair:
258                 case xml_state_t::tag_epair_ignore:
259                     // not valid
260                     break;
261             }
262         }
263
264     }
265
266     void popElement(const char *name)
267     {
268         if (m_xml_stack.back().m_tag == xml_state_t::tag_epair) {
269             m_preferences.importPref(m_xml_stack.back().m_name.c_str(), m_xml_stack.back().m_ostream.c_str());
270         }
271         m_xml_stack.pop_back();
272     }
273
274     std::size_t write(const char *buffer, std::size_t length)
275     {
276         return m_xml_stack.back().m_ostream.write(buffer, length);
277     }
278 };
279
280 #endif