Make touch-action apply to double-tap zoom
[chromium-blink-merge.git] / rlz / win / lib / rlz_value_store_registry.cc
blob2b50767a4a85a551221c5daa08fd5c07ffa1b98e
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.
5 #include "rlz/win/lib/rlz_value_store_registry.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/registry.h"
10 #include "rlz/lib/assert.h"
11 #include "rlz/lib/lib_values.h"
12 #include "rlz/lib/rlz_lib.h"
13 #include "rlz/lib/string_utils.h"
14 #include "rlz/win/lib/registry_util.h"
16 using base::ASCIIToWide;
18 namespace rlz_lib {
20 namespace {
23 // Registry keys:
25 // RLZ's are stored as:
26 // <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName.
28 // Events are stored as:
29 // <AccessPointName><EventName> = 1 @
30 // HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product).
32 // The OEM Deal Confirmation Code (DCC) is stored as
33 // kDccValueName = <DCC value> @ HKLM\kLibKeyName
35 // The last ping time, per product is stored as:
36 // GetProductName(product) = <last ping time> @
37 // HKCU\kLibKeyName\kPingTimesSubkeyName.
39 // The server does not care about any of these constants.
41 const char kLibKeyName[] = "Software\\Google\\Common\\Rlz";
42 const wchar_t kGoogleKeyName[] = L"Software\\Google";
43 const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common";
44 const char kRlzsSubkeyName[] = "RLZs";
45 const char kEventsSubkeyName[] = "Events";
46 const char kStatefulEventsSubkeyName[] = "StatefulEvents";
47 const char kPingTimesSubkeyName[] = "PTimes";
49 std::wstring GetWideProductName(Product product) {
50 return ASCIIToWide(GetProductName(product));
53 void AppendBrandToString(std::string* str) {
54 std::string brand(SupplementaryBranding::GetBrand());
55 if (!brand.empty())
56 base::StringAppendF(str, "\\_%s", brand.c_str());
59 // Function to get the specific registry keys.
60 bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) {
61 std::string key_location;
62 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name);
63 AppendBrandToString(&key_location);
65 LONG ret = ERROR_SUCCESS;
66 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
67 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
68 access);
69 } else {
70 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
71 access);
74 return ret == ERROR_SUCCESS;
77 bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) {
78 return GetRegKey(kPingTimesSubkeyName, access, key);
82 bool GetEventsRegKey(const char* event_type,
83 const rlz_lib::Product* product,
84 REGSAM access, base::win::RegKey* key) {
85 std::string key_location;
86 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName,
87 event_type);
88 AppendBrandToString(&key_location);
90 if (product != NULL) {
91 std::string product_name = GetProductName(*product);
92 if (product_name.empty())
93 return false;
95 base::StringAppendF(&key_location, "\\%s", product_name.c_str());
98 LONG ret = ERROR_SUCCESS;
99 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
100 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
101 access);
102 } else {
103 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
104 access);
107 return ret == ERROR_SUCCESS;
110 bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) {
111 return GetRegKey(kRlzsSubkeyName, access, key);
114 bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) {
115 std::wstring product_name = GetWideProductName(product);
116 if (product_name.empty())
117 return false;
119 base::win::RegKey reg_key;
120 GetEventsRegKey(key, NULL, KEY_WRITE, &reg_key);
121 reg_key.DeleteKey(product_name.c_str());
123 // Verify that the value no longer exists.
124 base::win::RegKey product_events(
125 reg_key.Handle(), product_name.c_str(), KEY_READ);
126 if (product_events.Valid()) {
127 ASSERT_STRING("ClearAllProductEvents: Key deletion failed");
128 return false;
131 return true;
134 // Deletes a registry key if it exists and has no subkeys or values.
135 // TODO: Move this to a registry_utils file and add unittest.
136 bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) {
137 if (!key_name) {
138 ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL");
139 return false;
140 } else { // Scope needed for RegKey
141 base::win::RegKey key(root_key, key_name, KEY_READ);
142 if (!key.Valid())
143 return true; // Key does not exist - nothing to do.
145 base::win::RegistryKeyIterator key_iter(root_key, key_name);
146 if (key_iter.SubkeyCount() > 0)
147 return true; // Not empty, so nothing to do
149 base::win::RegistryValueIterator value_iter(root_key, key_name);
150 if (value_iter.ValueCount() > 0)
151 return true; // Not empty, so nothing to do
154 // The key is empty - delete it now.
155 base::win::RegKey key(root_key, L"", KEY_WRITE);
156 return key.DeleteKey(key_name) == ERROR_SUCCESS;
159 } // namespace
161 // static
162 std::wstring RlzValueStoreRegistry::GetWideLibKeyName() {
163 return ASCIIToWide(kLibKeyName);
166 bool RlzValueStoreRegistry::HasAccess(AccessType type) {
167 return HasUserKeyAccess(type == kWriteAccess);
170 bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) {
171 base::win::RegKey key;
172 std::wstring product_name = GetWideProductName(product);
173 return GetPingTimesRegKey(KEY_WRITE, &key) &&
174 key.WriteValue(product_name.c_str(), &time, sizeof(time),
175 REG_QWORD) == ERROR_SUCCESS;
178 bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) {
179 base::win::RegKey key;
180 std::wstring product_name = GetWideProductName(product);
181 return GetPingTimesRegKey(KEY_READ, &key) &&
182 key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS;
185 bool RlzValueStoreRegistry::ClearPingTime(Product product) {
186 base::win::RegKey key;
187 GetPingTimesRegKey(KEY_WRITE, &key);
189 std::wstring product_name = GetWideProductName(product);
190 key.DeleteValue(product_name.c_str());
192 // Verify deletion.
193 uint64 value;
194 DWORD size = sizeof(value);
195 if (key.ReadValue(
196 product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) {
197 ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete.");
198 return false;
201 return true;
204 bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point,
205 const char* new_rlz) {
206 const char* access_point_name = GetAccessPointName(access_point);
207 if (!access_point_name)
208 return false;
210 std::wstring access_point_name_wide(ASCIIToWide(access_point_name));
211 base::win::RegKey key;
212 GetAccessPointRlzsRegKey(KEY_WRITE, &key);
214 if (!RegKeyWriteValue(key, access_point_name_wide.c_str(), new_rlz)) {
215 ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value");
216 return false;
218 return true;
221 bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point,
222 char* rlz,
223 size_t rlz_size) {
224 const char* access_point_name = GetAccessPointName(access_point);
225 if (!access_point_name)
226 return false;
228 size_t size = rlz_size;
229 base::win::RegKey key;
230 GetAccessPointRlzsRegKey(KEY_READ, &key);
231 if (!RegKeyReadValue(key, ASCIIToWide(access_point_name).c_str(),
232 rlz, &size)) {
233 rlz[0] = 0;
234 if (size > rlz_size) {
235 ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size");
236 return false;
239 return true;
242 bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) {
243 const char* access_point_name = GetAccessPointName(access_point);
244 if (!access_point_name)
245 return false;
247 std::wstring access_point_name_wide(ASCIIToWide(access_point_name));
248 base::win::RegKey key;
249 GetAccessPointRlzsRegKey(KEY_WRITE, &key);
251 key.DeleteValue(access_point_name_wide.c_str());
253 // Verify deletion.
254 DWORD value;
255 if (key.ReadValueDW(access_point_name_wide.c_str(), &value) ==
256 ERROR_SUCCESS) {
257 ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value.");
258 return false;
260 return true;
263 bool RlzValueStoreRegistry::AddProductEvent(Product product,
264 const char* event_rlz) {
265 std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
266 base::win::RegKey reg_key;
267 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &reg_key);
268 if (reg_key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) {
269 ASSERT_STRING("AddProductEvent: Could not write the new event value");
270 return false;
273 return true;
276 bool RlzValueStoreRegistry::ReadProductEvents(Product product,
277 std::vector<std::string>* events) {
278 // Open the events key.
279 base::win::RegKey events_key;
280 GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key);
281 if (!events_key.Valid())
282 return false;
284 // Append the events to the buffer.
285 int num_values = 0;
286 LONG result = ERROR_SUCCESS;
287 for (num_values = 0; result == ERROR_SUCCESS; ++num_values) {
288 // Max 32767 bytes according to MSDN, but we never use that much.
289 const size_t kMaxValueNameLength = 2048;
290 char buffer[kMaxValueNameLength];
291 DWORD size = arraysize(buffer);
293 result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size,
294 NULL, NULL, NULL, NULL);
295 if (result == ERROR_SUCCESS)
296 events->push_back(std::string(buffer));
299 return result == ERROR_NO_MORE_ITEMS;
302 bool RlzValueStoreRegistry::ClearProductEvent(Product product,
303 const char* event_rlz) {
304 std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
305 base::win::RegKey key;
306 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key);
307 key.DeleteValue(event_rlz_wide.c_str());
309 // Verify deletion.
310 DWORD value;
311 if (key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS) {
312 ASSERT_STRING("ClearProductEvent: Could not delete the event value.");
313 return false;
316 return true;
319 bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) {
320 return ClearAllProductEventValues(product, kEventsSubkeyName);
323 bool RlzValueStoreRegistry::AddStatefulEvent(Product product,
324 const char* event_rlz) {
325 base::win::RegKey key;
326 std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
327 if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) ||
328 key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) {
329 ASSERT_STRING(
330 "AddStatefulEvent: Could not write the new stateful event");
331 return false;
334 return true;
337 bool RlzValueStoreRegistry::IsStatefulEvent(Product product,
338 const char* event_rlz) {
339 DWORD value;
340 base::win::RegKey key;
341 GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key);
342 std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
343 return key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS;
346 bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) {
347 return ClearAllProductEventValues(product, kStatefulEventsSubkeyName);
350 void RlzValueStoreRegistry::CollectGarbage() {
351 // Delete each of the known subkeys if empty.
352 const char* subkeys[] = {
353 kRlzsSubkeyName,
354 kEventsSubkeyName,
355 kStatefulEventsSubkeyName,
356 kPingTimesSubkeyName
359 for (int i = 0; i < arraysize(subkeys); i++) {
360 std::string subkey_name;
361 base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]);
362 AppendBrandToString(&subkey_name);
364 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER,
365 ASCIIToWide(subkey_name).c_str()));
368 // Delete the library key and its parents too now if empty.
369 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str()));
370 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName));
371 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName));
374 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
375 if (!lock_.failed())
376 store_.reset(new RlzValueStoreRegistry);
379 ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
382 RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
383 return store_.get();
386 } // namespace rlz_lib