Chromium Code Reviews| 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> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/memory/scoped_vector.h" | 16 #include "base/memory/scoped_vector.h" |
| 17 #include "base/stl_util.h" | |
| 16 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 17 #include "components/json_schema/json_schema_constants.h" | 19 #include "components/json_schema/json_schema_constants.h" |
| 18 #include "components/json_schema/json_schema_validator.h" | 20 #include "components/json_schema/json_schema_validator.h" |
| 19 #include "components/policy/core/common/schema_internal.h" | 21 #include "components/policy/core/common/schema_internal.h" |
| 22 #include "third_party/re2/re2/re2.h" | |
| 20 | 23 |
| 21 namespace schema = json_schema_constants; | 24 namespace schema = json_schema_constants; |
| 22 | 25 |
| 23 namespace policy { | 26 namespace policy { |
| 24 | 27 |
| 25 using internal::PropertiesNode; | 28 using internal::PropertiesNode; |
| 26 using internal::PropertyNode; | 29 using internal::PropertyNode; |
| 27 using internal::RestrictionNode; | 30 using internal::RestrictionNode; |
| 28 using internal::SchemaData; | 31 using internal::SchemaData; |
| 29 using internal::SchemaNode; | 32 using internal::SchemaNode; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 } | 171 } |
| 169 | 172 |
| 170 const int* int_enums(int index) const { | 173 const int* int_enums(int index) const { |
| 171 return schema_data_.int_enums + index; | 174 return schema_data_.int_enums + index; |
| 172 } | 175 } |
| 173 | 176 |
| 174 const char** string_enums(int index) const { | 177 const char** string_enums(int index) const { |
| 175 return schema_data_.string_enums + index; | 178 return schema_data_.string_enums + index; |
| 176 } | 179 } |
| 177 | 180 |
| 181 // Compiles regular expression |pattern|. The result is cached and will be | |
| 182 // returned directly next time. | |
| 183 re2::RE2* CompileRegex(const std::string &pattern) const; | |
|
Joao da Silva
2014/03/21 12:58:12
const std::string& pattern
binjin
2014/03/27 17:57:47
Done.
| |
| 184 | |
| 178 private: | 185 private: |
| 179 friend class base::RefCountedThreadSafe<InternalStorage>; | 186 friend class base::RefCountedThreadSafe<InternalStorage>; |
| 180 | 187 |
| 181 InternalStorage(); | 188 InternalStorage(); |
| 182 ~InternalStorage(); | 189 ~InternalStorage(); |
| 183 | 190 |
| 184 // Determines the expected |sizes| of the storage for the representation | 191 // Determines the expected |sizes| of the storage for the representation |
| 185 // of |schema|. | 192 // of |schema|. |
| 186 static void DetermineStorageSizes(const base::DictionaryValue& schema, | 193 static void DetermineStorageSizes(const base::DictionaryValue& schema, |
| 187 StorageSizes* sizes); | 194 StorageSizes* sizes); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 | 228 |
| 222 bool ParseEnum(const base::DictionaryValue& schema, | 229 bool ParseEnum(const base::DictionaryValue& schema, |
| 223 base::Value::Type type, | 230 base::Value::Type type, |
| 224 SchemaNode* schema_node, | 231 SchemaNode* schema_node, |
| 225 std::string* error); | 232 std::string* error); |
| 226 | 233 |
| 227 bool ParseRangedInt(const base::DictionaryValue& schema, | 234 bool ParseRangedInt(const base::DictionaryValue& schema, |
| 228 SchemaNode* schema_node, | 235 SchemaNode* schema_node, |
| 229 std::string* error); | 236 std::string* error); |
| 230 | 237 |
| 238 bool ParseStringPattern(const base::DictionaryValue& schema, | |
| 239 SchemaNode* schema_node, | |
| 240 std::string* error); | |
| 241 | |
| 231 // Assigns the IDs in |id_map| to the pending references in the | 242 // 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 | 243 // |reference_list|. If an ID is missing then |error| is set and false is |
| 233 // returned; otherwise returns true. | 244 // returned; otherwise returns true. |
| 234 static bool ResolveReferences(const IdMap& id_map, | 245 static bool ResolveReferences(const IdMap& id_map, |
| 235 const ReferenceList& reference_list, | 246 const ReferenceList& reference_list, |
| 236 std::string* error); | 247 std::string* error); |
| 237 | 248 |
| 249 mutable std::map<std::string, re2::RE2*> regex_cache_; | |
|
Joao da Silva
2014/03/21 12:58:12
Argh, mutable. I think it's better than complicati
binjin
2014/03/27 17:57:47
Done.
| |
| 250 STLValueDeleter<std::map<std::string, re2::RE2*> > cache_deleter_; | |
| 251 | |
| 238 SchemaData schema_data_; | 252 SchemaData schema_data_; |
| 239 std::vector<std::string> strings_; | 253 std::vector<std::string> strings_; |
| 240 std::vector<SchemaNode> schema_nodes_; | 254 std::vector<SchemaNode> schema_nodes_; |
| 241 std::vector<PropertyNode> property_nodes_; | 255 std::vector<PropertyNode> property_nodes_; |
| 242 std::vector<PropertiesNode> properties_nodes_; | 256 std::vector<PropertiesNode> properties_nodes_; |
| 243 std::vector<RestrictionNode> restriction_nodes_; | 257 std::vector<RestrictionNode> restriction_nodes_; |
| 244 std::vector<int> int_enums_; | 258 std::vector<int> int_enums_; |
| 245 std::vector<const char*> string_enums_; | 259 std::vector<const char*> string_enums_; |
| 246 | 260 |
| 247 DISALLOW_COPY_AND_ASSIGN(InternalStorage); | 261 DISALLOW_COPY_AND_ASSIGN(InternalStorage); |
| 248 }; | 262 }; |
| 249 | 263 |
| 250 Schema::InternalStorage::InternalStorage() {} | 264 Schema::InternalStorage::InternalStorage() : cache_deleter_(®ex_cache_) {} |
| 251 | 265 |
| 252 Schema::InternalStorage::~InternalStorage() {} | 266 Schema::InternalStorage::~InternalStorage() {} |
| 253 | 267 |
| 254 // static | 268 // static |
| 255 scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( | 269 scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( |
| 256 const SchemaData* data) { | 270 const SchemaData* data) { |
| 257 InternalStorage* storage = new InternalStorage(); | 271 InternalStorage* storage = new InternalStorage(); |
| 258 storage->schema_data_.schema_nodes = data->schema_nodes; | 272 storage->schema_data_.schema_nodes = data->schema_nodes; |
| 259 storage->schema_data_.property_nodes = data->property_nodes; | 273 storage->schema_data_.property_nodes = data->property_nodes; |
| 260 storage->schema_data_.properties_nodes = data->properties_nodes; | 274 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_; | 331 SchemaData* data = &storage->schema_data_; |
| 318 data->schema_nodes = vector_as_array(&storage->schema_nodes_); | 332 data->schema_nodes = vector_as_array(&storage->schema_nodes_); |
| 319 data->property_nodes = vector_as_array(&storage->property_nodes_); | 333 data->property_nodes = vector_as_array(&storage->property_nodes_); |
| 320 data->properties_nodes = vector_as_array(&storage->properties_nodes_); | 334 data->properties_nodes = vector_as_array(&storage->properties_nodes_); |
| 321 data->restriction_nodes = vector_as_array(&storage->restriction_nodes_); | 335 data->restriction_nodes = vector_as_array(&storage->restriction_nodes_); |
| 322 data->int_enums = vector_as_array(&storage->int_enums_); | 336 data->int_enums = vector_as_array(&storage->int_enums_); |
| 323 data->string_enums = vector_as_array(&storage->string_enums_); | 337 data->string_enums = vector_as_array(&storage->string_enums_); |
| 324 return storage; | 338 return storage; |
| 325 } | 339 } |
| 326 | 340 |
| 341 re2::RE2* Schema::InternalStorage::CompileRegex( | |
| 342 const std::string& pattern) const { | |
| 343 std::map<std::string, re2::RE2*>::iterator it = regex_cache_.find(pattern); | |
| 344 if (it == regex_cache_.end()) { | |
| 345 re2::RE2* compiled = new re2::RE2(pattern); | |
| 346 regex_cache_[pattern] = compiled; | |
| 347 return compiled; | |
| 348 } | |
| 349 return it->second; | |
| 350 } | |
| 351 | |
| 327 // static | 352 // static |
| 328 void Schema::InternalStorage::DetermineStorageSizes( | 353 void Schema::InternalStorage::DetermineStorageSizes( |
| 329 const base::DictionaryValue& schema, | 354 const base::DictionaryValue& schema, |
| 330 StorageSizes* sizes) { | 355 StorageSizes* sizes) { |
| 331 std::string ref_string; | 356 std::string ref_string; |
| 332 if (schema.GetString(schema::kRef, &ref_string)) { | 357 if (schema.GetString(schema::kRef, &ref_string)) { |
| 333 // Schemas with a "$ref" attribute don't take additional storage. | 358 // Schemas with a "$ref" attribute don't take additional storage. |
| 334 return; | 359 return; |
| 335 } | 360 } |
| 336 | 361 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 359 if (schema.GetDictionary(schema::kProperties, &properties)) { | 384 if (schema.GetDictionary(schema::kProperties, &properties)) { |
| 360 for (base::DictionaryValue::Iterator it(*properties); | 385 for (base::DictionaryValue::Iterator it(*properties); |
| 361 !it.IsAtEnd(); it.Advance()) { | 386 !it.IsAtEnd(); it.Advance()) { |
| 362 // This should have been verified by the JSONSchemaValidator. | 387 // This should have been verified by the JSONSchemaValidator. |
| 363 CHECK(it.value().GetAsDictionary(&dict)); | 388 CHECK(it.value().GetAsDictionary(&dict)); |
| 364 DetermineStorageSizes(*dict, sizes); | 389 DetermineStorageSizes(*dict, sizes); |
| 365 sizes->strings++; | 390 sizes->strings++; |
| 366 sizes->property_nodes++; | 391 sizes->property_nodes++; |
| 367 } | 392 } |
| 368 } | 393 } |
| 394 | |
| 395 const base::DictionaryValue* pattern_properties = NULL; | |
| 396 if (schema.GetDictionary(schema::kPatternProperties, &pattern_properties)) { | |
| 397 for (base::DictionaryValue::Iterator it(*pattern_properties); | |
| 398 !it.IsAtEnd(); it.Advance()) { | |
| 399 CHECK(it.value().GetAsDictionary(&dict)); | |
| 400 DetermineStorageSizes(*dict, sizes); | |
| 401 sizes->strings++; | |
| 402 sizes->property_nodes++; | |
| 403 } | |
| 404 } | |
| 369 } else if (schema.HasKey(schema::kEnum)) { | 405 } else if (schema.HasKey(schema::kEnum)) { |
| 370 const base::ListValue* possible_values = NULL; | 406 const base::ListValue* possible_values = NULL; |
| 371 if (schema.GetList(schema::kEnum, &possible_values)) { | 407 if (schema.GetList(schema::kEnum, &possible_values)) { |
| 372 if (type == base::Value::TYPE_INTEGER) { | 408 if (type == base::Value::TYPE_INTEGER) { |
| 373 sizes->int_enums += possible_values->GetSize(); | 409 sizes->int_enums += possible_values->GetSize(); |
| 374 } else if (type == base::Value::TYPE_STRING) { | 410 } else if (type == base::Value::TYPE_STRING) { |
| 375 sizes->string_enums += possible_values->GetSize(); | 411 sizes->string_enums += possible_values->GetSize(); |
| 376 sizes->strings += possible_values->GetSize(); | 412 sizes->strings += possible_values->GetSize(); |
| 377 } | 413 } |
| 378 sizes->restriction_nodes++; | 414 sizes->restriction_nodes++; |
| 379 } | 415 } |
| 380 } else if (type == base::Value::TYPE_INTEGER) { | 416 } else if (type == base::Value::TYPE_INTEGER) { |
| 381 if (schema.HasKey(schema::kMinimum) || schema.HasKey(schema::kMaximum)) | 417 if (schema.HasKey(schema::kMinimum) || schema.HasKey(schema::kMaximum)) |
| 382 sizes->restriction_nodes++; | 418 sizes->restriction_nodes++; |
| 419 } else if (type == base::Value::TYPE_STRING) { | |
| 420 if (schema.HasKey(schema::kPattern)) { | |
| 421 sizes->strings++; | |
| 422 sizes->string_enums ++; | |
|
Joao da Silva
2014/03/21 12:58:12
nit: remove space before ++
binjin
2014/03/27 17:57:47
Done.
| |
| 423 sizes->restriction_nodes++; | |
| 424 } | |
| 383 } | 425 } |
| 384 } | 426 } |
| 385 | 427 |
| 386 bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, | 428 bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, |
| 387 int* index, | 429 int* index, |
| 388 IdMap* id_map, | 430 IdMap* id_map, |
| 389 ReferenceList* reference_list, | 431 ReferenceList* reference_list, |
| 390 std::string* error) { | 432 std::string* error) { |
| 391 std::string ref_string; | 433 std::string ref_string; |
| 392 if (schema.GetString(schema::kRef, &ref_string)) { | 434 if (schema.GetString(schema::kRef, &ref_string)) { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 419 | 461 |
| 420 if (type == base::Value::TYPE_DICTIONARY) { | 462 if (type == base::Value::TYPE_DICTIONARY) { |
| 421 if (!ParseDictionary(schema, schema_node, id_map, reference_list, error)) | 463 if (!ParseDictionary(schema, schema_node, id_map, reference_list, error)) |
| 422 return false; | 464 return false; |
| 423 } else if (type == base::Value::TYPE_LIST) { | 465 } else if (type == base::Value::TYPE_LIST) { |
| 424 if (!ParseList(schema, schema_node, id_map, reference_list, error)) | 466 if (!ParseList(schema, schema_node, id_map, reference_list, error)) |
| 425 return false; | 467 return false; |
| 426 } else if (schema.HasKey(schema::kEnum)) { | 468 } else if (schema.HasKey(schema::kEnum)) { |
| 427 if (!ParseEnum(schema, type, schema_node, error)) | 469 if (!ParseEnum(schema, type, schema_node, error)) |
| 428 return false; | 470 return false; |
| 471 } else if (schema.HasKey(schema::kPattern)) { | |
| 472 if (!ParseStringPattern(schema, schema_node, error)) | |
| 473 return false; | |
| 429 } else if (schema.HasKey(schema::kMinimum) || | 474 } else if (schema.HasKey(schema::kMinimum) || |
| 430 schema.HasKey(schema::kMaximum)) { | 475 schema.HasKey(schema::kMaximum)) { |
| 431 if (type != base::Value::TYPE_INTEGER) { | 476 if (type != base::Value::TYPE_INTEGER) { |
| 432 *error = "Only integers can have minimum and maximum"; | 477 *error = "Only integers can have minimum and maximum"; |
| 433 return false; | 478 return false; |
| 434 } | 479 } |
| 435 if (!ParseRangedInt(schema, schema_node, error)) | 480 if (!ParseRangedInt(schema, schema_node, error)) |
| 436 return false; | 481 return false; |
| 437 } | 482 } |
| 438 std::string id_string; | 483 std::string id_string; |
| 439 if (schema.GetString(schema::kId, &id_string)) { | 484 if (schema.GetString(schema::kId, &id_string)) { |
| 440 if (ContainsKey(*id_map, id_string)) { | 485 if (ContainsKey(*id_map, id_string)) { |
| 441 *error = "Duplicated id: " + id_string; | 486 *error = "Duplicated id: " + id_string; |
| 442 return false; | 487 return false; |
| 443 } | 488 } |
| 444 (*id_map)[id_string] = *index; | 489 (*id_map)[id_string] = *index; |
| 445 } | 490 } |
| 446 | 491 |
| 447 return true; | 492 return true; |
| 448 } | 493 } |
| 449 | 494 |
| 450 bool Schema::InternalStorage::ParseDictionary( | 495 bool Schema::InternalStorage::ParseDictionary( |
| 451 const base::DictionaryValue& schema, | 496 const base::DictionaryValue& schema, |
| 452 SchemaNode* schema_node, | 497 SchemaNode* schema_node, |
| 453 IdMap* id_map, | 498 IdMap* id_map, |
| 454 ReferenceList* reference_list, | 499 ReferenceList* reference_list, |
| 455 std::string* error) { | 500 std::string* error) { |
| 456 int extra = static_cast<int>(properties_nodes_.size()); | 501 int extra = static_cast<int>(properties_nodes_.size()); |
| 457 properties_nodes_.push_back(PropertiesNode()); | 502 properties_nodes_.push_back(PropertiesNode()); |
| 458 properties_nodes_[extra].begin = kInvalid; | |
| 459 properties_nodes_[extra].end = kInvalid; | |
| 460 properties_nodes_[extra].additional = kInvalid; | 503 properties_nodes_[extra].additional = kInvalid; |
| 461 schema_node->extra = extra; | 504 schema_node->extra = extra; |
| 462 | 505 |
| 463 const base::DictionaryValue* dict = NULL; | 506 const base::DictionaryValue* dict = NULL; |
| 464 if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) { | 507 if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) { |
| 465 if (!Parse(*dict, &properties_nodes_[extra].additional, | 508 if (!Parse(*dict, &properties_nodes_[extra].additional, |
| 466 id_map, reference_list, error)) { | 509 id_map, reference_list, error)) { |
| 467 return false; | 510 return false; |
| 468 } | 511 } |
| 469 } | 512 } |
| 470 | 513 |
| 514 properties_nodes_[extra].begin = static_cast<int>(property_nodes_.size()); | |
| 515 | |
| 471 const base::DictionaryValue* properties = NULL; | 516 const base::DictionaryValue* properties = NULL; |
| 472 if (schema.GetDictionary(schema::kProperties, &properties)) { | 517 if (schema.GetDictionary(schema::kProperties, &properties)) |
| 473 int base_index = static_cast<int>(property_nodes_.size()); | 518 property_nodes_.resize(property_nodes_.size() + properties->size()); |
| 474 // This reserves nodes for all of the |properties|, and makes sure they | |
| 475 // are contiguous. Recursive calls to Parse() will append after these | |
| 476 // elements. | |
|
Joao da Silva
2014/03/21 12:58:12
Please leave this comment included.
binjin
2014/03/27 17:57:47
Done.
| |
| 477 property_nodes_.resize(base_index + properties->size()); | |
| 478 | 519 |
| 520 properties_nodes_[extra].end = static_cast<int>(property_nodes_.size()); | |
| 521 | |
| 522 const base::DictionaryValue* pattern_properties = NULL; | |
| 523 if (schema.GetDictionary(schema::kPatternProperties, &pattern_properties)) | |
| 524 property_nodes_.resize(property_nodes_.size() + pattern_properties->size()); | |
| 525 | |
| 526 properties_nodes_[extra].pattern_end = | |
| 527 static_cast<int>(property_nodes_.size()); | |
| 528 | |
| 529 if (properties != NULL) { | |
| 530 int base_index = properties_nodes_[extra].begin; | |
| 479 int index = base_index; | 531 int index = base_index; |
| 532 | |
| 480 for (base::DictionaryValue::Iterator it(*properties); | 533 for (base::DictionaryValue::Iterator it(*properties); |
| 481 !it.IsAtEnd(); it.Advance(), ++index) { | 534 !it.IsAtEnd(); it.Advance(), ++index) { |
| 482 // This should have been verified by the JSONSchemaValidator. | 535 // This should have been verified by the JSONSchemaValidator. |
| 483 CHECK(it.value().GetAsDictionary(&dict)); | 536 CHECK(it.value().GetAsDictionary(&dict)); |
| 484 strings_.push_back(it.key()); | 537 strings_.push_back(it.key()); |
| 485 property_nodes_[index].key = strings_.back().c_str(); | 538 property_nodes_[index].key = strings_.back().c_str(); |
| 486 if (!Parse(*dict, &property_nodes_[index].schema, | 539 if (!Parse(*dict, &property_nodes_[index].schema, |
| 487 id_map, reference_list, error)) { | 540 id_map, reference_list, error)) { |
| 488 return false; | 541 return false; |
| 489 } | 542 } |
| 490 } | 543 } |
| 491 CHECK_EQ(static_cast<int>(properties->size()), index - base_index); | 544 CHECK_EQ(static_cast<int>(properties->size()), index - base_index); |
| 492 properties_nodes_[extra].begin = base_index; | 545 } |
| 493 properties_nodes_[extra].end = index; | 546 |
| 547 if (pattern_properties != NULL) { | |
| 548 int base_index = properties_nodes_[extra].end; | |
| 549 int index = base_index; | |
| 550 | |
| 551 for (base::DictionaryValue::Iterator it(*pattern_properties); | |
| 552 !it.IsAtEnd(); it.Advance(), ++index) { | |
| 553 CHECK(it.value().GetAsDictionary(&dict)); | |
| 554 if (!CompileRegex(it.key())->ok()) { | |
| 555 *error = "Invalid regex: /" + it.key() + "/."; | |
|
Joao da Silva
2014/03/21 12:58:12
Include the ->error()
binjin
2014/03/27 17:57:47
Done.
| |
| 556 return false; | |
| 557 } | |
| 558 strings_.push_back(it.key()); | |
| 559 property_nodes_[index].key = strings_.back().c_str(); | |
| 560 if (!Parse(*dict, &property_nodes_[index].schema, | |
| 561 id_map, reference_list, error)) { | |
| 562 return false; | |
| 563 } | |
| 564 } | |
| 565 CHECK_EQ(static_cast<int>(pattern_properties->size()), index - base_index); | |
| 566 } | |
| 567 | |
| 568 if (properties_nodes_[extra].begin == properties_nodes_[extra].pattern_end) { | |
| 569 properties_nodes_[extra].begin = kInvalid; | |
| 570 properties_nodes_[extra].end = kInvalid; | |
| 571 properties_nodes_[extra].pattern_end = kInvalid; | |
| 494 } | 572 } |
| 495 | 573 |
| 496 return true; | 574 return true; |
| 497 } | 575 } |
| 498 | 576 |
| 499 bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, | 577 bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, |
| 500 SchemaNode* schema_node, | 578 SchemaNode* schema_node, |
| 501 IdMap* id_map, | 579 IdMap* id_map, |
| 502 ReferenceList* reference_list, | 580 ReferenceList* reference_list, |
| 503 std::string* error) { | 581 std::string* error) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 *error = "Invalid range restriction for int type."; | 653 *error = "Invalid range restriction for int type."; |
| 576 return false; | 654 return false; |
| 577 } | 655 } |
| 578 schema_node->extra = static_cast<int>(restriction_nodes_.size()); | 656 schema_node->extra = static_cast<int>(restriction_nodes_.size()); |
| 579 restriction_nodes_.push_back(RestrictionNode()); | 657 restriction_nodes_.push_back(RestrictionNode()); |
| 580 restriction_nodes_.back().ranged_restriction.max_value = max_value; | 658 restriction_nodes_.back().ranged_restriction.max_value = max_value; |
| 581 restriction_nodes_.back().ranged_restriction.min_value = min_value; | 659 restriction_nodes_.back().ranged_restriction.min_value = min_value; |
| 582 return true; | 660 return true; |
| 583 } | 661 } |
| 584 | 662 |
| 663 bool Schema::InternalStorage::ParseStringPattern( | |
| 664 const base::DictionaryValue& schema, | |
| 665 SchemaNode* schema_node, | |
| 666 std::string* error) { | |
| 667 std::string pattern; | |
| 668 if (!schema.GetString(schema::kPattern, &pattern)) { | |
| 669 *error = "Schema pattern must be a string."; | |
| 670 return false; | |
| 671 } | |
| 672 if (!CompileRegex(pattern)->ok()) { | |
| 673 *error = "Invalid regex: /" + pattern + "/."; | |
|
Joao da Silva
2014/03/21 12:58:12
Include the ->error() in this message too
binjin
2014/03/27 17:57:47
Done.
| |
| 674 return false; | |
| 675 } | |
| 676 int index = static_cast<int>(string_enums_.size()); | |
| 677 strings_.push_back(pattern); | |
| 678 string_enums_.push_back(strings_.back().c_str()); | |
| 679 schema_node->extra = static_cast<int>(restriction_nodes_.size()); | |
| 680 restriction_nodes_.push_back(RestrictionNode()); | |
| 681 restriction_nodes_.back().string_pattern_restriction.pattern_index = index; | |
| 682 restriction_nodes_.back().string_pattern_restriction.pattern_index_backup = | |
| 683 index; | |
| 684 return true; | |
| 685 } | |
| 686 | |
| 585 // static | 687 // static |
| 586 bool Schema::InternalStorage::ResolveReferences( | 688 bool Schema::InternalStorage::ResolveReferences( |
| 587 const IdMap& id_map, | 689 const IdMap& id_map, |
| 588 const ReferenceList& reference_list, | 690 const ReferenceList& reference_list, |
| 589 std::string* error) { | 691 std::string* error) { |
| 590 for (ReferenceList::const_iterator ref = reference_list.begin(); | 692 for (ReferenceList::const_iterator ref = reference_list.begin(); |
| 591 ref != reference_list.end(); ++ref) { | 693 ref != reference_list.end(); ++ref) { |
| 592 IdMap::const_iterator id = id_map.find(ref->first); | 694 IdMap::const_iterator id = id_map.find(ref->first); |
| 593 if (id == id_map.end()) { | 695 if (id == id_map.end()) { |
| 594 *error = "Invalid $ref: " + ref->first; | 696 *error = "Invalid $ref: " + ref->first; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 680 return false; | 782 return false; |
| 681 } | 783 } |
| 682 | 784 |
| 683 const base::DictionaryValue* dict = NULL; | 785 const base::DictionaryValue* dict = NULL; |
| 684 const base::ListValue* list = NULL; | 786 const base::ListValue* list = NULL; |
| 685 int int_value; | 787 int int_value; |
| 686 std::string str_value; | 788 std::string str_value; |
| 687 if (value.GetAsDictionary(&dict)) { | 789 if (value.GetAsDictionary(&dict)) { |
| 688 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 790 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
| 689 it.Advance()) { | 791 it.Advance()) { |
| 690 Schema subschema = GetProperty(it.key()); | 792 Schema subschema = GetProperty(it.key()); |
|
Joao da Silva
2014/03/21 12:58:12
This needs to be updated to validate against all p
binjin
2014/04/01 12:29:36
Done. But I think schema from pattern_properties a
| |
| 691 if (!subschema.valid()) { | 793 if (!subschema.valid()) { |
| 692 // Unknown property was detected. | 794 // Unknown property was detected. |
| 693 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); | 795 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
| 694 if (!StrategyAllowUnknownOnTopLevel(strategy)) | 796 if (!StrategyAllowUnknownOnTopLevel(strategy)) |
| 695 return false; | 797 return false; |
| 696 } else if (!subschema.Validate(it.value(), | 798 } else if (!subschema.Validate(it.value(), |
| 697 StrategyForNextLevel(strategy), | 799 StrategyForNextLevel(strategy), |
| 698 error_path, | 800 error_path, |
| 699 error)) { | 801 error)) { |
| 700 // Invalid property was detected. | 802 // Invalid property was detected. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 error_path, error, "The value type doesn't match the schema type."); | 858 error_path, error, "The value type doesn't match the schema type."); |
| 757 return false; | 859 return false; |
| 758 } | 860 } |
| 759 | 861 |
| 760 base::DictionaryValue* dict = NULL; | 862 base::DictionaryValue* dict = NULL; |
| 761 base::ListValue* list = NULL; | 863 base::ListValue* list = NULL; |
| 762 if (value->GetAsDictionary(&dict)) { | 864 if (value->GetAsDictionary(&dict)) { |
| 763 std::vector<std::string> drop_list; // Contains the keys to drop. | 865 std::vector<std::string> drop_list; // Contains the keys to drop. |
| 764 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 866 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
| 765 it.Advance()) { | 867 it.Advance()) { |
| 766 Schema subschema = GetProperty(it.key()); | 868 Schema subschema = GetProperty(it.key()); |
|
Joao da Silva
2014/03/21 12:58:12
Similar fixes here to handle GetPatternProperties(
binjin
2014/04/01 12:29:36
Done.
| |
| 767 if (!subschema.valid()) { | 869 if (!subschema.valid()) { |
| 768 // Unknown property was detected. | 870 // Unknown property was detected. |
| 769 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); | 871 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
| 770 if (StrategyAllowUnknownOnTopLevel(strategy)) | 872 if (StrategyAllowUnknownOnTopLevel(strategy)) |
| 771 drop_list.push_back(it.key()); | 873 drop_list.push_back(it.key()); |
| 772 else | 874 else |
| 773 return false; | 875 return false; |
| 774 } else { | 876 } else { |
| 775 base::Value* sub_value = NULL; | 877 base::Value* sub_value = NULL; |
| 776 dict->GetWithoutPathExpansion(it.key(), &sub_value); | 878 dict->GetWithoutPathExpansion(it.key(), &sub_value); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 892 | 994 |
| 893 Schema Schema::GetAdditionalProperties() const { | 995 Schema Schema::GetAdditionalProperties() const { |
| 894 CHECK(valid()); | 996 CHECK(valid()); |
| 895 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); | 997 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
| 896 const PropertiesNode* node = storage_->properties(node_->extra); | 998 const PropertiesNode* node = storage_->properties(node_->extra); |
| 897 if (node->additional == kInvalid) | 999 if (node->additional == kInvalid) |
| 898 return Schema(); | 1000 return Schema(); |
| 899 return Schema(storage_, storage_->schema(node->additional)); | 1001 return Schema(storage_, storage_->schema(node->additional)); |
| 900 } | 1002 } |
| 901 | 1003 |
| 1004 Schema Schema::GetPatternProperty(const std::string& key) const { | |
| 1005 CHECK(valid()); | |
| 1006 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); | |
| 1007 const PropertiesNode* node = storage_->properties(node_->extra); | |
| 1008 const PropertyNode* begin = storage_->property(node->end); | |
| 1009 const PropertyNode* end = storage_->property(node->pattern_end); | |
| 1010 for (const PropertyNode* it = begin; it != end; ++it) { | |
| 1011 if (re2::RE2::PartialMatch(key, *storage_->CompileRegex(begin->key))) | |
|
Joao da Silva
2014/03/21 12:58:12
begin->key should be it->key
binjin
2014/03/27 17:57:47
Done.
| |
| 1012 return Schema(storage_, storage_->schema(it->schema)); | |
| 1013 } | |
| 1014 return Schema(); | |
| 1015 } | |
| 1016 | |
| 902 Schema Schema::GetProperty(const std::string& key) const { | 1017 Schema Schema::GetProperty(const std::string& key) const { |
|
Joao da Silva
2014/03/21 12:58:12
So this method is just a helper to mix GetKnownPro
binjin
2014/04/01 12:29:36
I deprecated this function, as it's a little bit c
| |
| 903 Schema schema = GetKnownProperty(key); | 1018 Schema schema = GetKnownProperty(key); |
| 904 return schema.valid() ? schema : GetAdditionalProperties(); | 1019 if (schema.valid()) |
| 1020 return schema; | |
| 1021 // This is slightly different from json schema standard. We won't match the | |
| 1022 // key against "patternProperty" regular expressions if it's already | |
| 1023 // presented by "property" attribute. | |
| 1024 schema = GetPatternProperty(key); | |
| 1025 if (schema.valid()) | |
| 1026 return schema; | |
| 1027 return GetAdditionalProperties(); | |
| 905 } | 1028 } |
| 906 | 1029 |
| 907 Schema Schema::GetItems() const { | 1030 Schema Schema::GetItems() const { |
| 908 CHECK(valid()); | 1031 CHECK(valid()); |
| 909 CHECK_EQ(base::Value::TYPE_LIST, type()); | 1032 CHECK_EQ(base::Value::TYPE_LIST, type()); |
| 910 if (node_->extra == kInvalid) | 1033 if (node_->extra == kInvalid) |
| 911 return Schema(); | 1034 return Schema(); |
| 912 return Schema(storage_, storage_->schema(node_->extra)); | 1035 return Schema(storage_, storage_->schema(node_->extra)); |
| 913 } | 1036 } |
| 914 | 1037 |
| 915 bool Schema::ValidateIntegerRestriction(int index, int value) const { | 1038 bool Schema::ValidateIntegerRestriction(int index, int value) const { |
| 916 const RestrictionNode* rnode = storage_->restriction(index); | 1039 const RestrictionNode* rnode = storage_->restriction(index); |
| 917 if (rnode->ranged_restriction.min_value <= | 1040 if (rnode->ranged_restriction.min_value <= |
| 918 rnode->ranged_restriction.max_value) { | 1041 rnode->ranged_restriction.max_value) { |
| 919 return rnode->ranged_restriction.min_value <= value && | 1042 return rnode->ranged_restriction.min_value <= value && |
| 920 rnode->ranged_restriction.max_value >= value; | 1043 rnode->ranged_restriction.max_value >= value; |
| 921 } else { | 1044 } else { |
| 922 for (int i = rnode->enumeration_restriction.offset_begin; | 1045 for (int i = rnode->enumeration_restriction.offset_begin; |
| 923 i < rnode->enumeration_restriction.offset_end; i++) { | 1046 i < rnode->enumeration_restriction.offset_end; i++) { |
| 924 if (*storage_->int_enums(i) == value) | 1047 if (*storage_->int_enums(i) == value) |
| 925 return true; | 1048 return true; |
| 926 } | 1049 } |
| 927 return false; | 1050 return false; |
| 928 } | 1051 } |
| 929 } | 1052 } |
| 930 | 1053 |
| 931 bool Schema::ValidateStringRestriction(int index, const char* str) const { | 1054 bool Schema::ValidateStringRestriction(int index, const char* str) const { |
| 932 const RestrictionNode* rnode = storage_->restriction(index); | 1055 const RestrictionNode* rnode = storage_->restriction(index); |
| 933 for (int i = rnode->enumeration_restriction.offset_begin; | 1056 if (rnode->enumeration_restriction.offset_begin < |
| 934 i < rnode->enumeration_restriction.offset_end; i++) { | 1057 rnode->enumeration_restriction.offset_end) { |
| 935 if (strcmp(*storage_->string_enums(i), str) == 0) | 1058 for (int i = rnode->enumeration_restriction.offset_begin; |
| 936 return true; | 1059 i < rnode->enumeration_restriction.offset_end; i++) { |
|
Joao da Silva
2014/03/21 12:58:12
nit: add one space at the beginning of this line
binjin
2014/03/27 17:57:47
Done.
| |
| 1060 if (strcmp(*storage_->string_enums(i), str) == 0) | |
| 1061 return true; | |
| 1062 } | |
| 1063 return false; | |
| 1064 } else { | |
| 1065 int index = rnode->string_pattern_restriction.pattern_index; | |
| 1066 DCHECK(index == rnode->string_pattern_restriction.pattern_index_backup); | |
| 1067 re2::RE2* regex = storage_->CompileRegex(*storage_->string_enums(index)); | |
| 1068 return re2::RE2::PartialMatch(str, *regex); | |
| 937 } | 1069 } |
| 938 return false; | |
| 939 } | 1070 } |
| 940 | 1071 |
| 941 } // namespace policy | 1072 } // namespace policy |
| OLD | NEW |