Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/src/setting.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 132 - (show annotations) (download) (as text)
Tue Sep 13 17:40:57 2016 UTC (7 years, 6 months ago) by z0rac
File MIME type: text/x-c++src
File size: 9741 byte(s)


1 /*
2 * Copyright (C) 2009-2016 TSUBAKIMOTO Hiroya <z0rac@users.sourceforge.jp>
3 *
4 * This software comes with ABSOLUTELY NO WARRANTY; for details of
5 * the license terms, see the LICENSE.txt file included with the program.
6 */
7 #include "define.h"
8 #include "setting.h"
9 #include "win32.h"
10 #include <cassert>
11 #include <ctime>
12 #include <shlwapi.h>
13
14 #ifdef _DEBUG
15 #include <iostream>
16 #define DBG(s) s
17 #define LOG(s) (cout << s)
18 #else
19 #define DBG(s)
20 #define LOG(s)
21 #endif
22
23 /*
24 * Functions of class setting::_repository
25 */
26 static setting::repository* _rep = NULL;
27
28 setting::_repository::_repository()
29 {
30 _rep = this;
31 }
32
33 /*
34 * Functions of class setting
35 */
36 setting
37 setting::preferences()
38 {
39 // "(preferences)" is the special section name.
40 return _rep->storage("(preferences)");
41 }
42
43 setting
44 setting::preferences(_str name)
45 {
46 assert(_rep);
47 assert(name && name[0]);
48 return _rep->storage('(' + string(name) + ')');
49 }
50
51 list<string>
52 setting::mailboxes()
53 {
54 assert(_rep);
55 list<string> st(_rep->storages());
56 for (list<string>::iterator p = st.begin(); p != st.end();) {
57 // skip sections matched with the pattern "(.*)".
58 p = p->empty() || ((*p)[0] == '(' && *p->rbegin() == ')') ? st.erase(p) : ++p;
59 }
60 return st;
61 }
62
63 setting
64 setting::mailbox(const string& id)
65 {
66 assert(_rep);
67 return _rep->storage(id);
68 }
69
70 void
71 setting::mailboxclear(const string& id)
72 {
73 assert(_rep);
74 _rep->erase(id);
75 }
76
77 namespace {
78 string cachekey(const string& key)
79 {
80 string esc;
81 string ch = string("$") + _rep->invalidchars();
82 string::size_type i = 0, n;
83 while (n = StrCSpn(key.c_str() + i, ch.c_str()), i + n < key.size()) {
84 esc += key.substr(i, n), i += n;
85 char e[] = "$0";
86 e[1] += char(ch.find_first_of(key[i++]));
87 esc += e;
88 }
89 return "(cache:" + esc + key.substr(i, n) + ')';
90 }
91 }
92
93 list<string>
94 setting::cache(const string& key)
95 {
96 assert(_rep);
97 list<string> result;
98 unique_ptr<storage> cache(_rep->storage(cachekey(key)));
99 list<string> keys(cache->keys());
100 for (list<string>::iterator p = keys.begin(); p != keys.end(); ++p) {
101 result.push_back(cache->get(p->c_str()));
102 }
103 return result;
104 }
105
106 void
107 setting::cache(const string& key, const list<string>& data)
108 {
109 assert(_rep);
110 string id = cachekey(key);
111 _rep->erase(id);
112 if (!data.empty()) {
113 unique_ptr<storage> cache(_rep->storage(id));
114 long i = 0;
115 for (list<string>::const_iterator p = data.begin(); p != data.end(); ++p) {
116 char s[35];
117 cache->put(_ltoa(++i, s, 10), p->c_str());
118 }
119 }
120 }
121
122 void
123 setting::cacheclear()
124 {
125 assert(_rep);
126 list<string> rep(_rep->storages());
127 for (list<string>::iterator p = rep.begin(); p != rep.end(); ++p) {
128 if (!p->empty() && *p->rbegin() == ')' && p->find("(cache:") == 0) {
129 _rep->erase(*p);
130 }
131 }
132 }
133
134 const char*
135 setting::invalidchars()
136 {
137 assert(_rep);
138 return _rep->invalidchars();
139 }
140
141 static const char code64[] =
142 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
143
144 string
145 setting::cipher(_str key)
146 {
147 string s = _st->get(key);
148 if (!s.empty()) {
149 if (s[0] == '\x7f') {
150 if (s.size() < 5 || (s.size() & 1) == 0) return string();
151 string e;
152 unsigned i = 0;
153 for (const char* p = s.c_str() + 1; *p; p += 2) {
154 int c = 0;
155 for (int h = 0; h < 2; ++h) {
156 const char* pos = strchr(code64, p[h]);
157 if (!pos) return string();
158 c = (c << 4) | ((unsigned(pos - code64) - i) & 15);
159 i += 5 + h;
160 }
161 e += char(c);
162 }
163 for (string::size_type j = e.size(); j-- > 2;) e[j] ^= e[j & 1];
164 s = e.substr(2);
165 } else {
166 cipher(key, s);
167 }
168 }
169 return s;
170 }
171
172 setting&
173 setting::cipher(_str key, const string& value)
174 {
175 union { char s[2]; short r; } seed;
176 seed.r = short(unsigned(ptrdiff_t(value.data())) + time(NULL));
177 string e = string(seed.s, 2) + value;
178 for (string::size_type i = e.size(); i-- > 2;) e[i] ^= e[i & 1];
179 string s(e.size() * 2 + 1, '\x7f');
180 unsigned d = 0;
181 for (string::size_type i = 0; i < e.size(); ++i) {
182 s[i * 2 + 1] = code64[(((e[i] >> 4) & 15) + d) & 63];
183 s[i * 2 + 2] = code64[((e[i] & 15) + d + 5) & 63];
184 d += 11;
185 }
186 _st->put(key, s.c_str());
187 return *this;
188 }
189
190 /*
191 * Functions of class setting::tuple
192 */
193 setting::tuple&
194 setting::tuple::add(const string& s)
195 {
196 _s += _sep, _s += s;
197 return *this;
198 }
199
200 string
201 setting::tuple::digit(long i)
202 {
203 char s[35];
204 return _ltoa(i, s, 10);
205 }
206
207 /*
208 * Functions of class setting::manip
209 */
210 setting::manip::manip(const string& s)
211 : _s(s), _next(0), _sep(',') {}
212
213 string
214 setting::manip::next()
215 {
216 static const char ws[] = " \t";
217 if (!avail()) return string();
218 string::size_type i = _s.find_first_not_of(ws, _next);
219 string::size_type n = _s.find_first_of(_sep, _next);
220 _next = n != string::npos ? n + 1 : (n = _s.size());
221 return i < n ? _s.substr(i, _s.find_last_not_of(ws, n - 1) - i + 1) : string();
222 }
223
224 bool
225 setting::manip::next(int& v)
226 {
227 string s = next();
228 if (s.empty()) return false;
229 v = strtol(s.c_str(), NULL, 0);
230 return true;
231 }
232
233 setting::manip&
234 setting::manip::operator()(string& v)
235 {
236 string s = next();
237 if (!s.empty()) v = win32::xenv(s);
238 return *this;
239 }
240
241 list<string>
242 setting::manip::split()
243 {
244 list<string> result;
245 while (avail()) result.push_back(win32::xenv(next()));
246 return result;
247 }
248
249 #if USE_REG
250 /** regkey - implement for setting::storage.
251 */
252 namespace {
253 class regkey : public setting::storage {
254 HKEY _key;
255 public:
256 regkey(HKEY key, const string& name);
257 ~regkey();
258 string get(const char* key) const;
259 void put(const char* key, const char* value);
260 void erase(const char* key);
261 list<string> keys() const;
262 };
263 }
264
265 regkey::regkey(HKEY key, const string& name)
266 : _key(NULL)
267 {
268 key && RegCreateKeyEx(key, name.c_str(), 0, NULL,
269 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &_key, NULL);
270 }
271
272 regkey::~regkey()
273 {
274 _key && RegCloseKey(_key);
275 }
276
277 string
278 regkey::get(const char* key) const
279 {
280 DWORD type;
281 DWORD size;
282 if (_key &&
283 RegQueryValueEx(_key, key, NULL, &type, NULL, &size) == ERROR_SUCCESS &&
284 type == REG_SZ) {
285 win32::textbuf<char> buf(size);
286 if (RegQueryValueEx(_key, key, NULL, NULL, LPBYTE(buf.data), &size) == ERROR_SUCCESS) {
287 return buf.data;
288 }
289 }
290 return string();
291 }
292
293 void
294 regkey::put(const char* key, const char* value)
295 {
296 _key && RegSetValueEx(_key, key, 0, REG_SZ, (const BYTE*)value, strlen(value) + 1);
297 }
298
299 void
300 regkey::erase(const char* key)
301 {
302 _key && RegDeleteValue(_key, key);
303 }
304
305 list<string>
306 regkey::keys() const
307 {
308 list<string> result;
309 DWORD size;
310 if (_key && RegQueryInfoKey(_key, NULL, NULL, NULL, NULL, NULL,
311 NULL, NULL, &size, NULL, NULL, NULL) == ERROR_SUCCESS) {
312 win32::textbuf<char> buf(++size);
313 DWORD i = 0, n;
314 while (n = size, RegEnumValue(_key, i++, buf.data, &n,
315 NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
316 result.push_back(buf.data);
317 }
318 }
319 return result;
320 }
321
322 /*
323 * Functions of class registory
324 */
325 registory::registory(const char* key)
326 : _key(NULL)
327 {
328 RegCreateKeyEx(HKEY_CURRENT_USER, key, 0, NULL,
329 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, PHKEY(&_key), NULL);
330 }
331
332 registory::~registory()
333 {
334 _key && RegCloseKey(HKEY(_key));
335 }
336
337 setting::storage*
338 registory::storage(const string& name) const
339 {
340 return new regkey(HKEY(_key), name);
341 }
342
343 list<string>
344 registory::storages() const
345 {
346 list<string> result;
347 DWORD size;
348 if (_key && RegQueryInfoKey(HKEY(_key), NULL, NULL, NULL, NULL, &size,
349 NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
350 win32::textbuf<char> buf(++size);
351 DWORD i = 0, n;
352 while (n = size, RegEnumKeyEx(HKEY(_key), i++, buf.data, &n,
353 NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
354 result.push_back(buf.data);
355 }
356 }
357 return result;
358 }
359
360 void
361 registory::erase(const string& name)
362 {
363 _key && RegDeleteKey(HKEY(_key), name.c_str());
364 }
365 #else // !USE_REG
366 /** section - implement for setting::storage.
367 * This is using Windows API for .INI file.
368 */
369 namespace {
370 class section : public setting::storage {
371 string _section;
372 const char* _path;
373 public:
374 section(const string& section, const char* path)
375 : _section(section), _path(path) {}
376 string get(const char* key) const;
377 void put(const char* key, const char* value);
378 void erase(const char* key);
379 list<string> keys() const;
380 };
381 }
382
383 string
384 section::get(const char* key) const
385 {
386 return win32::profile(_section.c_str(), key, _path);
387 }
388
389 void
390 section::put(const char* key, const char* value)
391 {
392 string tmp;
393 if (value && value[0] == '"' && value[strlen(value) - 1] == '"') {
394 tmp = '"' + string(value) + '"';
395 value = tmp.c_str();
396 }
397 win32::profile(_section.c_str(), key, value, _path);
398 }
399
400 void
401 section::erase(const char* key)
402 {
403 win32::profile(_section.c_str(), key, NULL, _path);
404 }
405
406 list<string>
407 section::keys() const
408 {
409 return setting::manip(get(NULL)).sep(0).split();
410 }
411
412 /*
413 * Functions of class profile
414 */
415 profile::~profile()
416 {
417 win32::profile(NULL, NULL, NULL, _path);
418 }
419
420 setting::storage*
421 profile::storage(const string& name) const
422 {
423 return new section(name, _path);
424 }
425
426 list<string>
427 profile::storages() const
428 {
429 return setting::manip(win32::profile(NULL, NULL, _path)).sep(0).split();
430 }
431
432 void
433 profile::erase(const string& name)
434 {
435 win32::profile(name.c_str(), NULL, NULL, _path);
436 }
437 #endif // !USE_REG

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26