checking in the recent efforts at optimizing clam
[feisty_meow.git] / nucleus / library / application / registry_config.cpp
1 /*
2 *  Name   : registry_configurator                                             *
3 *  Author : Chris Koeritz                                                     *
4 **
5 * Copyright (c) 2004-$now By Author.  This program is free software; you can  *
6 * redistribute it and/or modify it under the terms of the GNU General Public  *
7 * License as published by the Free Software Foundation; either version 2 of   *
8 * the License or (at your option) any later version.  This is online at:      *
9 *     http://www.fsf.org/copyleft/gpl.html                                    *
10 * Please send any updates to: fred@gruntose.com                               *
11 */
12
13 #include "registry_config.h"
14
15 #include <application/windoze_helper.h>
16 #include <basis/astring.h>
17 #include <basis/functions.h>
18 #include <basis/utf_conversion.h>
19 #include <structures/static_memory_gremlin.h>
20 #include <structures/string_array.h>
21 #include <structures/string_table.h>
22
23 using namespace basis;
24 using namespace filesystem;
25 using namespace structures;
26
27 #ifdef __WIN32__
28
29   // this implementation only works on windows currently.
30 //hmmm: i suppose we could fake it with an ini file.
31
32   #include <shlwapi.h>
33 #endif
34
35 #undef LOG
36 #ifdef DEBUG_REGISTRY_CONFIGURATOR
37   #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
38 #else
39   #define LOG(s) {}
40 #endif
41
42 //#define DEBUG_REGISTRY_CONFIGURATOR
43   // uncomment for noisy version.
44
45 namespace configuration {
46
47 const int MAXIMUM_ENTRY_SIZE = 256 * KILOBYTE;
48   // arbitrary maximum for entries we'll read.
49
50 const int MAXIMUM_NAME_SIZE = 16384;
51   // the longest that value names can be in the registry.
52
53 // a default we hope never to see in the registry.
54 const astring &registry_configurator::reg_str_fake_default()
55 {
56   static astring _hidden = "bogus_never_should_see";
57   return _hidden;
58 }
59
60 registry_configurator::registry_configurator(registry_hives hive,
61       treatment_of_defaults behavior)
62 : configurator(behavior),
63   _hive(hive)
64 {}
65
66 registry_configurator::~registry_configurator()
67 {}
68
69 #ifndef __WIN32__
70 // fake the platform dependent names.
71 void *HKEY_CLASSES_ROOT = NULL;
72 void *HKEY_CURRENT_USER = NULL;
73 void *HKEY_LOCAL_MACHINE = NULL;
74 void *HKEY_USERS = NULL;
75 void *HKEY_CURRENT_CONFIG = NULL;
76 #endif
77
78 void *registry_configurator::translate_hive(registry_hives hive)
79 {
80   switch (hive) {
81     case hkey_classes_root: return HKEY_CLASSES_ROOT;
82     case hkey_current_user: return HKEY_CURRENT_USER;
83     case hkey_local_machine: return HKEY_LOCAL_MACHINE;
84     case hkey_users: return HKEY_USERS;
85     case hkey_current_config: return HKEY_CURRENT_CONFIG;
86     default: return 0;
87   }
88 }
89
90 astring registry_configurator::fix_section(const astring &section)
91 {
92   astring to_return = section;
93   for (int i = 0; i < to_return.length(); i++) {
94     if (to_return[i] == '/')
95       to_return[i] = '\\';
96   }
97   return to_return;
98 }
99
100 bool registry_configurator::put(const astring &section_in, const astring &entry,
101     const astring &to_store)
102 {
103   FUNCDEF("put");
104   astring section = fix_section(section_in);
105   if (!to_store.length()) return delete_entry(section, entry);
106   else if (!section.length()) return false;
107
108 #ifdef __WIN32__
109   HKEY key;
110   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
111       to_unicode_temp(section), 0, KEY_WRITE, &key);
112   if (ret != ERROR_SUCCESS) {
113     LOG("failed to open the key, trying to create it.");
114     DWORD dispose;  // the disposition of the call (created or existing).
115     ret = RegCreateKeyEx((HKEY)translate_hive(_hive),
116         to_unicode_temp(section), 0, NULL_POINTER, REG_OPTION_NON_VOLATILE,
117         KEY_ALL_ACCESS, NULL_POINTER, &key, &dispose);
118     if (ret != ERROR_SUCCESS) {
119       LOG("failed to create the key!!");
120       return false;
121     }
122   }
123
124   bool to_return = true;
125   ret = RegSetValueEx(key, to_unicode_temp(entry), 0, REG_SZ,
126       (byte *)to_store.s(), to_store.length() + 1);
127   if (ret != ERROR_SUCCESS) {
128     LOG(astring("failed to write the entry!"));
129     to_return = false;
130   }
131
132   RegCloseKey(key);
133   return to_return;
134 #else
135   return false;
136 #endif
137 }
138
139 bool registry_configurator::get(const astring &section_in, const astring &entry,
140     astring &found)
141 {
142   FUNCDEF("get");
143   found = "";
144   if (!section_in) return false;
145   if (!entry) {}  // not a problem.
146   astring section = fix_section(section_in);
147 #ifdef __WIN32__
148   HKEY key;
149   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
150       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
151   if (ret != ERROR_SUCCESS) {
152     LOG("failed to open the key!");
153     return false;
154   }
155
156   DWORD type_seen;
157   byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
158   DWORD length = MAXIMUM_ENTRY_SIZE - 1;
159   ret = RegQueryValueEx(key, to_unicode_temp(entry), 0, &type_seen, data_seen,
160       &length);
161   if (ret != ERROR_SUCCESS) {
162     LOG(astring("failed to read the entry!"));
163     return false;
164   }
165
166   if (type_seen != REG_SZ) {
167     LOG(astring("entry found was not of string type!"));
168     RegCloseKey(key);
169     return false;
170   }
171
172   data_seen[MAXIMUM_ENTRY_SIZE - 1] = '\0';
173     // force last character to be null if data happened to be too big.
174   found = astring((char *)data_seen);
175
176   delete [] data_seen;
177
178   RegCloseKey(key);
179   return true;
180 #else
181   return false;
182 #endif
183 }
184
185 bool registry_configurator::get_section(const astring &section_in,
186     string_table &info)
187 {
188   FUNCDEF("get_section");
189   info.reset();
190   if (!section_in.length()) return false;
191   astring section = fix_section(section_in);
192 #ifdef __WIN32__
193   HKEY key;
194   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
195       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
196   if (ret != ERROR_SUCCESS) {
197     LOG("failed to open the key!");
198     return false;
199   }
200
201   DWORD type_seen;
202   byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
203   flexichar *name_seen = new flexichar[MAXIMUM_NAME_SIZE];
204   DWORD name_length;
205   for (DWORD index = 0; true; index++) {
206     DWORD length = MAXIMUM_ENTRY_SIZE - 1;
207     name_length = MAXIMUM_NAME_SIZE - 1;
208     LONG ret = RegEnumValue(key, index, name_seen, &name_length, 0,
209         &type_seen, data_seen, &length);
210     if (ret != ERROR_SUCCESS) break;  // no entry at that index.
211     if (type_seen == REG_SZ) {
212       // found an entry successfully and it's the right type.
213       astring name = from_unicode_temp(name_seen);
214       astring content = from_unicode_temp((flexichar *)data_seen);
215       info.add(name, content);
216     }
217   }
218
219   delete [] data_seen;
220   delete [] name_seen;
221
222   RegCloseKey(key);
223
224   return true;
225 #else
226   return false;
227 #endif
228 }
229
230 bool registry_configurator::section_exists(const astring &section_in)
231 {
232   FUNCDEF("section_exists");
233   if (!section_in.length()) return false;
234   astring section = fix_section(section_in);
235 #ifdef __WIN32__
236   HKEY key;
237   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
238       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
239   if (ret != ERROR_SUCCESS) {
240     LOG("failed to open the key!");
241     return false;
242   }
243   RegCloseKey(key);
244   return true;
245 #else
246   return false;
247 #endif
248 }
249
250 bool registry_configurator::delete_section(const astring &section_in)
251 {
252   FUNCDEF("delete_section");
253   if (!section_in.length()) return false;
254   astring section = fix_section(section_in);
255 //if the key doesn't exist, should that be a failure?
256 #ifdef __WIN32__
257   long ret = SHDeleteKey((HKEY)translate_hive(_hive),
258       to_unicode_temp(section));
259   if (ret != ERROR_SUCCESS) {
260     LOG("failed to delete the key!");
261     return false;
262   }
263   return true;
264 #else
265   return false;
266 #endif
267 }
268
269 bool registry_configurator::delete_entry(const astring &section_in,
270     const astring &entry)
271 {
272   FUNCDEF("delete_entry");
273   if (!section_in.length()) return false;
274   astring section = fix_section(section_in);
275   if (!entry) {}  // no problem.
276
277 #ifdef __WIN32__
278   HKEY key;
279   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
280       to_unicode_temp(section), 0, KEY_SET_VALUE, &key);
281   if (ret != ERROR_SUCCESS) {
282     LOG("failed to open the key!");
283     return false;
284   }
285
286   bool to_return = true;
287   ret = RegDeleteValue(key, to_unicode_temp(entry));
288   if (ret != ERROR_SUCCESS) {
289     LOG(astring("failed to delete the entry!"));
290     to_return = false;
291   }
292
293   RegCloseKey(key);
294   return to_return;
295 #else
296   return false;
297 #endif
298 }
299
300 bool registry_configurator::put_section(const astring &section_in,
301     const string_table &info)
302 {
303   if (!section_in) return false;
304   astring section = fix_section(section_in);
305   bool failures = false;
306   for (int i = 0; i < info.symbols(); i++) {
307     bool worked = put(section, info.name(i), info[i]);
308     if (!worked) failures = true;
309   }
310   return !failures;
311 }
312
313 } // namespace
314