1// Copyright 2013 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 "components/policy/core/common/policy_map.h"
6
7#include <algorithm>
8
9#include "base/callback.h"
10#include "base/stl_util.h"
11
12namespace policy {
13
14PolicyMap::Entry::Entry()
15    : level(POLICY_LEVEL_RECOMMENDED),
16      scope(POLICY_SCOPE_USER),
17      value(NULL),
18      external_data_fetcher(NULL) {}
19
20void PolicyMap::Entry::DeleteOwnedMembers() {
21  delete value;
22  value = NULL;
23  delete external_data_fetcher;
24  external_data_fetcher = NULL;
25}
26
27scoped_ptr<PolicyMap::Entry> PolicyMap::Entry::DeepCopy() const {
28  scoped_ptr<Entry> copy(new Entry);
29  copy->level = level;
30  copy->scope = scope;
31  if (value)
32    copy->value = value->DeepCopy();
33  if (external_data_fetcher) {
34    copy->external_data_fetcher =
35        new ExternalDataFetcher(*external_data_fetcher);
36  }
37  return copy.Pass();
38}
39
40bool PolicyMap::Entry::has_higher_priority_than(
41    const PolicyMap::Entry& other) const {
42  if (level == other.level)
43    return scope > other.scope;
44  else
45    return level > other.level;
46}
47
48bool PolicyMap::Entry::Equals(const PolicyMap::Entry& other) const {
49  return level == other.level &&
50         scope == other.scope &&
51         base::Value::Equals(value, other.value) &&
52         ExternalDataFetcher::Equals(external_data_fetcher,
53                                     other.external_data_fetcher);
54}
55
56PolicyMap::PolicyMap() {
57}
58
59PolicyMap::~PolicyMap() {
60  Clear();
61}
62
63const PolicyMap::Entry* PolicyMap::Get(const std::string& policy) const {
64  PolicyMapType::const_iterator entry = map_.find(policy);
65  return entry == map_.end() ? NULL : &entry->second;
66}
67
68const base::Value* PolicyMap::GetValue(const std::string& policy) const {
69  PolicyMapType::const_iterator entry = map_.find(policy);
70  return entry == map_.end() ? NULL : entry->second.value;
71}
72
73void PolicyMap::Set(const std::string& policy,
74                    PolicyLevel level,
75                    PolicyScope scope,
76                    base::Value* value,
77                    ExternalDataFetcher* external_data_fetcher) {
78  Entry& entry = map_[policy];
79  entry.DeleteOwnedMembers();
80  entry.level = level;
81  entry.scope = scope;
82  entry.value = value;
83  entry.external_data_fetcher = external_data_fetcher;
84}
85
86void PolicyMap::Erase(const std::string& policy) {
87  PolicyMapType::iterator it = map_.find(policy);
88  if (it != map_.end()) {
89    it->second.DeleteOwnedMembers();
90    map_.erase(it);
91  }
92}
93
94void PolicyMap::Swap(PolicyMap* other) {
95  map_.swap(other->map_);
96}
97
98void PolicyMap::CopyFrom(const PolicyMap& other) {
99  Clear();
100  for (const_iterator it = other.begin(); it != other.end(); ++it) {
101    const Entry& entry = it->second;
102    Set(it->first, entry.level, entry.scope,
103        entry.value->DeepCopy(), entry.external_data_fetcher ?
104            new ExternalDataFetcher(*entry.external_data_fetcher) : NULL);
105  }
106}
107
108scoped_ptr<PolicyMap> PolicyMap::DeepCopy() const {
109  PolicyMap* copy = new PolicyMap();
110  copy->CopyFrom(*this);
111  return make_scoped_ptr(copy);
112}
113
114void PolicyMap::MergeFrom(const PolicyMap& other) {
115  for (const_iterator it = other.begin(); it != other.end(); ++it) {
116    const Entry* entry = Get(it->first);
117    if (!entry || it->second.has_higher_priority_than(*entry)) {
118      Set(it->first, it->second.level, it->second.scope,
119          it->second.value->DeepCopy(), it->second.external_data_fetcher ?
120              new ExternalDataFetcher(*it->second.external_data_fetcher) :
121              NULL);
122    }
123  }
124}
125
126void PolicyMap::LoadFrom(
127    const base::DictionaryValue* policies,
128    PolicyLevel level,
129    PolicyScope scope) {
130  for (base::DictionaryValue::Iterator it(*policies);
131       !it.IsAtEnd(); it.Advance()) {
132    Set(it.key(), level, scope, it.value().DeepCopy(), NULL);
133  }
134}
135
136void PolicyMap::GetDifferingKeys(const PolicyMap& other,
137                                 std::set<std::string>* differing_keys) const {
138  // Walk over the maps in lockstep, adding everything that is different.
139  const_iterator iter_this(begin());
140  const_iterator iter_other(other.begin());
141  while (iter_this != end() && iter_other != other.end()) {
142    const int diff = iter_this->first.compare(iter_other->first);
143    if (diff == 0) {
144      if (!iter_this->second.Equals(iter_other->second))
145        differing_keys->insert(iter_this->first);
146      ++iter_this;
147      ++iter_other;
148    } else if (diff < 0) {
149      differing_keys->insert(iter_this->first);
150      ++iter_this;
151    } else {
152      differing_keys->insert(iter_other->first);
153      ++iter_other;
154    }
155  }
156
157  // Add the remaining entries.
158  for ( ; iter_this != end(); ++iter_this)
159      differing_keys->insert(iter_this->first);
160  for ( ; iter_other != other.end(); ++iter_other)
161      differing_keys->insert(iter_other->first);
162}
163
164void PolicyMap::FilterLevel(PolicyLevel level) {
165  PolicyMapType::iterator iter(map_.begin());
166  while (iter != map_.end()) {
167    if (iter->second.level != level) {
168      iter->second.DeleteOwnedMembers();
169      map_.erase(iter++);
170    } else {
171      ++iter;
172    }
173  }
174}
175
176bool PolicyMap::Equals(const PolicyMap& other) const {
177  return other.size() == size() &&
178      std::equal(begin(), end(), other.begin(), MapEntryEquals);
179}
180
181bool PolicyMap::empty() const {
182  return map_.empty();
183}
184
185size_t PolicyMap::size() const {
186  return map_.size();
187}
188
189PolicyMap::const_iterator PolicyMap::begin() const {
190  return map_.begin();
191}
192
193PolicyMap::const_iterator PolicyMap::end() const {
194  return map_.end();
195}
196
197void PolicyMap::Clear() {
198  for (PolicyMapType::iterator it = map_.begin(); it != map_.end(); ++it)
199    it->second.DeleteOwnedMembers();
200  map_.clear();
201}
202
203// static
204bool PolicyMap::MapEntryEquals(const PolicyMap::PolicyMapType::value_type& a,
205                               const PolicyMap::PolicyMapType::value_type& b) {
206  return a.first == b.first && a.second.Equals(b.second);
207}
208
209}  // namespace policy
210