OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/policy/core/common/registry_dict_win.h" | 5 #include "components/policy/core/common/registry_dict_win.h" |
6 | 6 |
7 #include "base/json/json_reader.h" | 7 #include "base/json/json_reader.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/sys_byteorder.h" | 12 #include "base/sys_byteorder.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "base/win/registry.h" | 14 #include "base/win/registry.h" |
15 #include "components/json_schema/json_schema_constants.h" | 15 #include "components/policy/core/common/schema.h" |
16 | |
17 namespace schema = json_schema_constants; | |
18 | 16 |
19 using base::win::RegistryKeyIterator; | 17 using base::win::RegistryKeyIterator; |
20 using base::win::RegistryValueIterator; | 18 using base::win::RegistryValueIterator; |
21 | 19 |
22 namespace policy { | 20 namespace policy { |
23 | 21 |
24 namespace { | 22 namespace { |
25 | 23 |
26 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL. | |
27 const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary, | |
28 const std::string& name) { | |
29 if (!dictionary) | |
30 return NULL; | |
31 const base::DictionaryValue* entry = NULL; | |
32 dictionary->GetDictionaryWithoutPathExpansion(name, &entry); | |
33 return entry; | |
34 } | |
35 | |
36 // Returns the Value type described in |schema|, or |default_type| if not found. | |
37 base::Value::Type GetValueTypeForSchema(const base::DictionaryValue* schema, | |
38 base::Value::Type default_type) { | |
39 // JSON-schema types to base::Value::Type mapping. | |
40 static const struct { | |
41 // JSON schema type. | |
42 const char* schema_type; | |
43 // Correspondent value type. | |
44 base::Value::Type value_type; | |
45 } kSchemaToValueTypeMap[] = { | |
46 { schema::kArray, base::Value::TYPE_LIST }, | |
47 { schema::kBoolean, base::Value::TYPE_BOOLEAN }, | |
48 { schema::kInteger, base::Value::TYPE_INTEGER }, | |
49 { schema::kNull, base::Value::TYPE_NULL }, | |
50 { schema::kNumber, base::Value::TYPE_DOUBLE }, | |
51 { schema::kObject, base::Value::TYPE_DICTIONARY }, | |
52 { schema::kString, base::Value::TYPE_STRING }, | |
53 }; | |
54 | |
55 if (!schema) | |
56 return default_type; | |
57 std::string type; | |
58 if (!schema->GetStringWithoutPathExpansion(schema::kType, &type)) | |
59 return default_type; | |
60 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { | |
61 if (type == kSchemaToValueTypeMap[i].schema_type) | |
62 return kSchemaToValueTypeMap[i].value_type; | |
63 } | |
64 return default_type; | |
65 } | |
66 | |
67 // Returns the schema for property |name| given the |schema| of an object. | |
68 // Returns the "additionalProperties" schema if no specific schema for | |
69 // |name| is present. Returns NULL if no schema is found. | |
70 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, | |
71 const std::string& name) { | |
72 const base::DictionaryValue* properties = | |
73 GetEntry(schema, schema::kProperties); | |
74 const base::DictionaryValue* sub_schema = GetEntry(properties, name); | |
75 if (sub_schema) | |
76 return sub_schema; | |
77 // "additionalProperties" can be a boolean, but that case is ignored. | |
78 return GetEntry(schema, schema::kAdditionalProperties); | |
79 } | |
80 | |
81 // Converts a value (as read from the registry) to meet |schema|, converting | 24 // Converts a value (as read from the registry) to meet |schema|, converting |
82 // types as necessary. Unconvertible types will show up as NULL values in the | 25 // types as necessary. Unconvertible types will show up as NULL values in the |
83 // result. | 26 // result. |
84 scoped_ptr<base::Value> ConvertValue(const base::Value& value, | 27 scoped_ptr<base::Value> ConvertValue(const base::Value& value, |
85 const base::DictionaryValue* schema) { | 28 const Schema& schema) { |
86 // Figure out the type to convert to from the schema. | 29 if (!schema.valid()) |
87 const base::Value::Type result_type( | 30 return make_scoped_ptr(value.DeepCopy()); |
88 GetValueTypeForSchema(schema, value.GetType())); | |
89 | 31 |
90 // If the type is good already, go with it. | 32 // If the type is good already, go with it. |
91 if (value.IsType(result_type)) { | 33 if (value.IsType(schema.type())) { |
92 // Recurse for complex types if there is a schema. | 34 // Recurse for complex types. |
93 if (schema) { | 35 const base::DictionaryValue* dict = NULL; |
94 const base::DictionaryValue* dict = NULL; | 36 const base::ListValue* list = NULL; |
95 const base::ListValue* list = NULL; | 37 if (value.GetAsDictionary(&dict)) { |
96 if (value.GetAsDictionary(&dict)) { | 38 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
97 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 39 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); |
98 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); | 40 entry.Advance()) { |
99 entry.Advance()) { | 41 scoped_ptr<base::Value> converted = |
100 scoped_ptr<base::Value> converted_value( | 42 ConvertValue(entry.value(), schema.GetProperty(entry.key())); |
101 ConvertValue(entry.value(), GetSchemaFor(schema, entry.key()))); | 43 if (converted) |
102 result->SetWithoutPathExpansion(entry.key(), | 44 result->SetWithoutPathExpansion(entry.key(), converted.release()); |
103 converted_value.release()); | |
104 } | |
105 return result.Pass(); | |
106 } else if (value.GetAsList(&list)) { | |
107 scoped_ptr<base::ListValue> result(new base::ListValue()); | |
108 const base::DictionaryValue* item_schema = | |
109 GetEntry(schema, schema::kItems); | |
110 for (base::ListValue::const_iterator entry(list->begin()); | |
111 entry != list->end(); ++entry) { | |
112 result->Append(ConvertValue(**entry, item_schema).release()); | |
113 } | |
114 return result.Pass(); | |
115 } | 45 } |
| 46 return result.Pass(); |
| 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.Pass(); |
116 } | 57 } |
117 return make_scoped_ptr(value.DeepCopy()); | 58 return make_scoped_ptr(value.DeepCopy()); |
118 } | 59 } |
119 | 60 |
120 // Else, do some conversions to map windows registry data types to JSON types. | 61 // Else, do some conversions to map windows registry data types to JSON types. |
121 std::string string_value; | 62 std::string string_value; |
122 int int_value = 0; | 63 int int_value = 0; |
123 switch (result_type) { | 64 switch (schema.type()) { |
124 case base::Value::TYPE_NULL: { | 65 case base::Value::TYPE_NULL: { |
125 return make_scoped_ptr(base::Value::CreateNullValue()); | 66 return make_scoped_ptr(base::Value::CreateNullValue()); |
126 } | 67 } |
127 case base::Value::TYPE_BOOLEAN: { | 68 case base::Value::TYPE_BOOLEAN: { |
128 // Accept booleans encoded as either string or integer. | 69 // Accept booleans encoded as either string or integer. |
129 if (value.GetAsInteger(&int_value) || | 70 if (value.GetAsInteger(&int_value) || |
130 (value.GetAsString(&string_value) && | 71 (value.GetAsString(&string_value) && |
131 base::StringToInt(string_value, &int_value))) { | 72 base::StringToInt(string_value, &int_value))) { |
132 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0)); | 73 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0)); |
133 } | 74 } |
(...skipping 16 matching lines...) Expand all Loading... |
150 base::StringToDouble(string_value, &double_value)) { | 91 base::StringToDouble(string_value, &double_value)) { |
151 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); | 92 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); |
152 } | 93 } |
153 break; | 94 break; |
154 } | 95 } |
155 case base::Value::TYPE_LIST: { | 96 case base::Value::TYPE_LIST: { |
156 // Lists are encoded as subkeys with numbered value in the registry. | 97 // Lists are encoded as subkeys with numbered value in the registry. |
157 const base::DictionaryValue* dict = NULL; | 98 const base::DictionaryValue* dict = NULL; |
158 if (value.GetAsDictionary(&dict)) { | 99 if (value.GetAsDictionary(&dict)) { |
159 scoped_ptr<base::ListValue> result(new base::ListValue()); | 100 scoped_ptr<base::ListValue> result(new base::ListValue()); |
160 const base::DictionaryValue* item_schema = | |
161 GetEntry(schema, schema::kItems); | |
162 for (int i = 1; ; ++i) { | 101 for (int i = 1; ; ++i) { |
163 const base::Value* entry = NULL; | 102 const base::Value* entry = NULL; |
164 if (!dict->Get(base::IntToString(i), &entry)) | 103 if (!dict->Get(base::IntToString(i), &entry)) |
165 break; | 104 break; |
166 result->Append(ConvertValue(*entry, item_schema).release()); | 105 scoped_ptr<base::Value> converted = |
| 106 ConvertValue(*entry, schema.GetItems()); |
| 107 if (converted) |
| 108 result->Append(converted.release()); |
167 } | 109 } |
168 return result.Pass(); | 110 return result.Pass(); |
169 } | 111 } |
170 // Fall through in order to accept lists encoded as JSON strings. | 112 // Fall through in order to accept lists encoded as JSON strings. |
171 } | 113 } |
172 case base::Value::TYPE_DICTIONARY: { | 114 case base::Value::TYPE_DICTIONARY: { |
173 // Dictionaries may be encoded as JSON strings. | 115 // Dictionaries may be encoded as JSON strings. |
174 if (value.GetAsString(&string_value)) { | 116 if (value.GetAsString(&string_value)) { |
175 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); | 117 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); |
176 if (result && result->IsType(result_type)) | 118 if (result && result->IsType(schema.type())) |
177 return result.Pass(); | 119 return result.Pass(); |
178 } | 120 } |
179 break; | 121 break; |
180 } | 122 } |
181 case base::Value::TYPE_STRING: | 123 case base::Value::TYPE_STRING: |
182 case base::Value::TYPE_BINARY: | 124 case base::Value::TYPE_BINARY: |
183 // No conversion possible. | 125 // No conversion possible. |
184 break; | 126 break; |
185 } | 127 } |
186 | 128 |
187 LOG(WARNING) << "Failed to convert " << value.GetType() | 129 LOG(WARNING) << "Failed to convert " << value.GetType() |
188 << " to " << result_type; | 130 << " to " << schema.type(); |
189 return make_scoped_ptr(base::Value::CreateNullValue()); | 131 return scoped_ptr<base::Value>(); |
190 } | 132 } |
191 | 133 |
192 } // namespace | 134 } // namespace |
193 | 135 |
194 bool CaseInsensitiveStringCompare::operator()(const std::string& a, | 136 bool CaseInsensitiveStringCompare::operator()(const std::string& a, |
195 const std::string& b) const { | 137 const std::string& b) const { |
196 return base::strcasecmp(a.c_str(), b.c_str()) < 0; | 138 return base::strcasecmp(a.c_str(), b.c_str()) < 0; |
197 } | 139 } |
198 | 140 |
199 RegistryDict::RegistryDict() {} | 141 RegistryDict::RegistryDict() {} |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 // Recurse for all subkeys. | 283 // Recurse for all subkeys. |
342 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { | 284 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { |
343 std::string name(UTF16ToUTF8(it.Name())); | 285 std::string name(UTF16ToUTF8(it.Name())); |
344 scoped_ptr<RegistryDict> subdict(new RegistryDict()); | 286 scoped_ptr<RegistryDict> subdict(new RegistryDict()); |
345 subdict->ReadRegistry(hive, root + L"\\" + it.Name()); | 287 subdict->ReadRegistry(hive, root + L"\\" + it.Name()); |
346 SetKey(name, subdict.Pass()); | 288 SetKey(name, subdict.Pass()); |
347 } | 289 } |
348 } | 290 } |
349 | 291 |
350 scoped_ptr<base::Value> RegistryDict::ConvertToJSON( | 292 scoped_ptr<base::Value> RegistryDict::ConvertToJSON( |
351 const base::DictionaryValue* schema) const { | 293 const Schema& schema) const { |
352 base::Value::Type type = | 294 base::Value::Type type = |
353 GetValueTypeForSchema(schema, base::Value::TYPE_DICTIONARY); | 295 schema.valid() ? schema.type() : base::Value::TYPE_DICTIONARY; |
354 switch (type) { | 296 switch (type) { |
355 case base::Value::TYPE_DICTIONARY: { | 297 case base::Value::TYPE_DICTIONARY: { |
356 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 298 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
357 for (RegistryDict::ValueMap::const_iterator entry(values_.begin()); | 299 for (RegistryDict::ValueMap::const_iterator entry(values_.begin()); |
358 entry != values_.end(); ++entry) { | 300 entry != values_.end(); ++entry) { |
359 result->SetWithoutPathExpansion( | 301 Schema subschema = |
360 entry->first, | 302 schema.valid() ? schema.GetProperty(entry->first) : Schema(); |
361 ConvertValue(*entry->second, | 303 scoped_ptr<base::Value> converted = |
362 GetSchemaFor(schema, entry->first)).release()); | 304 ConvertValue(*entry->second, subschema); |
| 305 if (converted) |
| 306 result->SetWithoutPathExpansion(entry->first, converted.release()); |
363 } | 307 } |
364 for (RegistryDict::KeyMap::const_iterator entry(keys_.begin()); | 308 for (RegistryDict::KeyMap::const_iterator entry(keys_.begin()); |
365 entry != keys_.end(); ++entry) { | 309 entry != keys_.end(); ++entry) { |
366 result->SetWithoutPathExpansion( | 310 Schema subschema = |
367 entry->first, | 311 schema.valid() ? schema.GetProperty(entry->first) : Schema(); |
368 entry->second->ConvertToJSON( | 312 scoped_ptr<base::Value> converted = |
369 GetSchemaFor(schema, entry->first)).release()); | 313 entry->second->ConvertToJSON(subschema); |
| 314 if (converted) |
| 315 result->SetWithoutPathExpansion(entry->first, converted.release()); |
370 } | 316 } |
371 return result.Pass(); | 317 return result.Pass(); |
372 } | 318 } |
373 case base::Value::TYPE_LIST: { | 319 case base::Value::TYPE_LIST: { |
374 scoped_ptr<base::ListValue> result(new base::ListValue()); | 320 scoped_ptr<base::ListValue> result(new base::ListValue()); |
375 const base::DictionaryValue* item_schema = | 321 Schema item_schema = schema.valid() ? schema.GetItems() : Schema(); |
376 GetEntry(schema, schema::kItems); | |
377 for (int i = 1; ; ++i) { | 322 for (int i = 1; ; ++i) { |
378 const std::string name(base::IntToString(i)); | 323 const std::string name(base::IntToString(i)); |
379 const RegistryDict* key = GetKey(name); | 324 const RegistryDict* key = GetKey(name); |
380 if (key) { | 325 if (key) { |
381 result->Append(key->ConvertToJSON(item_schema).release()); | 326 scoped_ptr<base::Value> converted = key->ConvertToJSON(item_schema); |
| 327 if (converted) |
| 328 result->Append(converted.release()); |
382 continue; | 329 continue; |
383 } | 330 } |
384 const base::Value* value = GetValue(name); | 331 const base::Value* value = GetValue(name); |
385 if (value) { | 332 if (value) { |
386 result->Append(ConvertValue(*value, item_schema).release()); | 333 scoped_ptr<base::Value> converted = ConvertValue(*value, item_schema); |
| 334 if (converted) |
| 335 result->Append(converted.release()); |
387 continue; | 336 continue; |
388 } | 337 } |
389 break; | 338 break; |
390 } | 339 } |
391 return result.Pass(); | 340 return result.Pass(); |
392 } | 341 } |
393 default: | 342 default: |
394 LOG(WARNING) << "Can't convert registry key to schema type " << type; | 343 LOG(WARNING) << "Can't convert registry key to schema type " << type; |
395 } | 344 } |
396 | 345 |
397 return make_scoped_ptr(base::Value::CreateNullValue()); | 346 return scoped_ptr<base::Value>(); |
398 } | 347 } |
399 | 348 |
400 } // namespace policy | 349 } // namespace policy |
OLD | NEW |