updates from orpheus for windoze build
[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 _MSC_VER
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 //SAFE_STATIC_CONST(astring, registry_configurator::reg_str_fake_default,
55  //   ("bogus_never_should_see"));
56 const astring &registry_configurator::reg_str_fake_default()
57 {
58   static astring _hidden = "bogus_never_should_see";
59   return _hidden;
60 }
61
62 registry_configurator::registry_configurator(registry_hives hive,
63       treatment_of_defaults behavior)
64 : configurator(behavior),
65   _hive(hive)
66 {}
67
68 registry_configurator::~registry_configurator()
69 {}
70
71 #ifndef __WIN32__
72 // fake the platform dependent names.
73 void *HKEY_CLASSES_ROOT = NULL;
74 void *HKEY_CURRENT_USER = NULL;
75 void *HKEY_LOCAL_MACHINE = NULL;
76 void *HKEY_USERS = NULL;
77 void *HKEY_CURRENT_CONFIG = NULL;
78 #endif
79
80 void *registry_configurator::translate_hive(registry_hives hive)
81 {
82   switch (hive) {
83     case hkey_classes_root: return HKEY_CLASSES_ROOT;
84     case hkey_current_user: return HKEY_CURRENT_USER;
85     case hkey_local_machine: return HKEY_LOCAL_MACHINE;
86     case hkey_users: return HKEY_USERS;
87     case hkey_current_config: return HKEY_CURRENT_CONFIG;
88     default: return 0;
89   }
90 }
91
92 astring registry_configurator::fix_section(const astring &section)
93 {
94   astring to_return = section;
95   for (int i = 0; i < to_return.length(); i++) {
96     if (to_return[i] == '/')
97       to_return[i] = '\\';
98   }
99   return to_return;
100 }
101
102 bool registry_configurator::put(const astring &section_in, const astring &entry,
103     const astring &to_store)
104 {
105   FUNCDEF("put");
106   astring section = fix_section(section_in);
107   if (!to_store.length()) return delete_entry(section, entry);
108   else if (!section.length()) return false;
109
110 #ifdef _MSC_VER
111   HKEY key;
112   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
113       to_unicode_temp(section), 0, KEY_WRITE, &key);
114   if (ret != ERROR_SUCCESS) {
115     LOG("failed to open the key, trying to create it.");
116     DWORD dispose;  // the disposition of the call (created or existing).
117     ret = RegCreateKeyEx((HKEY)translate_hive(_hive),
118         to_unicode_temp(section), 0, NULL_POINTER, REG_OPTION_NON_VOLATILE,
119         KEY_ALL_ACCESS, NULL_POINTER, &key, &dispose);
120     if (ret != ERROR_SUCCESS) {
121       LOG("failed to create the key!!");
122       return false;
123     }
124   }
125
126   bool to_return = true;
127   ret = RegSetValueEx(key, to_unicode_temp(entry), 0, REG_SZ,
128       (byte *)to_store.s(), to_store.length() + 1);
129   if (ret != ERROR_SUCCESS) {
130     LOG(astring("failed to write the entry!"));
131     to_return = false;
132   }
133
134   RegCloseKey(key);
135   return to_return;
136 #else
137   return false;
138 #endif
139 }
140
141 bool registry_configurator::get(const astring &section_in, const astring &entry,
142     astring &found)
143 {
144   FUNCDEF("get");
145   found = "";
146   if (!section_in) return false;
147   if (!entry) {}  // not a problem.
148   astring section = fix_section(section_in);
149 #ifdef _MSC_VER
150   HKEY key;
151   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
152       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
153   if (ret != ERROR_SUCCESS) {
154     LOG("failed to open the key!");
155     return false;
156   }
157
158   DWORD type_seen;
159   byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
160   DWORD length = MAXIMUM_ENTRY_SIZE - 1;
161   ret = RegQueryValueEx(key, to_unicode_temp(entry), 0, &type_seen, data_seen,
162       &length);
163   if (ret != ERROR_SUCCESS) {
164     LOG(astring("failed to read the entry!"));
165     return false;
166   }
167
168   if (type_seen != REG_SZ) {
169     LOG(astring("entry found was not of string type!"));
170     RegCloseKey(key);
171     return false;
172   }
173
174   data_seen[MAXIMUM_ENTRY_SIZE - 1] = '\0';
175     // force last character to be null if data happened to be too big.
176   found = astring((char *)data_seen);
177
178   delete [] data_seen;
179
180   RegCloseKey(key);
181   return true;
182 #else
183   return false;
184 #endif
185 }
186
187 bool registry_configurator::get_section(const astring &section_in,
188     string_table &info)
189 {
190   FUNCDEF("get_section");
191   info.reset();
192   if (!section_in.length()) return false;
193   astring section = fix_section(section_in);
194 #ifdef _MSC_VER
195   HKEY key;
196   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
197       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
198   if (ret != ERROR_SUCCESS) {
199     LOG("failed to open the key!");
200     return false;
201   }
202
203   DWORD type_seen;
204   byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
205   flexichar *name_seen = new flexichar[MAXIMUM_NAME_SIZE];
206   DWORD name_length;
207   for (DWORD index = 0; true; index++) {
208     DWORD length = MAXIMUM_ENTRY_SIZE - 1;
209     name_length = MAXIMUM_NAME_SIZE - 1;
210     LONG ret = RegEnumValue(key, index, name_seen, &name_length, 0,
211         &type_seen, data_seen, &length);
212     if (ret != ERROR_SUCCESS) break;  // no entry at that index.
213     if (type_seen == REG_SZ) {
214       // found an entry successfully and it's the right type.
215       astring name = from_unicode_temp(name_seen);
216       astring content = from_unicode_temp((flexichar *)data_seen);
217       info.add(name, content);
218     }
219   }
220
221   delete [] data_seen;
222   delete [] name_seen;
223
224   RegCloseKey(key);
225
226   return true;
227 #else
228   return false;
229 #endif
230 }
231
232 bool registry_configurator::section_exists(const astring &section_in)
233 {
234   FUNCDEF("section_exists");
235   if (!section_in.length()) return false;
236   astring section = fix_section(section_in);
237 #ifdef _MSC_VER
238   HKEY key;
239   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
240       to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
241   if (ret != ERROR_SUCCESS) {
242     LOG("failed to open the key!");
243     return false;
244   }
245   RegCloseKey(key);
246   return true;
247 #else
248   return false;
249 #endif
250 }
251
252 bool registry_configurator::delete_section(const astring &section_in)
253 {
254   FUNCDEF("delete_section");
255   if (!section_in.length()) return false;
256   astring section = fix_section(section_in);
257 //if the key doesn't exist, should that be a failure?
258 #ifdef _MSC_VER
259   long ret = SHDeleteKey((HKEY)translate_hive(_hive),
260       to_unicode_temp(section));
261   if (ret != ERROR_SUCCESS) {
262     LOG("failed to delete the key!");
263     return false;
264   }
265   return true;
266 #else
267   return false;
268 #endif
269 }
270
271 bool registry_configurator::delete_entry(const astring &section_in,
272     const astring &entry)
273 {
274   FUNCDEF("delete_entry");
275   if (!section_in.length()) return false;
276   astring section = fix_section(section_in);
277   if (!entry) {}  // no problem.
278
279 #ifdef _MSC_VER
280   HKEY key;
281   long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
282       to_unicode_temp(section), 0, KEY_SET_VALUE, &key);
283   if (ret != ERROR_SUCCESS) {
284     LOG("failed to open the key!");
285     return false;
286   }
287
288   bool to_return = true;
289   ret = RegDeleteValue(key, to_unicode_temp(entry));
290   if (ret != ERROR_SUCCESS) {
291     LOG(astring("failed to delete the entry!"));
292     to_return = false;
293   }
294
295   RegCloseKey(key);
296   return to_return;
297 #else
298   return false;
299 #endif
300 }
301
302 bool registry_configurator::put_section(const astring &section_in,
303     const string_table &info)
304 {
305   if (!section_in) return false;
306   astring section = fix_section(section_in);
307   bool failures = false;
308   for (int i = 0; i < info.symbols(); i++) {
309     bool worked = put(section, info.name(i), info[i]);
310     if (!worked) failures = true;
311   }
312   return !failures;
313 }
314
315 } // namespace
316