|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY
|
|
|
4 #include <vector>
|
|
|
5 #include "filesystem.h" // stream_reader, stream_writer
|
|
|
6
|
|
|
7 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
8 #include "configStore.h"
|
|
|
9 #include "initquit.h"
|
|
|
10 #endif
|
|
|
11
|
|
|
12 namespace cfg_var_legacy {
|
|
|
13 #define CFG_VAR_ASSERT_SAFEINIT PFC_ASSERT(!core_api::are_services_available());/*imperfect check for nonstatic instantiation*/
|
|
|
14
|
|
|
15 //! Reader part of cfg_var object. In most cases, you should use cfg_var instead of using cfg_var_reader directly.
|
|
|
16 class NOVTABLE cfg_var_reader {
|
|
|
17 public:
|
|
|
18 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
19 cfg_var_reader(const GUID& guid) : m_guid(guid) { CFG_VAR_ASSERT_SAFEINIT; m_next = g_list; g_list = this; }
|
|
|
20 ~cfg_var_reader() { CFG_VAR_ASSERT_SAFEINIT; }
|
|
|
21
|
|
|
22 //! Sets state of the variable. Called only from main thread, when reading configuration file.
|
|
|
23 //! @param p_stream Stream containing new state of the variable.
|
|
|
24 //! @param p_sizehint Number of bytes contained in the stream; reading past p_sizehint bytes will fail (EOF).
|
|
|
25 virtual void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) = 0;
|
|
|
26
|
|
|
27 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
28 private:
|
|
|
29 pfc::string8 m_downgrade_name;
|
|
|
30 public:
|
|
|
31 pfc::string8 downgrade_name() const;
|
|
|
32 void downgrade_set_name( const char * arg ) { m_downgrade_name = arg; }
|
|
|
33
|
|
|
34 //! Implementation of config downgrade for this var, see FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE for more info. \n
|
|
|
35 //! Most components should not use this.
|
|
|
36 virtual void downgrade_check(fb2k::configStore::ptr api) {}
|
|
|
37 //! Config downgrade main for your component, see FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE for more info. \n
|
|
|
38 //! Put FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE somewhere in your component to call on startup, or call from your code as early as possible after config read. \n
|
|
|
39 //! If you call it more than once, spurious calls will be ignored.
|
|
|
40 static void downgrade_main();
|
|
|
41 #endif
|
|
|
42
|
|
|
43 //! For internal use only, do not call.
|
|
|
44 static void config_read_file(stream_reader* p_stream, abort_callback& p_abort);
|
|
|
45
|
|
|
46 const GUID m_guid;
|
|
|
47 private:
|
|
|
48 static cfg_var_reader* g_list;
|
|
|
49 cfg_var_reader* m_next;
|
|
|
50
|
|
|
51 PFC_CLASS_NOT_COPYABLE_EX(cfg_var_reader)
|
|
|
52 };
|
|
|
53
|
|
|
54 //! Writer part of cfg_var object. In most cases, you should use cfg_var instead of using cfg_var_writer directly.
|
|
|
55 class NOVTABLE cfg_var_writer {
|
|
|
56 public:
|
|
|
57 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
58 cfg_var_writer(const GUID& guid) : m_guid(guid) { CFG_VAR_ASSERT_SAFEINIT; m_next = g_list; g_list = this; }
|
|
|
59 ~cfg_var_writer() { CFG_VAR_ASSERT_SAFEINIT; }
|
|
|
60
|
|
|
61 //! Retrieves state of the variable. Called only from main thread, when writing configuration file.
|
|
|
62 //! @param p_stream Stream receiving state of the variable.
|
|
|
63 virtual void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) = 0;
|
|
|
64
|
|
|
65 //! For internal use only, do not call.
|
|
|
66 static void config_write_file(stream_writer* p_stream, abort_callback& p_abort);
|
|
|
67
|
|
|
68 const GUID m_guid;
|
|
|
69 private:
|
|
|
70 static cfg_var_writer* g_list;
|
|
|
71 cfg_var_writer* m_next;
|
|
|
72
|
|
|
73 PFC_CLASS_NOT_COPYABLE_EX(cfg_var_writer)
|
|
|
74 };
|
|
|
75
|
|
|
76 //! Base class for configuration variable classes; provides self-registration mechaisms and methods to set/retrieve configuration data; those methods are automatically called for all registered instances by backend when configuration file is being read or written.\n
|
|
|
77 //! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such).
|
|
|
78 class NOVTABLE cfg_var : public cfg_var_reader, public cfg_var_writer {
|
|
|
79 protected:
|
|
|
80 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
81 cfg_var(const GUID& p_guid) : cfg_var_reader(p_guid), cfg_var_writer(p_guid) {}
|
|
|
82 public:
|
|
|
83 GUID get_guid() const { return cfg_var_reader::m_guid; }
|
|
|
84 };
|
|
|
85
|
|
|
86 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
87 int64_t downgrade_this( fb2k::configStore::ptr api, const char*, int64_t current);
|
|
|
88 uint64_t downgrade_this( fb2k::configStore::ptr api, const char*, uint64_t current);
|
|
|
89 int32_t downgrade_this( fb2k::configStore::ptr api, const char*, int32_t current);
|
|
|
90 uint32_t downgrade_this( fb2k::configStore::ptr api, const char*, uint32_t current);
|
|
|
91 bool downgrade_this( fb2k::configStore::ptr api, const char*, bool current);
|
|
|
92 double downgrade_this( fb2k::configStore::ptr api, const char*, double current);
|
|
|
93 GUID downgrade_this( fb2k::configStore::ptr api, const char*, GUID current);
|
|
|
94 #endif
|
|
|
95
|
|
|
96 //! Generic integer config variable class. Template parameter can be used to specify integer type to use.\n
|
|
|
97 //! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such).
|
|
|
98 template<typename t_inttype>
|
|
|
99 class cfg_int_t : public cfg_var {
|
|
|
100 private:
|
|
|
101 t_inttype m_val;
|
|
|
102 protected:
|
|
|
103 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override { p_stream->write_lendian_t(m_val, p_abort); }
|
|
|
104 void set_data_raw(stream_reader* p_stream, t_size, abort_callback& p_abort) override {
|
|
|
105 t_inttype temp;
|
|
|
106 p_stream->read_lendian_t(temp, p_abort);//alter member data only on success, this will throw an exception when something isn't right
|
|
|
107 m_val = temp;
|
|
|
108 }
|
|
|
109 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
110 void downgrade_check(fb2k::configStore::ptr api) override {
|
|
|
111 m_val = downgrade_this(api, this->downgrade_name(), m_val);
|
|
|
112 }
|
|
|
113 #endif
|
|
|
114 public:
|
|
|
115 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
116 //! @param p_default Default value of the variable.
|
|
|
117 explicit inline cfg_int_t(const GUID& p_guid, t_inttype p_default) : cfg_var(p_guid), m_val(p_default) {}
|
|
|
118
|
|
|
119 inline const cfg_int_t<t_inttype>& operator=(const cfg_int_t<t_inttype>& p_val) { m_val = p_val.m_val; return *this; }
|
|
|
120 inline t_inttype operator=(t_inttype p_val) { m_val = p_val; return m_val; }
|
|
|
121
|
|
|
122 inline operator t_inttype() const { return m_val; }
|
|
|
123
|
|
|
124 inline t_inttype get_value() const { return m_val; }
|
|
|
125 inline t_inttype get() const { return m_val; }
|
|
|
126 };
|
|
|
127
|
|
|
128 typedef cfg_int_t<t_int32> cfg_int;
|
|
|
129 typedef cfg_int_t<t_uint32> cfg_uint;
|
|
|
130 typedef cfg_int_t<GUID> cfg_guid; // ANNOYING OLD DESIGN. THIS DOESN'T BELONG HERE BUT CANNOT BE CHANGED WITHOUT BREAKING PEOPLE'S STUFF. BLARFGH.
|
|
|
131 typedef cfg_int_t<bool> cfg_bool; // See above.
|
|
|
132 typedef cfg_int_t<float> cfg_float; // See above %$!@#$
|
|
|
133 typedef cfg_int_t<double> cfg_double; // ....
|
|
|
134
|
|
|
135 //! String config variable. Stored in the stream with int32 header containing size in bytes, followed by non-null-terminated UTF-8 data.\n
|
|
|
136 //! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such).
|
|
|
137 class cfg_string : public cfg_var, public pfc::string8 {
|
|
|
138 protected:
|
|
|
139 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override;
|
|
|
140 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) override;
|
|
|
141
|
|
|
142 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
143 void downgrade_check(fb2k::configStore::ptr) override;
|
|
|
144 #endif
|
|
|
145 public:
|
|
|
146 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
147 //! @param p_defaultval Default/initial value of the variable.
|
|
|
148 explicit inline cfg_string(const GUID& p_guid, const char* p_defaultval) : cfg_var(p_guid), pfc::string8(p_defaultval) {}
|
|
|
149
|
|
|
150 const cfg_string& operator=(const cfg_string& p_val) { set_string(p_val); return *this; }
|
|
|
151 const cfg_string& operator=(const char* p_val) { set_string(p_val); return *this; }
|
|
|
152 const cfg_string& operator=(pfc::string8 && p_val) { set(std::move(p_val)); return *this; }
|
|
|
153
|
|
|
154
|
|
|
155 inline operator const char* () const { return get_ptr(); }
|
|
|
156 const pfc::string8& get() const { return *this; }
|
|
|
157 void set( const char * arg ) { this->set_string(arg); }
|
|
|
158 void set(pfc::string8&& arg) { pfc::string8 * pThis = this; *pThis = std::move(arg); }
|
|
|
159 };
|
|
|
160
|
|
|
161
|
|
|
162 class cfg_string_mt : public cfg_var {
|
|
|
163 protected:
|
|
|
164 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override {
|
|
|
165 pfc::string8 temp;
|
|
|
166 get(temp);
|
|
|
167 p_stream->write_object(temp.get_ptr(), temp.length(), p_abort);
|
|
|
168 }
|
|
|
169 void set_data_raw(stream_reader* p_stream, t_size, abort_callback& p_abort) override {
|
|
|
170 pfc::string8_fastalloc temp;
|
|
|
171 p_stream->read_string_raw(temp, p_abort);
|
|
|
172 set(temp);
|
|
|
173 }
|
|
|
174 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
175 void downgrade_check(fb2k::configStore::ptr) override;
|
|
|
176 #endif
|
|
|
177 public:
|
|
|
178 cfg_string_mt(const GUID& id, const char* defVal) : cfg_var(id), m_val(defVal) {}
|
|
|
179 void get(pfc::string_base& out) const { inReadSync(m_sync); out = m_val; }
|
|
|
180 pfc::string8 get() const { inReadSync(m_sync); return m_val; }
|
|
|
181 void set(const char* val, t_size valLen = SIZE_MAX) { inWriteSync(m_sync); m_val.set_string(val, valLen); }
|
|
|
182 void set( pfc::string8 && val ) { inWriteSync(m_sync); m_val = std::move(val); }
|
|
|
183 private:
|
|
|
184 mutable pfc::readWriteLock m_sync;
|
|
|
185 pfc::string8 m_val;
|
|
|
186 };
|
|
|
187
|
|
|
188 //! Struct config variable template. Warning: not endian safe, should be used only for nonportable code.\n
|
|
|
189 //! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such).
|
|
|
190 template<typename t_struct>
|
|
|
191 class cfg_struct_t : public cfg_var {
|
|
|
192 private:
|
|
|
193 t_struct m_val = {};
|
|
|
194 protected:
|
|
|
195
|
|
|
196 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) { p_stream->write_object(&m_val, sizeof(m_val), p_abort); }
|
|
|
197 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
198 t_struct temp;
|
|
|
199 p_stream->read_object(&temp, sizeof(temp), p_abort);
|
|
|
200 m_val = temp;
|
|
|
201 }
|
|
|
202 public:
|
|
|
203 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
204 inline cfg_struct_t(const GUID& p_guid, const t_struct& p_val) : cfg_var(p_guid), m_val(p_val) {}
|
|
|
205 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
206 inline cfg_struct_t(const GUID& p_guid, int filler) : cfg_var(p_guid) { memset(&m_val, filler, sizeof(t_struct)); }
|
|
|
207 //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var.
|
|
|
208 inline cfg_struct_t(const GUID& p_guid) : cfg_var(p_guid) {}
|
|
|
209
|
|
|
210 inline const cfg_struct_t<t_struct>& operator=(const cfg_struct_t<t_struct>& p_val) { m_val = p_val.get_value(); return *this; }
|
|
|
211 inline const cfg_struct_t<t_struct>& operator=(const t_struct& p_val) { m_val = p_val; return *this; }
|
|
|
212
|
|
|
213 inline const t_struct& get_value() const { return m_val; }
|
|
|
214 inline t_struct& get_value() { return m_val; }
|
|
|
215 inline operator t_struct() const { return m_val; }
|
|
|
216
|
|
|
217 void set(t_struct&& arg) { m_val = std::move(arg); }
|
|
|
218 void set(t_struct const& arg) { m_val = arg; }
|
|
|
219 t_struct get() const { return m_val; }
|
|
|
220 };
|
|
|
221
|
|
|
222
|
|
|
223 template<typename TObj>
|
|
|
224 class cfg_objList : public cfg_var, public pfc::list_t<TObj> {
|
|
|
225 public:
|
|
|
226 typedef TObj item_t;
|
|
|
227 typedef cfg_objList<item_t> t_self;
|
|
|
228 cfg_objList(const GUID& guid) : cfg_var(guid) {}
|
|
|
229 template<typename TSource, unsigned Count> cfg_objList(const GUID& guid, const TSource(&source)[Count]) : cfg_var(guid) {
|
|
|
230 reset(source);
|
|
|
231 }
|
|
|
232 template<typename TSource, unsigned Count> void reset(const TSource(&source)[Count]) {
|
|
|
233 this->set_size(Count); for (t_size walk = 0; walk < Count; ++walk) (*this)[walk] = source[walk];
|
|
|
234 }
|
|
|
235 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) {
|
|
|
236 stream_writer_formatter<> out(*p_stream, p_abort);
|
|
|
237 out << pfc::downcast_guarded<t_uint32>(this->get_size());
|
|
|
238 for (t_size walk = 0; walk < this->get_size(); ++walk) out << (*this)[walk];
|
|
|
239 }
|
|
|
240 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
241 try {
|
|
|
242 stream_reader_formatter<> in(*p_stream, p_abort);
|
|
|
243 t_uint32 count; in >> count;
|
|
|
244 this->set_count(count);
|
|
|
245 for (t_uint32 walk = 0; walk < count; ++walk) in >> (*this)[walk];
|
|
|
246 } catch (...) {
|
|
|
247 this->remove_all();
|
|
|
248 throw;
|
|
|
249 }
|
|
|
250 }
|
|
|
251 template<typename t_in> t_self& operator=(t_in const& source) { this->remove_all(); this->add_items(source); return *this; }
|
|
|
252 template<typename t_in> t_self& operator+=(t_in const& p_source) { this->add_item(p_source); return *this; }
|
|
|
253 template<typename t_in> t_self& operator|=(t_in const& p_source) { this->add_items(p_source); return *this; }
|
|
|
254
|
|
|
255
|
|
|
256 std::vector<item_t> get() const {
|
|
|
257 std::vector<item_t> ret; ret.reserve(this->size());
|
|
|
258 for (auto& item : *this) ret.push_back(item);
|
|
|
259 return ret;
|
|
|
260 }
|
|
|
261 template<typename arg_t> void set(arg_t&& arg) {
|
|
|
262 this->remove_all();
|
|
|
263 this->prealloc(std::size(arg));
|
|
|
264 for (auto& item : arg) {
|
|
|
265 this->add_item(item);
|
|
|
266 }
|
|
|
267 }
|
|
|
268 };
|
|
|
269 template<typename TList>
|
|
|
270 class cfg_objListEx : public cfg_var, public TList {
|
|
|
271 public:
|
|
|
272 typedef cfg_objListEx<TList> t_self;
|
|
|
273 cfg_objListEx(const GUID& guid) : cfg_var(guid) {}
|
|
|
274 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) {
|
|
|
275 stream_writer_formatter<> out(*p_stream, p_abort);
|
|
|
276 out << pfc::downcast_guarded<t_uint32>(this->get_count());
|
|
|
277 for (typename TList::const_iterator walk = this->first(); walk.is_valid(); ++walk) out << *walk;
|
|
|
278 }
|
|
|
279 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
280 this->remove_all();
|
|
|
281 stream_reader_formatter<> in(*p_stream, p_abort);
|
|
|
282 t_uint32 count; in >> count;
|
|
|
283 for (t_uint32 walk = 0; walk < count; ++walk) {
|
|
|
284 typename TList::t_item item; in >> item; this->add_item(item);
|
|
|
285 }
|
|
|
286 }
|
|
|
287 template<typename t_in> t_self& operator=(t_in const& source) { this->remove_all(); this->add_items(source); return *this; }
|
|
|
288 template<typename t_in> t_self& operator+=(t_in const& p_source) { this->add_item(p_source); return *this; }
|
|
|
289 template<typename t_in> t_self& operator|=(t_in const& p_source) { this->add_items(p_source); return *this; }
|
|
|
290 };
|
|
|
291
|
|
|
292 template<typename TObj>
|
|
|
293 class cfg_obj : public cfg_var, public TObj {
|
|
|
294 public:
|
|
|
295 cfg_obj(const GUID& guid) : cfg_var(guid), TObj() {}
|
|
|
296 template<typename TInitData> cfg_obj(const GUID& guid, const TInitData& initData) : cfg_var(guid), TObj(initData) {}
|
|
|
297
|
|
|
298 TObj& val() { return *this; }
|
|
|
299 TObj const& val() const { return *this; }
|
|
|
300 TObj get() const { return val(); }
|
|
|
301 template<typename arg_t> void set(arg_t&& arg) { val() = std::forward<arg_t>(arg); }
|
|
|
302
|
|
|
303 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) {
|
|
|
304 stream_writer_formatter<> out(*p_stream, p_abort);
|
|
|
305 const TObj* ptr = this;
|
|
|
306 out << *ptr;
|
|
|
307 }
|
|
|
308 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
309 stream_reader_formatter<> in(*p_stream, p_abort);
|
|
|
310 TObj* ptr = this;
|
|
|
311 in >> *ptr;
|
|
|
312 }
|
|
|
313 };
|
|
|
314
|
|
|
315 template<typename TObj, typename TImport> class cfg_objListImporter : private cfg_var_reader {
|
|
|
316 public:
|
|
|
317 typedef cfg_objList<TObj> TMasterVar;
|
|
|
318 cfg_objListImporter(TMasterVar& var, const GUID& guid) : m_var(var), cfg_var_reader(guid) {}
|
|
|
319
|
|
|
320 private:
|
|
|
321 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
322 TImport temp;
|
|
|
323 try {
|
|
|
324 stream_reader_formatter<> in(*p_stream, p_abort);
|
|
|
325 t_uint32 count; in >> count;
|
|
|
326 m_var.set_count(count);
|
|
|
327 for (t_uint32 walk = 0; walk < count; ++walk) {
|
|
|
328 in >> temp;
|
|
|
329 m_var[walk] = temp;
|
|
|
330 }
|
|
|
331 } catch (...) {
|
|
|
332 m_var.remove_all();
|
|
|
333 throw;
|
|
|
334 }
|
|
|
335 }
|
|
|
336 TMasterVar& m_var;
|
|
|
337 };
|
|
|
338 template<typename TMap> class cfg_objMap : private cfg_var, public TMap {
|
|
|
339 public:
|
|
|
340 cfg_objMap(const GUID& id) : cfg_var(id) {}
|
|
|
341 private:
|
|
|
342 void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) {
|
|
|
343 stream_writer_formatter<> out(*p_stream, p_abort);
|
|
|
344 out << pfc::downcast_guarded<t_uint32>(this->get_count());
|
|
|
345 for (typename TMap::const_iterator walk = this->first(); walk.is_valid(); ++walk) {
|
|
|
346 out << walk->m_key << walk->m_value;
|
|
|
347 }
|
|
|
348 }
|
|
|
349 void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) {
|
|
|
350 this->remove_all();
|
|
|
351 stream_reader_formatter<> in(*p_stream, p_abort);
|
|
|
352 t_uint32 count; in >> count;
|
|
|
353 for (t_uint32 walk = 0; walk < count; ++walk) {
|
|
|
354 typename TMap::t_key key; in >> key; PFC_ASSERT(!this->have_item(key));
|
|
|
355 try { in >> this->find_or_add(key); } catch (...) { this->remove(key); throw; }
|
|
|
356 }
|
|
|
357 }
|
|
|
358 };
|
|
|
359 #if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
360 #define FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE FB2K_RUN_ON_INIT(cfg_var_reader::downgrade_main)
|
|
|
361 #endif // FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE
|
|
|
362 } // cfg_var_legacy
|
|
|
363 #else
|
|
|
364 namespace cfg_var_legacy {
|
|
|
365 // Dummy class
|
|
|
366 class cfg_var_reader {
|
|
|
367 public:
|
|
|
368 cfg_var_reader(const GUID& id) : m_guid(id) {}
|
|
|
369 const GUID m_guid;
|
|
|
370 };
|
|
|
371 }
|
|
|
372 #endif
|
|
|
373
|
|
|
374 #ifndef FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE
|
|
|
375 #define FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE
|
|
|
376 #endif |