1// Copyright 2014 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 "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h"
6
7#include "base/prefs/pref_registry_simple.h"
8#include "base/prefs/pref_service.h"
9#include "base/prefs/scoped_user_pref_update.h"
10#include "base/values.h"
11
12namespace {
13
14// Implements get-or-create of a dictionary value and holds a
15// DictionaryPrefUpdate.
16class PrefServiceMutableDictionary
17    : public HashStoreContents::MutableDictionary {
18 public:
19  // Creates an instance that provides mutable access to a dictionary value
20  // named |key| that is a child of |kProfilePreferenceHashes| in
21  // |prefs|.
22  PrefServiceMutableDictionary(const std::string& key,
23                               PrefService* pref_service);
24
25  // HashStoreContents::MutableDictionary implementation
26  virtual base::DictionaryValue* operator->() OVERRIDE;
27
28 private:
29  const std::string key_;
30  DictionaryPrefUpdate update_;
31};
32
33PrefServiceMutableDictionary::PrefServiceMutableDictionary(
34    const std::string& key,
35    PrefService* pref_service)
36    : key_(key),
37      update_(pref_service,
38              PrefServiceHashStoreContents::kProfilePreferenceHashes) {
39  DCHECK(!key_.empty());
40}
41
42base::DictionaryValue* PrefServiceMutableDictionary::operator->() {
43  base::DictionaryValue* dictionary = NULL;
44  if (!update_->GetDictionaryWithoutPathExpansion(key_, &dictionary)) {
45    dictionary = new base::DictionaryValue;
46    update_->SetWithoutPathExpansion(key_, dictionary);
47  }
48  return dictionary;
49}
50
51}  // namespace
52
53// static
54const char PrefServiceHashStoreContents::kProfilePreferenceHashes[] =
55    "profile.preference_hashes";
56
57// static
58const char PrefServiceHashStoreContents::kHashOfHashesDict[] = "hash_of_hashes";
59
60// static
61const char PrefServiceHashStoreContents::kStoreVersionsDict[] =
62    "store_versions";
63
64PrefServiceHashStoreContents::PrefServiceHashStoreContents(
65    const std::string& hash_store_id,
66    PrefService* pref_service)
67    : hash_store_id_(hash_store_id), pref_service_(pref_service) {
68  // TODO(erikwright): Remove in M40+.
69  DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes);
70  update->RemovePath(kStoreVersionsDict, NULL);
71}
72
73// static
74void PrefServiceHashStoreContents::RegisterPrefs(PrefRegistrySimple* registry) {
75  // Register the top level dictionary to map profile names to dictionaries of
76  // tracked preferences.
77  registry->RegisterDictionaryPref(kProfilePreferenceHashes);
78}
79
80// static
81void PrefServiceHashStoreContents::ResetAllPrefHashStores(
82    PrefService* pref_service) {
83  pref_service->ClearPref(kProfilePreferenceHashes);
84}
85
86std::string PrefServiceHashStoreContents::hash_store_id() const {
87  return hash_store_id_;
88}
89
90void PrefServiceHashStoreContents::Reset() {
91  DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes);
92
93  update->RemoveWithoutPathExpansion(hash_store_id_, NULL);
94
95  // Remove this store's entry in the kHashOfHashesDict.
96  base::DictionaryValue* hash_of_hashes_dict;
97  if (update->GetDictionaryWithoutPathExpansion(kHashOfHashesDict,
98                                                &hash_of_hashes_dict)) {
99    hash_of_hashes_dict->RemoveWithoutPathExpansion(hash_store_id_, NULL);
100    if (hash_of_hashes_dict->empty())
101      update->RemovePath(kHashOfHashesDict, NULL);
102  }
103
104  if (update->empty())
105    pref_service_->ClearPref(kProfilePreferenceHashes);
106}
107
108bool PrefServiceHashStoreContents::IsInitialized() const {
109  const base::DictionaryValue* pref_hash_dicts =
110      pref_service_->GetDictionary(kProfilePreferenceHashes);
111  return pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_,
112                                                            NULL);
113}
114
115const base::DictionaryValue* PrefServiceHashStoreContents::GetContents() const {
116  const base::DictionaryValue* pref_hash_dicts =
117      pref_service_->GetDictionary(kProfilePreferenceHashes);
118  const base::DictionaryValue* hashes_dict = NULL;
119  pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_,
120                                                     &hashes_dict);
121  return hashes_dict;
122}
123
124scoped_ptr<HashStoreContents::MutableDictionary>
125PrefServiceHashStoreContents::GetMutableContents() {
126  return scoped_ptr<HashStoreContents::MutableDictionary>(
127      new PrefServiceMutableDictionary(hash_store_id_, pref_service_));
128}
129
130std::string PrefServiceHashStoreContents::GetSuperMac() const {
131  const base::DictionaryValue* pref_hash_dicts =
132      pref_service_->GetDictionary(kProfilePreferenceHashes);
133  const base::DictionaryValue* hash_of_hashes_dict = NULL;
134  std::string hash_of_hashes;
135  if (pref_hash_dicts->GetDictionaryWithoutPathExpansion(
136          kHashOfHashesDict, &hash_of_hashes_dict)) {
137    hash_of_hashes_dict->GetStringWithoutPathExpansion(hash_store_id_,
138                                                       &hash_of_hashes);
139  }
140  return hash_of_hashes;
141}
142
143void PrefServiceHashStoreContents::SetSuperMac(const std::string& super_mac) {
144  PrefServiceMutableDictionary(kHashOfHashesDict, pref_service_)
145      ->SetStringWithoutPathExpansion(hash_store_id_, super_mac);
146}
147