Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / policy / core / common / registry_dict_win.cc
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/registry_dict_win.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/sys_byteorder.h"
13 #include "base/values.h"
14 #include "base/win/registry.h"
15 #include "components/policy/core/common/schema.h"
16
17 using base::win::RegistryKeyIterator;
18 using base::win::RegistryValueIterator;
19
20 namespace policy {
21
22 namespace {
23
24 // Converts a value (as read from the registry) to meet |schema|, converting
25 // types as necessary. Unconvertible types will show up as NULL values in the
26 // result.
27 scoped_ptr<base::Value> ConvertValue(const base::Value& value,
28                                      const Schema& schema) {
29   if (!schema.valid())
30     return make_scoped_ptr(value.DeepCopy()).Pass();
31
32   // If the type is good already, go with it.
33   if (value.IsType(schema.type())) {
34     // Recurse for complex types.
35     const base::DictionaryValue* dict = NULL;
36     const base::ListValue* list = NULL;
37     if (value.GetAsDictionary(&dict)) {
38       scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
39       for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
40            entry.Advance()) {
41         scoped_ptr<base::Value> converted =
42             ConvertValue(entry.value(), schema.GetProperty(entry.key()));
43         if (converted)
44           result->SetWithoutPathExpansion(entry.key(), converted.release());
45       }
46       return result.PassAs<base::Value>();
47     } else if (value.GetAsList(&list)) {
48       scoped_ptr<base::ListValue> result(new base::ListValue());
49       for (base::ListValue::const_iterator entry(list->begin());
50            entry != list->end(); ++entry) {
51         scoped_ptr<base::Value> converted =
52             ConvertValue(**entry, schema.GetItems());
53         if (converted)
54           result->Append(converted.release());
55       }
56       return result.PassAs<base::Value>();
57     }
58     return make_scoped_ptr(value.DeepCopy()).Pass();
59   }
60
61   // Else, do some conversions to map windows registry data types to JSON types.
62   std::string string_value;
63   int int_value = 0;
64   switch (schema.type()) {
65     case base::Value::TYPE_NULL: {
66       return make_scoped_ptr(base::Value::CreateNullValue()).Pass();
67     }
68     case base::Value::TYPE_BOOLEAN: {
69       // Accept booleans encoded as either string or integer.
70       if (value.GetAsInteger(&int_value) ||
71           (value.GetAsString(&string_value) &&
72            base::StringToInt(string_value, &int_value))) {
73         return scoped_ptr<base::Value>(
74             new base::FundamentalValue(int_value != 0));
75       }
76       break;
77     }
78     case base::Value::TYPE_INTEGER: {
79       // Integers may be string-encoded.
80       if (value.GetAsString(&string_value) &&
81           base::StringToInt(string_value, &int_value)) {
82         return scoped_ptr<base::Value>(new base::FundamentalValue(int_value));
83       }
84       break;
85     }
86     case base::Value::TYPE_DOUBLE: {
87       // Doubles may be string-encoded or integer-encoded.
88       double double_value = 0;
89       if (value.GetAsDouble(&double_value) ||
90           (value.GetAsString(&string_value) &&
91            base::StringToDouble(string_value, &double_value))) {
92         return scoped_ptr<base::Value>(
93             new base::FundamentalValue(double_value));
94       }
95       break;
96     }
97     case base::Value::TYPE_LIST: {
98       // Lists are encoded as subkeys with numbered value in the registry.
99       const base::DictionaryValue* dict = NULL;
100       if (value.GetAsDictionary(&dict)) {
101         scoped_ptr<base::ListValue> result(new base::ListValue());
102         for (int i = 1; ; ++i) {
103           const base::Value* entry = NULL;
104           if (!dict->Get(base::IntToString(i), &entry))
105             break;
106           scoped_ptr<base::Value> converted =
107               ConvertValue(*entry, schema.GetItems());
108           if (converted)
109             result->Append(converted.release());
110         }
111         return result.PassAs<base::Value>();
112       }
113       // Fall through in order to accept lists encoded as JSON strings.
114     }
115     case base::Value::TYPE_DICTIONARY: {
116       // Dictionaries may be encoded as JSON strings.
117       if (value.GetAsString(&string_value)) {
118         scoped_ptr<base::Value> result(base::JSONReader::Read(string_value));
119         if (result && result->IsType(schema.type()))
120           return result.Pass();
121       }
122       break;
123     }
124     case base::Value::TYPE_STRING:
125     case base::Value::TYPE_BINARY:
126       // No conversion possible.
127       break;
128   }
129
130   LOG(WARNING) << "Failed to convert " << value.GetType()
131                << " to " << schema.type();
132   return scoped_ptr<base::Value>();
133 }
134
135 }  // namespace
136
137 bool CaseInsensitiveStringCompare::operator()(const std::string& a,
138                                               const std::string& b) const {
139   return base::strcasecmp(a.c_str(), b.c_str()) < 0;
140 }
141
142 RegistryDict::RegistryDict() {}
143
144 RegistryDict::~RegistryDict() {
145   ClearKeys();
146   ClearValues();
147 }
148
149 RegistryDict* RegistryDict::GetKey(const std::string& name) {
150   KeyMap::iterator entry = keys_.find(name);
151   return entry != keys_.end() ? entry->second : NULL;
152 }
153
154 const RegistryDict* RegistryDict::GetKey(const std::string& name) const {
155   KeyMap::const_iterator entry = keys_.find(name);
156   return entry != keys_.end() ? entry->second : NULL;
157 }
158
159 void RegistryDict::SetKey(const std::string& name,
160                           scoped_ptr<RegistryDict> dict) {
161   if (!dict) {
162     RemoveKey(name);
163     return;
164   }
165
166   RegistryDict*& entry = keys_[name];
167   delete entry;
168   entry = dict.release();
169 }
170
171 scoped_ptr<RegistryDict> RegistryDict::RemoveKey(const std::string& name) {
172   scoped_ptr<RegistryDict> result;
173   KeyMap::iterator entry = keys_.find(name);
174   if (entry != keys_.end()) {
175     result.reset(entry->second);
176     keys_.erase(entry);
177   }
178   return result.Pass();
179 }
180
181 void RegistryDict::ClearKeys() {
182   STLDeleteValues(&keys_);
183 }
184
185 base::Value* RegistryDict::GetValue(const std::string& name) {
186   ValueMap::iterator entry = values_.find(name);
187   return entry != values_.end() ? entry->second : NULL;
188 }
189
190 const base::Value* RegistryDict::GetValue(const std::string& name) const {
191   ValueMap::const_iterator entry = values_.find(name);
192   return entry != values_.end() ? entry->second : NULL;
193 }
194
195 void RegistryDict::SetValue(const std::string& name,
196                             scoped_ptr<base::Value> dict) {
197   if (!dict) {
198     RemoveValue(name);
199     return;
200   }
201
202   base::Value*& entry = values_[name];
203   delete entry;
204   entry = dict.release();
205 }
206
207 scoped_ptr<base::Value> RegistryDict::RemoveValue(const std::string& name) {
208   scoped_ptr<base::Value> result;
209   ValueMap::iterator entry = values_.find(name);
210   if (entry != values_.end()) {
211     result.reset(entry->second);
212     values_.erase(entry);
213   }
214   return result.Pass();
215 }
216
217 void RegistryDict::ClearValues() {
218   STLDeleteValues(&values_);
219 }
220
221 void RegistryDict::Merge(const RegistryDict& other) {
222   for (KeyMap::const_iterator entry(other.keys_.begin());
223        entry != other.keys_.end(); ++entry) {
224     RegistryDict*& subdict = keys_[entry->first];
225     if (!subdict)
226       subdict = new RegistryDict();
227     subdict->Merge(*entry->second);
228   }
229
230   for (ValueMap::const_iterator entry(other.values_.begin());
231        entry != other.values_.end(); ++entry) {
232     SetValue(entry->first, make_scoped_ptr(entry->second->DeepCopy()).Pass());
233   }
234 }
235
236 void RegistryDict::Swap(RegistryDict* other) {
237   keys_.swap(other->keys_);
238   values_.swap(other->values_);
239 }
240
241 void RegistryDict::ReadRegistry(HKEY hive, const base::string16& root) {
242   ClearKeys();
243   ClearValues();
244
245   // First, read all the values of the key.
246   for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) {
247     const std::string name = base::UTF16ToUTF8(it.Name());
248     switch (it.Type()) {
249       case REG_SZ:
250       case REG_EXPAND_SZ:
251         SetValue(name,
252                  scoped_ptr<base::Value>(
253                      new base::StringValue(base::UTF16ToUTF8(it.Value()))));
254         continue;
255       case REG_DWORD_LITTLE_ENDIAN:
256       case REG_DWORD_BIG_ENDIAN:
257         if (it.ValueSize() == sizeof(DWORD)) {
258           DWORD dword_value = *(reinterpret_cast<const DWORD*>(it.Value()));
259           if (it.Type() == REG_DWORD_BIG_ENDIAN)
260             dword_value = base::NetToHost32(dword_value);
261           else
262             dword_value = base::ByteSwapToLE32(dword_value);
263           SetValue(name,
264                    scoped_ptr<base::Value>(new base::FundamentalValue(
265                        static_cast<int>(dword_value))));
266           continue;
267         }
268       case REG_NONE:
269       case REG_LINK:
270       case REG_MULTI_SZ:
271       case REG_RESOURCE_LIST:
272       case REG_FULL_RESOURCE_DESCRIPTOR:
273       case REG_RESOURCE_REQUIREMENTS_LIST:
274       case REG_QWORD_LITTLE_ENDIAN:
275         // Unsupported type, message gets logged below.
276         break;
277     }
278
279     LOG(WARNING) << "Failed to read hive " << hive << " at "
280                  << root << "\\" << name
281                  << " type " << it.Type();
282   }
283
284   // Recurse for all subkeys.
285   for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) {
286     std::string name(base::UTF16ToUTF8(it.Name()));
287     scoped_ptr<RegistryDict> subdict(new RegistryDict());
288     subdict->ReadRegistry(hive, root + L"\\" + it.Name());
289     SetKey(name, subdict.Pass());
290   }
291 }
292
293 scoped_ptr<base::Value> RegistryDict::ConvertToJSON(
294     const Schema& schema) const {
295   base::Value::Type type =
296       schema.valid() ? schema.type() : base::Value::TYPE_DICTIONARY;
297   switch (type) {
298     case base::Value::TYPE_DICTIONARY: {
299       scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
300       for (RegistryDict::ValueMap::const_iterator entry(values_.begin());
301            entry != values_.end(); ++entry) {
302         Schema subschema =
303             schema.valid() ? schema.GetProperty(entry->first) : Schema();
304         scoped_ptr<base::Value> converted =
305             ConvertValue(*entry->second, subschema);
306         if (converted)
307           result->SetWithoutPathExpansion(entry->first, converted.release());
308       }
309       for (RegistryDict::KeyMap::const_iterator entry(keys_.begin());
310            entry != keys_.end(); ++entry) {
311         Schema subschema =
312             schema.valid() ? schema.GetProperty(entry->first) : Schema();
313         scoped_ptr<base::Value> converted =
314             entry->second->ConvertToJSON(subschema);
315         if (converted)
316           result->SetWithoutPathExpansion(entry->first, converted.release());
317       }
318       return result.PassAs<base::Value>();
319     }
320     case base::Value::TYPE_LIST: {
321       scoped_ptr<base::ListValue> result(new base::ListValue());
322       Schema item_schema = schema.valid() ? schema.GetItems() : Schema();
323       for (int i = 1; ; ++i) {
324         const std::string name(base::IntToString(i));
325         const RegistryDict* key = GetKey(name);
326         if (key) {
327           scoped_ptr<base::Value> converted = key->ConvertToJSON(item_schema);
328           if (converted)
329             result->Append(converted.release());
330           continue;
331         }
332         const base::Value* value = GetValue(name);
333         if (value) {
334           scoped_ptr<base::Value> converted = ConvertValue(*value, item_schema);
335           if (converted)
336             result->Append(converted.release());
337           continue;
338         }
339         break;
340       }
341       return result.PassAs<base::Value>();
342     }
343     default:
344       LOG(WARNING) << "Can't convert registry key to schema type " << type;
345   }
346
347   return scoped_ptr<base::Value>();
348 }
349
350 }  // namespace policy