| 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 |