- add sources.
[platform/framework/web/crosswalk.git] / src / base / win / registry.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/win/registry.h"
6
7 #include <shlwapi.h>
8 #include <algorithm>
9
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_restrictions.h"
13
14 #pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey
15
16 namespace base {
17 namespace win {
18
19 namespace {
20
21 // RegEnumValue() reports the number of characters from the name that were
22 // written to the buffer, not how many there are. This constant is the maximum
23 // name size, such that a buffer with this size should read any name.
24 const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
25
26 // Registry values are read as BYTE* but can have wchar_t* data whose last
27 // wchar_t is truncated. This function converts the reported |byte_size| to
28 // a size in wchar_t that can store a truncated wchar_t if necessary.
29 inline DWORD to_wchar_size(DWORD byte_size) {
30   return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
31 }
32
33 }  // namespace
34
35 // RegKey ----------------------------------------------------------------------
36
37 RegKey::RegKey()
38     : key_(NULL),
39       watch_event_(0) {
40 }
41
42 RegKey::RegKey(HKEY key)
43     : key_(key),
44       watch_event_(0) {
45 }
46
47 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
48     : key_(NULL),
49       watch_event_(0) {
50   if (rootkey) {
51     if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
52       Create(rootkey, subkey, access);
53     else
54       Open(rootkey, subkey, access);
55   } else {
56     DCHECK(!subkey);
57   }
58 }
59
60 RegKey::~RegKey() {
61   Close();
62 }
63
64 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
65   DWORD disposition_value;
66   return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
67 }
68
69 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
70                                    DWORD* disposition, REGSAM access) {
71   DCHECK(rootkey && subkey && access && disposition);
72   Close();
73
74   LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
75                                REG_OPTION_NON_VOLATILE, access, NULL, &key_,
76                                disposition);
77   return result;
78 }
79
80 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
81   DCHECK(name && access);
82   HKEY subkey = NULL;
83   LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
84                                access, NULL, &subkey, NULL);
85   Close();
86
87   key_ = subkey;
88   return result;
89 }
90
91 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
92   DCHECK(rootkey && subkey && access);
93   Close();
94
95   LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
96   return result;
97 }
98
99 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
100   DCHECK(relative_key_name && access);
101   HKEY subkey = NULL;
102   LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
103
104   // We have to close the current opened key before replacing it with the new
105   // one.
106   Close();
107
108   key_ = subkey;
109   return result;
110 }
111
112 void RegKey::Close() {
113   StopWatching();
114   if (key_) {
115     ::RegCloseKey(key_);
116     key_ = NULL;
117   }
118 }
119
120 void RegKey::Set(HKEY key) {
121   if (key_ != key) {
122     Close();
123     key_ = key;
124   }
125 }
126
127 HKEY RegKey::Take() {
128   StopWatching();
129   HKEY key = key_;
130   key_ = NULL;
131   return key;
132 }
133
134 bool RegKey::HasValue(const wchar_t* name) const {
135   return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
136 }
137
138 DWORD RegKey::GetValueCount() const {
139   DWORD count = 0;
140   LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
141                                 NULL, NULL, NULL, NULL);
142   return (result == ERROR_SUCCESS) ? count : 0;
143 }
144
145 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
146   wchar_t buf[256];
147   DWORD bufsize = arraysize(buf);
148   LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
149   if (r == ERROR_SUCCESS)
150     *name = buf;
151
152   return r;
153 }
154
155 LONG RegKey::DeleteKey(const wchar_t* name) {
156   DCHECK(key_);
157   DCHECK(name);
158   LONG result = SHDeleteKey(key_, name);
159   return result;
160 }
161
162 LONG RegKey::DeleteValue(const wchar_t* value_name) {
163   DCHECK(key_);
164   LONG result = RegDeleteValue(key_, value_name);
165   return result;
166 }
167
168 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
169   DCHECK(out_value);
170   DWORD type = REG_DWORD;
171   DWORD size = sizeof(DWORD);
172   DWORD local_value = 0;
173   LONG result = ReadValue(name, &local_value, &size, &type);
174   if (result == ERROR_SUCCESS) {
175     if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
176       *out_value = local_value;
177     else
178       result = ERROR_CANTREAD;
179   }
180
181   return result;
182 }
183
184 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
185   DCHECK(out_value);
186   DWORD type = REG_QWORD;
187   int64 local_value = 0;
188   DWORD size = sizeof(local_value);
189   LONG result = ReadValue(name, &local_value, &size, &type);
190   if (result == ERROR_SUCCESS) {
191     if ((type == REG_QWORD || type == REG_BINARY) &&
192         size == sizeof(local_value))
193       *out_value = local_value;
194     else
195       result = ERROR_CANTREAD;
196   }
197
198   return result;
199 }
200
201 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
202   DCHECK(out_value);
203   const size_t kMaxStringLength = 1024;  // This is after expansion.
204   // Use the one of the other forms of ReadValue if 1024 is too small for you.
205   wchar_t raw_value[kMaxStringLength];
206   DWORD type = REG_SZ, size = sizeof(raw_value);
207   LONG result = ReadValue(name, raw_value, &size, &type);
208   if (result == ERROR_SUCCESS) {
209     if (type == REG_SZ) {
210       *out_value = raw_value;
211     } else if (type == REG_EXPAND_SZ) {
212       wchar_t expanded[kMaxStringLength];
213       size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
214       // Success: returns the number of wchar_t's copied
215       // Fail: buffer too small, returns the size required
216       // Fail: other, returns 0
217       if (size == 0 || size > kMaxStringLength) {
218         result = ERROR_MORE_DATA;
219       } else {
220         *out_value = expanded;
221       }
222     } else {
223       // Not a string. Oops.
224       result = ERROR_CANTREAD;
225     }
226   }
227
228   return result;
229 }
230
231 LONG RegKey::ReadValue(const wchar_t* name,
232                        void* data,
233                        DWORD* dsize,
234                        DWORD* dtype) const {
235   LONG result = RegQueryValueEx(key_, name, 0, dtype,
236                                 reinterpret_cast<LPBYTE>(data), dsize);
237   return result;
238 }
239
240 LONG RegKey::ReadValues(const wchar_t* name,
241                         std::vector<std::wstring>* values) {
242   values->clear();
243
244   DWORD type = REG_MULTI_SZ;
245   DWORD size = 0;
246   LONG result = ReadValue(name, NULL, &size, &type);
247   if (FAILED(result) || size == 0)
248     return result;
249
250   if (type != REG_MULTI_SZ)
251     return ERROR_CANTREAD;
252
253   std::vector<wchar_t> buffer(size / sizeof(wchar_t));
254   result = ReadValue(name, &buffer[0], &size, NULL);
255   if (FAILED(result) || size == 0)
256     return result;
257
258   // Parse the double-null-terminated list of strings.
259   // Note: This code is paranoid to not read outside of |buf|, in the case where
260   // it may not be properly terminated.
261   const wchar_t* entry = &buffer[0];
262   const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
263   while (entry < buffer_end && entry[0] != '\0') {
264     const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
265     values->push_back(std::wstring(entry, entry_end));
266     entry = entry_end + 1;
267   }
268   return 0;
269 }
270
271 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
272   return WriteValue(
273       name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
274 }
275
276 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
277   return WriteValue(name, in_value,
278       static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
279 }
280
281 LONG RegKey::WriteValue(const wchar_t* name,
282                         const void* data,
283                         DWORD dsize,
284                         DWORD dtype) {
285   DCHECK(data || !dsize);
286
287   LONG result = RegSetValueEx(key_, name, 0, dtype,
288       reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
289   return result;
290 }
291
292 LONG RegKey::StartWatching() {
293   DCHECK(key_);
294   if (!watch_event_)
295     watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
296
297   DWORD filter = REG_NOTIFY_CHANGE_NAME |
298                  REG_NOTIFY_CHANGE_ATTRIBUTES |
299                  REG_NOTIFY_CHANGE_LAST_SET |
300                  REG_NOTIFY_CHANGE_SECURITY;
301
302   // Watch the registry key for a change of value.
303   LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
304   if (result != ERROR_SUCCESS) {
305     CloseHandle(watch_event_);
306     watch_event_ = 0;
307   }
308
309   return result;
310 }
311
312 bool RegKey::HasChanged() {
313   if (watch_event_) {
314     if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
315       StartWatching();
316       return true;
317     }
318   }
319   return false;
320 }
321
322 LONG RegKey::StopWatching() {
323   LONG result = ERROR_INVALID_HANDLE;
324   if (watch_event_) {
325     CloseHandle(watch_event_);
326     watch_event_ = 0;
327     result = ERROR_SUCCESS;
328   }
329   return result;
330 }
331
332 // RegistryValueIterator ------------------------------------------------------
333
334 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
335                                              const wchar_t* folder_key)
336     : name_(MAX_PATH, L'\0'),
337       value_(MAX_PATH, L'\0') {
338   LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
339   if (result != ERROR_SUCCESS) {
340     key_ = NULL;
341   } else {
342     DWORD count = 0;
343     result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
344                                NULL, NULL, NULL, NULL);
345
346     if (result != ERROR_SUCCESS) {
347       ::RegCloseKey(key_);
348       key_ = NULL;
349     } else {
350       index_ = count - 1;
351     }
352   }
353
354   Read();
355 }
356
357 RegistryValueIterator::~RegistryValueIterator() {
358   if (key_)
359     ::RegCloseKey(key_);
360 }
361
362 DWORD RegistryValueIterator::ValueCount() const {
363   DWORD count = 0;
364   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
365                                   &count, NULL, NULL, NULL, NULL);
366   if (result != ERROR_SUCCESS)
367     return 0;
368
369   return count;
370 }
371
372 bool RegistryValueIterator::Valid() const {
373   return key_ != NULL && index_ >= 0;
374 }
375
376 void RegistryValueIterator::operator++() {
377   --index_;
378   Read();
379 }
380
381 bool RegistryValueIterator::Read() {
382   if (Valid()) {
383     DWORD capacity = static_cast<DWORD>(name_.capacity());
384     DWORD name_size = capacity;
385     // |value_size_| is in bytes. Reserve the last character for a NUL.
386     value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
387     LONG result = ::RegEnumValue(
388         key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
389         reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
390
391     if (result == ERROR_MORE_DATA) {
392       // Registry key names are limited to 255 characters and fit within
393       // MAX_PATH (which is 260) but registry value names can use up to 16,383
394       // characters and the value itself is not limited
395       // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
396       // ms724872(v=vs.85).aspx).
397       // Resize the buffers and retry if their size caused the failure.
398       DWORD value_size_in_wchars = to_wchar_size(value_size_);
399       if (value_size_in_wchars + 1 > value_.size())
400         value_.resize(value_size_in_wchars + 1, L'\0');
401       value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
402       name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
403       result = ::RegEnumValue(
404           key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
405           reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
406     }
407
408     if (result == ERROR_SUCCESS) {
409       DCHECK_LT(to_wchar_size(value_size_), value_.size());
410       value_[to_wchar_size(value_size_)] = L'\0';
411       return true;
412     }
413   }
414
415   name_[0] = L'\0';
416   value_[0] = L'\0';
417   value_size_ = 0;
418   return false;
419 }
420
421 // RegistryKeyIterator --------------------------------------------------------
422
423 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
424                                          const wchar_t* folder_key) {
425   LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
426   if (result != ERROR_SUCCESS) {
427     key_ = NULL;
428   } else {
429     DWORD count = 0;
430     LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
431                                     NULL, NULL, NULL, NULL, NULL);
432
433     if (result != ERROR_SUCCESS) {
434       ::RegCloseKey(key_);
435       key_ = NULL;
436     } else {
437       index_ = count - 1;
438     }
439   }
440
441   Read();
442 }
443
444 RegistryKeyIterator::~RegistryKeyIterator() {
445   if (key_)
446     ::RegCloseKey(key_);
447 }
448
449 DWORD RegistryKeyIterator::SubkeyCount() const {
450   DWORD count = 0;
451   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
452                                   NULL, NULL, NULL, NULL, NULL);
453   if (result != ERROR_SUCCESS)
454     return 0;
455
456   return count;
457 }
458
459 bool RegistryKeyIterator::Valid() const {
460   return key_ != NULL && index_ >= 0;
461 }
462
463 void RegistryKeyIterator::operator++() {
464   --index_;
465   Read();
466 }
467
468 bool RegistryKeyIterator::Read() {
469   if (Valid()) {
470     DWORD ncount = arraysize(name_);
471     FILETIME written;
472     LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
473                             NULL, &written);
474     if (ERROR_SUCCESS == r)
475       return true;
476   }
477
478   name_[0] = '\0';
479   return false;
480 }
481
482 }  // namespace win
483 }  // namespace base