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/schema.h" | 5 #include "components/policy/core/common/schema.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <climits> | 8 #include <climits> |
9 #include <map> | 9 #include <map> |
10 #include <utility> | 10 #include <utility> |
11 #include <vector> | |
12 | 11 |
13 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
14 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/scoped_ptr.h" |
15 #include "base/memory/scoped_vector.h" | 15 #include "base/memory/scoped_vector.h" |
| 16 #include "base/stl_util.h" |
16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
17 #include "components/json_schema/json_schema_constants.h" | 18 #include "components/json_schema/json_schema_constants.h" |
18 #include "components/json_schema/json_schema_validator.h" | 19 #include "components/json_schema/json_schema_validator.h" |
19 #include "components/policy/core/common/schema_internal.h" | 20 #include "components/policy/core/common/schema_internal.h" |
| 21 #include "third_party/re2/re2/re2.h" |
20 | 22 |
21 namespace schema = json_schema_constants; | 23 namespace schema = json_schema_constants; |
22 | 24 |
23 namespace policy { | 25 namespace policy { |
24 | 26 |
25 using internal::PropertiesNode; | 27 using internal::PropertiesNode; |
26 using internal::PropertyNode; | 28 using internal::PropertyNode; |
27 using internal::RestrictionNode; | 29 using internal::RestrictionNode; |
28 using internal::SchemaData; | 30 using internal::SchemaData; |
29 using internal::SchemaNode; | 31 using internal::SchemaNode; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 } | 170 } |
169 | 171 |
170 const int* int_enums(int index) const { | 172 const int* int_enums(int index) const { |
171 return schema_data_.int_enums + index; | 173 return schema_data_.int_enums + index; |
172 } | 174 } |
173 | 175 |
174 const char** string_enums(int index) const { | 176 const char** string_enums(int index) const { |
175 return schema_data_.string_enums + index; | 177 return schema_data_.string_enums + index; |
176 } | 178 } |
177 | 179 |
| 180 // Compiles regular expression |pattern|. The result is cached and will be |
| 181 // returned directly next time. |
| 182 re2::RE2* CompileRegex(const std::string& pattern) const; |
| 183 |
178 private: | 184 private: |
179 friend class base::RefCountedThreadSafe<InternalStorage>; | 185 friend class base::RefCountedThreadSafe<InternalStorage>; |
180 | 186 |
181 InternalStorage(); | 187 InternalStorage(); |
182 ~InternalStorage(); | 188 ~InternalStorage(); |
183 | 189 |
184 // Determines the expected |sizes| of the storage for the representation | 190 // Determines the expected |sizes| of the storage for the representation |
185 // of |schema|. | 191 // of |schema|. |
186 static void DetermineStorageSizes(const base::DictionaryValue& schema, | 192 static void DetermineStorageSizes(const base::DictionaryValue& schema, |
187 StorageSizes* sizes); | 193 StorageSizes* sizes); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 | 227 |
222 bool ParseEnum(const base::DictionaryValue& schema, | 228 bool ParseEnum(const base::DictionaryValue& schema, |
223 base::Value::Type type, | 229 base::Value::Type type, |
224 SchemaNode* schema_node, | 230 SchemaNode* schema_node, |
225 std::string* error); | 231 std::string* error); |
226 | 232 |
227 bool ParseRangedInt(const base::DictionaryValue& schema, | 233 bool ParseRangedInt(const base::DictionaryValue& schema, |
228 SchemaNode* schema_node, | 234 SchemaNode* schema_node, |
229 std::string* error); | 235 std::string* error); |
230 | 236 |
| 237 bool ParseStringPattern(const base::DictionaryValue& schema, |
| 238 SchemaNode* schema_node, |
| 239 std::string* error); |
| 240 |
231 // Assigns the IDs in |id_map| to the pending references in the | 241 // Assigns the IDs in |id_map| to the pending references in the |
232 // |reference_list|. If an ID is missing then |error| is set and false is | 242 // |reference_list|. If an ID is missing then |error| is set and false is |
233 // returned; otherwise returns true. | 243 // returned; otherwise returns true. |
234 static bool ResolveReferences(const IdMap& id_map, | 244 static bool ResolveReferences(const IdMap& id_map, |
235 const ReferenceList& reference_list, | 245 const ReferenceList& reference_list, |
236 std::string* error); | 246 std::string* error); |
237 | 247 |
| 248 // Cache for CompileRegex(), will memorize return value of every call to |
| 249 // CompileRegex() and return results directly next time. |
| 250 mutable std::map<std::string, re2::RE2*> regex_cache_; |
| 251 STLValueDeleter<std::map<std::string, re2::RE2*> > regex_cache_deleter_; |
| 252 |
238 SchemaData schema_data_; | 253 SchemaData schema_data_; |
239 std::vector<std::string> strings_; | 254 std::vector<std::string> strings_; |
240 std::vector<SchemaNode> schema_nodes_; | 255 std::vector<SchemaNode> schema_nodes_; |
241 std::vector<PropertyNode> property_nodes_; | 256 std::vector<PropertyNode> property_nodes_; |
242 std::vector<PropertiesNode> properties_nodes_; | 257 std::vector<PropertiesNode> properties_nodes_; |
243 std::vector<RestrictionNode> restriction_nodes_; | 258 std::vector<RestrictionNode> restriction_nodes_; |
244 std::vector<int> int_enums_; | 259 std::vector<int> int_enums_; |
245 std::vector<const char*> string_enums_; | 260 std::vector<const char*> string_enums_; |
246 | 261 |
247 DISALLOW_COPY_AND_ASSIGN(InternalStorage); | 262 DISALLOW_COPY_AND_ASSIGN(InternalStorage); |
248 }; | 263 }; |
249 | 264 |
250 Schema::InternalStorage::InternalStorage() {} | 265 Schema::InternalStorage::InternalStorage() |
| 266 : regex_cache_deleter_(®ex_cache_) {} |
251 | 267 |
252 Schema::InternalStorage::~InternalStorage() {} | 268 Schema::InternalStorage::~InternalStorage() {} |
253 | 269 |
254 // static | 270 // static |
255 scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( | 271 scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( |
256 const SchemaData* data) { | 272 const SchemaData* data) { |
257 InternalStorage* storage = new InternalStorage(); | 273 InternalStorage* storage = new InternalStorage(); |
258 storage->schema_data_.schema_nodes = data->schema_nodes; | 274 storage->schema_data_.schema_nodes = data->schema_nodes; |
259 storage->schema_data_.property_nodes = data->property_nodes; | 275 storage->schema_data_.property_nodes = data->property_nodes; |
260 storage->schema_data_.properties_nodes = data->properties_nodes; | 276 storage->schema_data_.properties_nodes = data->properties_nodes; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 SchemaData* data = &storage->schema_data_; | 333 SchemaData* data = &storage->schema_data_; |
318 data->schema_nodes = vector_as_array(&storage->schema_nodes_); | 334 data->schema_nodes = vector_as_array(&storage->schema_nodes_); |
319 data->property_nodes = vector_as_array(&storage->property_nodes_); | 335 data->property_nodes = vector_as_array(&storage->property_nodes_); |
320 data->properties_nodes = vector_as_array(&storage->properties_nodes_); | 336 data->properties_nodes = vector_as_array(&storage->properties_nodes_); |
321 data->restriction_nodes = vector_as_array(&storage->restriction_nodes_); | 337 data->restriction_nodes = vector_as_array(&storage->restriction_nodes_); |
322 data->int_enums = vector_as_array(&storage->int_enums_); | 338 data->int_enums = vector_as_array(&storage->int_enums_); |
323 data->string_enums = vector_as_array(&storage->string_enums_); | 339 data->string_enums = vector_as_array(&storage->string_enums_); |
324 return storage; | 340 return storage; |
325 } | 341 } |
326 | 342 |
| 343 re2::RE2* Schema::InternalStorage::CompileRegex( |
| 344 const std::string& pattern) const { |
| 345 std::map<std::string, re2::RE2*>::iterator it = regex_cache_.find(pattern); |
| 346 if (it == regex_cache_.end()) { |
| 347 re2::RE2* compiled = new re2::RE2(pattern); |
| 348 regex_cache_[pattern] = compiled; |
| 349 return compiled; |
| 350 } |
| 351 return it->second; |
| 352 } |
| 353 |
327 // static | 354 // static |
328 void Schema::InternalStorage::DetermineStorageSizes( | 355 void Schema::InternalStorage::DetermineStorageSizes( |
329 const base::DictionaryValue& schema, | 356 const base::DictionaryValue& schema, |
330 StorageSizes* sizes) { | 357 StorageSizes* sizes) { |
331 std::string ref_string; | 358 std::string ref_string; |
332 if (schema.GetString(schema::kRef, &ref_string)) { | 359 if (schema.GetString(schema::kRef, &ref_string)) { |
333 // Schemas with a "$ref" attribute don't take additional storage. | 360 // Schemas with a "$ref" attribute don't take additional storage. |
334 return; | 361 return; |
335 } | 362 } |
336 | 363 |
(...skipping 22 matching lines...) Expand all Loading... |
359 if (schema.GetDictionary(schema::kProperties, &properties)) { | 386 if (schema.GetDictionary(schema::kProperties, &properties)) { |
360 for (base::DictionaryValue::Iterator it(*properties); | 387 for (base::DictionaryValue::Iterator it(*properties); |
361 !it.IsAtEnd(); it.Advance()) { | 388 !it.IsAtEnd(); it.Advance()) { |
362 // This should have been verified by the JSONSchemaValidator. | 389 // This should have been verified by the JSONSchemaValidator. |
363 CHECK(it.value().GetAsDictionary(&dict)); | 390 CHECK(it.value().GetAsDictionary(&dict)); |
364 DetermineStorageSizes(*dict, sizes); | 391 DetermineStorageSizes(*dict, sizes); |
365 sizes->strings++; | 392 sizes->strings++; |
366 sizes->property_nodes++; | 393 sizes->property_nodes++; |
367 } | 394 } |
368 } | 395 } |
| 396 |
| 397 const base::DictionaryValue* pattern_properties = NULL; |
| 398 if (schema.GetDictionary(schema::kPatternProperties, &pattern_properties)) { |
| 399 for (base::DictionaryValue::Iterator it(*pattern_properties); |
| 400 !it.IsAtEnd(); it.Advance()) { |
| 401 CHECK(it.value().GetAsDictionary(&dict)); |
| 402 DetermineStorageSizes(*dict, sizes); |
| 403 sizes->strings++; |
| 404 sizes->property_nodes++; |
| 405 } |
| 406 } |
369 } else if (schema.HasKey(schema::kEnum)) { | 407 } else if (schema.HasKey(schema::kEnum)) { |
370 const base::ListValue* possible_values = NULL; | 408 const base::ListValue* possible_values = NULL; |
371 if (schema.GetList(schema::kEnum, &possible_values)) { | 409 if (schema.GetList(schema::kEnum, &possible_values)) { |
372 if (type == base::Value::TYPE_INTEGER) { | 410 if (type == base::Value::TYPE_INTEGER) { |
373 sizes->int_enums += possible_values->GetSize(); | 411 sizes->int_enums += possible_values->GetSize(); |
374 } else if (type == base::Value::TYPE_STRING) { | 412 } else if (type == base::Value::TYPE_STRING) { |
375 sizes->string_enums += possible_values->GetSize(); | 413 sizes->string_enums += possible_values->GetSize(); |
376 sizes->strings += possible_values->GetSize(); | 414 sizes->strings += possible_values->GetSize(); |
377 } | 415 } |
378 sizes->restriction_nodes++; | 416 sizes->restriction_nodes++; |
379 } | 417 } |
380 } else if (type == base::Value::TYPE_INTEGER) { | 418 } else if (type == base::Value::TYPE_INTEGER) { |
381 if (schema.HasKey(schema::kMinimum) || schema.HasKey(schema::kMaximum)) | 419 if (schema.HasKey(schema::kMinimum) || schema.HasKey(schema::kMaximum)) |
382 sizes->restriction_nodes++; | 420 sizes->restriction_nodes++; |
| 421 } else if (type == base::Value::TYPE_STRING) { |
| 422 if (schema.HasKey(schema::kPattern)) { |
| 423 sizes->strings++; |
| 424 sizes->string_enums++; |
| 425 sizes->restriction_nodes++; |
| 426 } |
383 } | 427 } |
384 } | 428 } |
385 | 429 |
386 bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, | 430 bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, |
387 int* index, | 431 int* index, |
388 IdMap* id_map, | 432 IdMap* id_map, |
389 ReferenceList* reference_list, | 433 ReferenceList* reference_list, |
390 std::string* error) { | 434 std::string* error) { |
391 std::string ref_string; | 435 std::string ref_string; |
392 if (schema.GetString(schema::kRef, &ref_string)) { | 436 if (schema.GetString(schema::kRef, &ref_string)) { |
(...skipping 26 matching lines...) Expand all Loading... |
419 | 463 |
420 if (type == base::Value::TYPE_DICTIONARY) { | 464 if (type == base::Value::TYPE_DICTIONARY) { |
421 if (!ParseDictionary(schema, schema_node, id_map, reference_list, error)) | 465 if (!ParseDictionary(schema, schema_node, id_map, reference_list, error)) |
422 return false; | 466 return false; |
423 } else if (type == base::Value::TYPE_LIST) { | 467 } else if (type == base::Value::TYPE_LIST) { |
424 if (!ParseList(schema, schema_node, id_map, reference_list, error)) | 468 if (!ParseList(schema, schema_node, id_map, reference_list, error)) |
425 return false; | 469 return false; |
426 } else if (schema.HasKey(schema::kEnum)) { | 470 } else if (schema.HasKey(schema::kEnum)) { |
427 if (!ParseEnum(schema, type, schema_node, error)) | 471 if (!ParseEnum(schema, type, schema_node, error)) |
428 return false; | 472 return false; |
| 473 } else if (schema.HasKey(schema::kPattern)) { |
| 474 if (!ParseStringPattern(schema, schema_node, error)) |
| 475 return false; |
429 } else if (schema.HasKey(schema::kMinimum) || | 476 } else if (schema.HasKey(schema::kMinimum) || |
430 schema.HasKey(schema::kMaximum)) { | 477 schema.HasKey(schema::kMaximum)) { |
431 if (type != base::Value::TYPE_INTEGER) { | 478 if (type != base::Value::TYPE_INTEGER) { |
432 *error = "Only integers can have minimum and maximum"; | 479 *error = "Only integers can have minimum and maximum"; |
433 return false; | 480 return false; |
434 } | 481 } |
435 if (!ParseRangedInt(schema, schema_node, error)) | 482 if (!ParseRangedInt(schema, schema_node, error)) |
436 return false; | 483 return false; |
437 } | 484 } |
438 std::string id_string; | 485 std::string id_string; |
439 if (schema.GetString(schema::kId, &id_string)) { | 486 if (schema.GetString(schema::kId, &id_string)) { |
440 if (ContainsKey(*id_map, id_string)) { | 487 if (ContainsKey(*id_map, id_string)) { |
441 *error = "Duplicated id: " + id_string; | 488 *error = "Duplicated id: " + id_string; |
442 return false; | 489 return false; |
443 } | 490 } |
444 (*id_map)[id_string] = *index; | 491 (*id_map)[id_string] = *index; |
445 } | 492 } |
446 | 493 |
447 return true; | 494 return true; |
448 } | 495 } |
449 | 496 |
450 bool Schema::InternalStorage::ParseDictionary( | 497 bool Schema::InternalStorage::ParseDictionary( |
451 const base::DictionaryValue& schema, | 498 const base::DictionaryValue& schema, |
452 SchemaNode* schema_node, | 499 SchemaNode* schema_node, |
453 IdMap* id_map, | 500 IdMap* id_map, |
454 ReferenceList* reference_list, | 501 ReferenceList* reference_list, |
455 std::string* error) { | 502 std::string* error) { |
456 int extra = static_cast<int>(properties_nodes_.size()); | 503 int extra = static_cast<int>(properties_nodes_.size()); |
457 properties_nodes_.push_back(PropertiesNode()); | 504 properties_nodes_.push_back(PropertiesNode()); |
458 properties_nodes_[extra].begin = kInvalid; | |
459 properties_nodes_[extra].end = kInvalid; | |
460 properties_nodes_[extra].additional = kInvalid; | 505 properties_nodes_[extra].additional = kInvalid; |
461 schema_node->extra = extra; | 506 schema_node->extra = extra; |
462 | 507 |
463 const base::DictionaryValue* dict = NULL; | 508 const base::DictionaryValue* dict = NULL; |
464 if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) { | 509 if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) { |
465 if (!Parse(*dict, &properties_nodes_[extra].additional, | 510 if (!Parse(*dict, &properties_nodes_[extra].additional, |
466 id_map, reference_list, error)) { | 511 id_map, reference_list, error)) { |
467 return false; | 512 return false; |
468 } | 513 } |
469 } | 514 } |
470 | 515 |
| 516 properties_nodes_[extra].begin = static_cast<int>(property_nodes_.size()); |
| 517 |
471 const base::DictionaryValue* properties = NULL; | 518 const base::DictionaryValue* properties = NULL; |
472 if (schema.GetDictionary(schema::kProperties, &properties)) { | 519 if (schema.GetDictionary(schema::kProperties, &properties)) { |
473 int base_index = static_cast<int>(property_nodes_.size()); | 520 // This and below reserves nodes for all of the |properties|, and makes sure |
474 // This reserves nodes for all of the |properties|, and makes sure they | 521 // they are contiguous. Recursive calls to Parse() will append after these |
475 // are contiguous. Recursive calls to Parse() will append after these | |
476 // elements. | 522 // elements. |
477 property_nodes_.resize(base_index + properties->size()); | 523 property_nodes_.resize(property_nodes_.size() + properties->size()); |
| 524 } |
478 | 525 |
| 526 properties_nodes_[extra].end = static_cast<int>(property_nodes_.size()); |
| 527 |
| 528 const base::DictionaryValue* pattern_properties = NULL; |
| 529 if (schema.GetDictionary(schema::kPatternProperties, &pattern_properties)) |
| 530 property_nodes_.resize(property_nodes_.size() + pattern_properties->size()); |
| 531 |
| 532 properties_nodes_[extra].pattern_end = |
| 533 static_cast<int>(property_nodes_.size()); |
| 534 |
| 535 if (properties != NULL) { |
| 536 int base_index = properties_nodes_[extra].begin; |
479 int index = base_index; | 537 int index = base_index; |
| 538 |
480 for (base::DictionaryValue::Iterator it(*properties); | 539 for (base::DictionaryValue::Iterator it(*properties); |
481 !it.IsAtEnd(); it.Advance(), ++index) { | 540 !it.IsAtEnd(); it.Advance(), ++index) { |
482 // This should have been verified by the JSONSchemaValidator. | 541 // This should have been verified by the JSONSchemaValidator. |
483 CHECK(it.value().GetAsDictionary(&dict)); | 542 CHECK(it.value().GetAsDictionary(&dict)); |
484 strings_.push_back(it.key()); | 543 strings_.push_back(it.key()); |
485 property_nodes_[index].key = strings_.back().c_str(); | 544 property_nodes_[index].key = strings_.back().c_str(); |
486 if (!Parse(*dict, &property_nodes_[index].schema, | 545 if (!Parse(*dict, &property_nodes_[index].schema, |
487 id_map, reference_list, error)) { | 546 id_map, reference_list, error)) { |
488 return false; | 547 return false; |
489 } | 548 } |
490 } | 549 } |
491 CHECK_EQ(static_cast<int>(properties->size()), index - base_index); | 550 CHECK_EQ(static_cast<int>(properties->size()), index - base_index); |
492 properties_nodes_[extra].begin = base_index; | 551 } |
493 properties_nodes_[extra].end = index; | 552 |
| 553 if (pattern_properties != NULL) { |
| 554 int base_index = properties_nodes_[extra].end; |
| 555 int index = base_index; |
| 556 |
| 557 for (base::DictionaryValue::Iterator it(*pattern_properties); |
| 558 !it.IsAtEnd(); it.Advance(), ++index) { |
| 559 CHECK(it.value().GetAsDictionary(&dict)); |
| 560 re2::RE2* compiled_regex = CompileRegex(it.key()); |
| 561 if (!compiled_regex->ok()) { |
| 562 *error = |
| 563 "/" + it.key() + "/ is a invalid regex: " + compiled_regex->error(); |
| 564 return false; |
| 565 } |
| 566 strings_.push_back(it.key()); |
| 567 property_nodes_[index].key = strings_.back().c_str(); |
| 568 if (!Parse(*dict, &property_nodes_[index].schema, |
| 569 id_map, reference_list, error)) { |
| 570 return false; |
| 571 } |
| 572 } |
| 573 CHECK_EQ(static_cast<int>(pattern_properties->size()), index - base_index); |
| 574 } |
| 575 |
| 576 if (properties_nodes_[extra].begin == properties_nodes_[extra].pattern_end) { |
| 577 properties_nodes_[extra].begin = kInvalid; |
| 578 properties_nodes_[extra].end = kInvalid; |
| 579 properties_nodes_[extra].pattern_end = kInvalid; |
494 } | 580 } |
495 | 581 |
496 return true; | 582 return true; |
497 } | 583 } |
498 | 584 |
499 bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, | 585 bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, |
500 SchemaNode* schema_node, | 586 SchemaNode* schema_node, |
501 IdMap* id_map, | 587 IdMap* id_map, |
502 ReferenceList* reference_list, | 588 ReferenceList* reference_list, |
503 std::string* error) { | 589 std::string* error) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 *error = "Invalid range restriction for int type."; | 661 *error = "Invalid range restriction for int type."; |
576 return false; | 662 return false; |
577 } | 663 } |
578 schema_node->extra = static_cast<int>(restriction_nodes_.size()); | 664 schema_node->extra = static_cast<int>(restriction_nodes_.size()); |
579 restriction_nodes_.push_back(RestrictionNode()); | 665 restriction_nodes_.push_back(RestrictionNode()); |
580 restriction_nodes_.back().ranged_restriction.max_value = max_value; | 666 restriction_nodes_.back().ranged_restriction.max_value = max_value; |
581 restriction_nodes_.back().ranged_restriction.min_value = min_value; | 667 restriction_nodes_.back().ranged_restriction.min_value = min_value; |
582 return true; | 668 return true; |
583 } | 669 } |
584 | 670 |
| 671 bool Schema::InternalStorage::ParseStringPattern( |
| 672 const base::DictionaryValue& schema, |
| 673 SchemaNode* schema_node, |
| 674 std::string* error) { |
| 675 std::string pattern; |
| 676 if (!schema.GetString(schema::kPattern, &pattern)) { |
| 677 *error = "Schema pattern must be a string."; |
| 678 return false; |
| 679 } |
| 680 re2::RE2* compiled_regex = CompileRegex(pattern); |
| 681 if (!compiled_regex->ok()) { |
| 682 *error = "/" + pattern + "/ is invalid regex: " + compiled_regex->error(); |
| 683 return false; |
| 684 } |
| 685 int index = static_cast<int>(string_enums_.size()); |
| 686 strings_.push_back(pattern); |
| 687 string_enums_.push_back(strings_.back().c_str()); |
| 688 schema_node->extra = static_cast<int>(restriction_nodes_.size()); |
| 689 restriction_nodes_.push_back(RestrictionNode()); |
| 690 restriction_nodes_.back().string_pattern_restriction.pattern_index = index; |
| 691 restriction_nodes_.back().string_pattern_restriction.pattern_index_backup = |
| 692 index; |
| 693 return true; |
| 694 } |
| 695 |
585 // static | 696 // static |
586 bool Schema::InternalStorage::ResolveReferences( | 697 bool Schema::InternalStorage::ResolveReferences( |
587 const IdMap& id_map, | 698 const IdMap& id_map, |
588 const ReferenceList& reference_list, | 699 const ReferenceList& reference_list, |
589 std::string* error) { | 700 std::string* error) { |
590 for (ReferenceList::const_iterator ref = reference_list.begin(); | 701 for (ReferenceList::const_iterator ref = reference_list.begin(); |
591 ref != reference_list.end(); ++ref) { | 702 ref != reference_list.end(); ++ref) { |
592 IdMap::const_iterator id = id_map.find(ref->first); | 703 IdMap::const_iterator id = id_map.find(ref->first); |
593 if (id == id_map.end()) { | 704 if (id == id_map.end()) { |
594 *error = "Invalid $ref: " + ref->first; | 705 *error = "Invalid $ref: " + ref->first; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 return false; | 791 return false; |
681 } | 792 } |
682 | 793 |
683 const base::DictionaryValue* dict = NULL; | 794 const base::DictionaryValue* dict = NULL; |
684 const base::ListValue* list = NULL; | 795 const base::ListValue* list = NULL; |
685 int int_value; | 796 int int_value; |
686 std::string str_value; | 797 std::string str_value; |
687 if (value.GetAsDictionary(&dict)) { | 798 if (value.GetAsDictionary(&dict)) { |
688 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 799 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
689 it.Advance()) { | 800 it.Advance()) { |
690 Schema subschema = GetProperty(it.key()); | 801 SchemaList schema_list = GetMatchingProperties(it.key()); |
691 if (!subschema.valid()) { | 802 if (schema_list.empty()) { |
692 // Unknown property was detected. | 803 // Unknown property was detected. |
693 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); | 804 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
694 if (!StrategyAllowUnknownOnTopLevel(strategy)) | 805 if (!StrategyAllowUnknownOnTopLevel(strategy)) |
695 return false; | 806 return false; |
696 } else if (!subschema.Validate(it.value(), | 807 } else { |
697 StrategyForNextLevel(strategy), | 808 for (SchemaList::iterator subschema = schema_list.begin(); |
698 error_path, | 809 subschema != schema_list.end(); ++subschema) { |
699 error)) { | 810 if (!subschema->Validate(it.value(), |
700 // Invalid property was detected. | 811 StrategyForNextLevel(strategy), |
701 AddDictKeyPrefixToPath(it.key(), error_path); | 812 error_path, |
702 if (!StrategyAllowInvalidOnTopLevel(strategy)) | 813 error)) { |
703 return false; | 814 // Invalid property was detected. |
| 815 AddDictKeyPrefixToPath(it.key(), error_path); |
| 816 if (!StrategyAllowInvalidOnTopLevel(strategy)) |
| 817 return false; |
| 818 } |
| 819 } |
704 } | 820 } |
705 } | 821 } |
706 } else if (value.GetAsList(&list)) { | 822 } else if (value.GetAsList(&list)) { |
707 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); | 823 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); |
708 ++it) { | 824 ++it) { |
709 if (!*it || | 825 if (!*it || |
710 !GetItems().Validate(**it, | 826 !GetItems().Validate(**it, |
711 StrategyForNextLevel(strategy), | 827 StrategyForNextLevel(strategy), |
712 error_path, | 828 error_path, |
713 error)) { | 829 error)) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 error_path, error, "The value type doesn't match the schema type."); | 872 error_path, error, "The value type doesn't match the schema type."); |
757 return false; | 873 return false; |
758 } | 874 } |
759 | 875 |
760 base::DictionaryValue* dict = NULL; | 876 base::DictionaryValue* dict = NULL; |
761 base::ListValue* list = NULL; | 877 base::ListValue* list = NULL; |
762 if (value->GetAsDictionary(&dict)) { | 878 if (value->GetAsDictionary(&dict)) { |
763 std::vector<std::string> drop_list; // Contains the keys to drop. | 879 std::vector<std::string> drop_list; // Contains the keys to drop. |
764 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 880 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
765 it.Advance()) { | 881 it.Advance()) { |
766 Schema subschema = GetProperty(it.key()); | 882 SchemaList schema_list = GetMatchingProperties(it.key()); |
767 if (!subschema.valid()) { | 883 if (schema_list.empty()) { |
768 // Unknown property was detected. | 884 // Unknown property was detected. |
769 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); | 885 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
770 if (StrategyAllowUnknownOnTopLevel(strategy)) | 886 if (StrategyAllowUnknownOnTopLevel(strategy)) |
771 drop_list.push_back(it.key()); | 887 drop_list.push_back(it.key()); |
772 else | 888 else |
773 return false; | 889 return false; |
774 } else { | 890 } else { |
775 base::Value* sub_value = NULL; | 891 for (SchemaList::iterator subschema = schema_list.begin(); |
776 dict->GetWithoutPathExpansion(it.key(), &sub_value); | 892 subschema != schema_list.end(); ++subschema) { |
777 if (!subschema.Normalize(sub_value, | 893 base::Value* sub_value = NULL; |
778 StrategyForNextLevel(strategy), | 894 dict->GetWithoutPathExpansion(it.key(), &sub_value); |
779 error_path, | 895 if (!subschema->Normalize(sub_value, |
780 error, | 896 StrategyForNextLevel(strategy), |
781 changed)) { | 897 error_path, |
782 // Invalid property was detected. | 898 error, |
783 AddDictKeyPrefixToPath(it.key(), error_path); | 899 changed)) { |
784 if (StrategyAllowInvalidOnTopLevel(strategy)) | 900 // Invalid property was detected. |
785 drop_list.push_back(it.key()); | 901 AddDictKeyPrefixToPath(it.key(), error_path); |
786 else | 902 if (StrategyAllowInvalidOnTopLevel(strategy)) { |
787 return false; | 903 drop_list.push_back(it.key()); |
| 904 break; |
| 905 } else { |
| 906 return false; |
| 907 } |
| 908 } |
788 } | 909 } |
789 } | 910 } |
790 } | 911 } |
791 if (changed && !drop_list.empty()) | 912 if (changed && !drop_list.empty()) |
792 *changed = true; | 913 *changed = true; |
793 for (std::vector<std::string>::const_iterator it = drop_list.begin(); | 914 for (std::vector<std::string>::const_iterator it = drop_list.begin(); |
794 it != drop_list.end(); | 915 it != drop_list.end(); |
795 ++it) { | 916 ++it) { |
796 dict->RemoveWithoutPathExpansion(*it, NULL); | 917 dict->RemoveWithoutPathExpansion(*it, NULL); |
797 } | 918 } |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
892 | 1013 |
893 Schema Schema::GetAdditionalProperties() const { | 1014 Schema Schema::GetAdditionalProperties() const { |
894 CHECK(valid()); | 1015 CHECK(valid()); |
895 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); | 1016 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
896 const PropertiesNode* node = storage_->properties(node_->extra); | 1017 const PropertiesNode* node = storage_->properties(node_->extra); |
897 if (node->additional == kInvalid) | 1018 if (node->additional == kInvalid) |
898 return Schema(); | 1019 return Schema(); |
899 return Schema(storage_, storage_->schema(node->additional)); | 1020 return Schema(storage_, storage_->schema(node->additional)); |
900 } | 1021 } |
901 | 1022 |
| 1023 SchemaList Schema::GetPatternProperties(const std::string& key) const { |
| 1024 CHECK(valid()); |
| 1025 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
| 1026 const PropertiesNode* node = storage_->properties(node_->extra); |
| 1027 const PropertyNode* begin = storage_->property(node->end); |
| 1028 const PropertyNode* end = storage_->property(node->pattern_end); |
| 1029 SchemaList matching_properties; |
| 1030 for (const PropertyNode* it = begin; it != end; ++it) { |
| 1031 if (re2::RE2::PartialMatch(key, *storage_->CompileRegex(it->key))) { |
| 1032 matching_properties.push_back( |
| 1033 Schema(storage_, storage_->schema(it->schema))); |
| 1034 } |
| 1035 } |
| 1036 return matching_properties; |
| 1037 } |
| 1038 |
902 Schema Schema::GetProperty(const std::string& key) const { | 1039 Schema Schema::GetProperty(const std::string& key) const { |
903 Schema schema = GetKnownProperty(key); | 1040 Schema schema = GetKnownProperty(key); |
904 return schema.valid() ? schema : GetAdditionalProperties(); | 1041 if (schema.valid()) |
| 1042 return schema; |
| 1043 return GetAdditionalProperties(); |
| 1044 } |
| 1045 |
| 1046 SchemaList Schema::GetMatchingProperties(const std::string& key) const { |
| 1047 SchemaList schema_list; |
| 1048 |
| 1049 Schema known_property = GetKnownProperty(key); |
| 1050 if (known_property.valid()) |
| 1051 schema_list.push_back(known_property); |
| 1052 |
| 1053 SchemaList pattern_properties = GetPatternProperties(key); |
| 1054 schema_list.insert( |
| 1055 schema_list.end(), pattern_properties.begin(), pattern_properties.end()); |
| 1056 |
| 1057 if (schema_list.empty()) { |
| 1058 Schema additional_property = GetAdditionalProperties(); |
| 1059 if (additional_property.valid()) |
| 1060 schema_list.push_back(additional_property); |
| 1061 } |
| 1062 |
| 1063 return schema_list; |
905 } | 1064 } |
906 | 1065 |
907 Schema Schema::GetItems() const { | 1066 Schema Schema::GetItems() const { |
908 CHECK(valid()); | 1067 CHECK(valid()); |
909 CHECK_EQ(base::Value::TYPE_LIST, type()); | 1068 CHECK_EQ(base::Value::TYPE_LIST, type()); |
910 if (node_->extra == kInvalid) | 1069 if (node_->extra == kInvalid) |
911 return Schema(); | 1070 return Schema(); |
912 return Schema(storage_, storage_->schema(node_->extra)); | 1071 return Schema(storage_, storage_->schema(node_->extra)); |
913 } | 1072 } |
914 | 1073 |
915 bool Schema::ValidateIntegerRestriction(int index, int value) const { | 1074 bool Schema::ValidateIntegerRestriction(int index, int value) const { |
916 const RestrictionNode* rnode = storage_->restriction(index); | 1075 const RestrictionNode* rnode = storage_->restriction(index); |
917 if (rnode->ranged_restriction.min_value <= | 1076 if (rnode->ranged_restriction.min_value <= |
918 rnode->ranged_restriction.max_value) { | 1077 rnode->ranged_restriction.max_value) { |
919 return rnode->ranged_restriction.min_value <= value && | 1078 return rnode->ranged_restriction.min_value <= value && |
920 rnode->ranged_restriction.max_value >= value; | 1079 rnode->ranged_restriction.max_value >= value; |
921 } else { | 1080 } else { |
922 for (int i = rnode->enumeration_restriction.offset_begin; | 1081 for (int i = rnode->enumeration_restriction.offset_begin; |
923 i < rnode->enumeration_restriction.offset_end; i++) { | 1082 i < rnode->enumeration_restriction.offset_end; ++i) { |
924 if (*storage_->int_enums(i) == value) | 1083 if (*storage_->int_enums(i) == value) |
925 return true; | 1084 return true; |
926 } | 1085 } |
927 return false; | 1086 return false; |
928 } | 1087 } |
929 } | 1088 } |
930 | 1089 |
931 bool Schema::ValidateStringRestriction(int index, const char* str) const { | 1090 bool Schema::ValidateStringRestriction(int index, const char* str) const { |
932 const RestrictionNode* rnode = storage_->restriction(index); | 1091 const RestrictionNode* rnode = storage_->restriction(index); |
933 for (int i = rnode->enumeration_restriction.offset_begin; | 1092 if (rnode->enumeration_restriction.offset_begin < |
934 i < rnode->enumeration_restriction.offset_end; i++) { | 1093 rnode->enumeration_restriction.offset_end) { |
935 if (strcmp(*storage_->string_enums(i), str) == 0) | 1094 for (int i = rnode->enumeration_restriction.offset_begin; |
936 return true; | 1095 i < rnode->enumeration_restriction.offset_end; ++i) { |
| 1096 if (strcmp(*storage_->string_enums(i), str) == 0) |
| 1097 return true; |
| 1098 } |
| 1099 return false; |
| 1100 } else { |
| 1101 int index = rnode->string_pattern_restriction.pattern_index; |
| 1102 DCHECK(index == rnode->string_pattern_restriction.pattern_index_backup); |
| 1103 re2::RE2* regex = storage_->CompileRegex(*storage_->string_enums(index)); |
| 1104 return re2::RE2::PartialMatch(str, *regex); |
937 } | 1105 } |
938 return false; | |
939 } | 1106 } |
940 | 1107 |
941 } // namespace policy | 1108 } // namespace policy |
OLD | NEW |