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> |
Joao da Silva
2014/04/02 09:51:11
This is already in the .h
binjin
2014/04/03 10:13:37
Done.
| |
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; | |
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 // Cache for CompileRegex(), will memorize return value of every call to | |
250 // CompileRegex() and return results directly next time. | |
251 mutable std::map<std::string, re2::RE2*> regex_cache_; | |
252 STLValueDeleter<std::map<std::string, re2::RE2*> > cache_deleter_; | |
Joao da Silva
2014/04/02 09:51:11
regex_cache_deleter_
binjin
2014/04/03 10:13:37
Done.
| |
253 | |
238 SchemaData schema_data_; | 254 SchemaData schema_data_; |
239 std::vector<std::string> strings_; | 255 std::vector<std::string> strings_; |
240 std::vector<SchemaNode> schema_nodes_; | 256 std::vector<SchemaNode> schema_nodes_; |
241 std::vector<PropertyNode> property_nodes_; | 257 std::vector<PropertyNode> property_nodes_; |
242 std::vector<PropertiesNode> properties_nodes_; | 258 std::vector<PropertiesNode> properties_nodes_; |
243 std::vector<RestrictionNode> restriction_nodes_; | 259 std::vector<RestrictionNode> restriction_nodes_; |
244 std::vector<int> int_enums_; | 260 std::vector<int> int_enums_; |
245 std::vector<const char*> string_enums_; | 261 std::vector<const char*> string_enums_; |
246 | 262 |
247 DISALLOW_COPY_AND_ASSIGN(InternalStorage); | 263 DISALLOW_COPY_AND_ASSIGN(InternalStorage); |
248 }; | 264 }; |
249 | 265 |
250 Schema::InternalStorage::InternalStorage() {} | 266 Schema::InternalStorage::InternalStorage() : 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(); |
699 error)) { | 810 ++subschema) { |
Joao da Silva
2014/04/02 09:51:11
These 2 lines can be joined
binjin
2014/04/03 10:13:37
Done.
| |
700 // Invalid property was detected. | 811 if (!subschema->Validate(it.value(), |
701 AddDictKeyPrefixToPath(it.key(), error_path); | 812 StrategyForNextLevel(strategy), |
702 if (!StrategyAllowInvalidOnTopLevel(strategy)) | 813 error_path, |
703 return false; | 814 error)) { |
815 // Invalid property was detected. | |
816 AddDictKeyPrefixToPath(it.key(), error_path); | |
817 if (!StrategyAllowInvalidOnTopLevel(strategy)) | |
818 return false; | |
819 } | |
820 } | |
704 } | 821 } |
705 } | 822 } |
706 } else if (value.GetAsList(&list)) { | 823 } else if (value.GetAsList(&list)) { |
707 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); | 824 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); |
708 ++it) { | 825 ++it) { |
709 if (!*it || | 826 if (!*it || |
710 !GetItems().Validate(**it, | 827 !GetItems().Validate(**it, |
711 StrategyForNextLevel(strategy), | 828 StrategyForNextLevel(strategy), |
712 error_path, | 829 error_path, |
713 error)) { | 830 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."); | 873 error_path, error, "The value type doesn't match the schema type."); |
757 return false; | 874 return false; |
758 } | 875 } |
759 | 876 |
760 base::DictionaryValue* dict = NULL; | 877 base::DictionaryValue* dict = NULL; |
761 base::ListValue* list = NULL; | 878 base::ListValue* list = NULL; |
762 if (value->GetAsDictionary(&dict)) { | 879 if (value->GetAsDictionary(&dict)) { |
763 std::vector<std::string> drop_list; // Contains the keys to drop. | 880 std::vector<std::string> drop_list; // Contains the keys to drop. |
764 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 881 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
765 it.Advance()) { | 882 it.Advance()) { |
766 Schema subschema = GetProperty(it.key()); | 883 bool drop_it = false; |
767 if (!subschema.valid()) { | 884 SchemaList schema_list = GetMatchingProperties(it.key()); |
885 if (schema_list.empty()) { | |
768 // Unknown property was detected. | 886 // Unknown property was detected. |
769 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); | 887 SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
770 if (StrategyAllowUnknownOnTopLevel(strategy)) | 888 if (StrategyAllowUnknownOnTopLevel(strategy)) |
771 drop_list.push_back(it.key()); | 889 drop_it = true; |
772 else | 890 else |
773 return false; | 891 return false; |
774 } else { | 892 } else { |
775 base::Value* sub_value = NULL; | 893 for (SchemaList::iterator subschema = schema_list.begin(); |
776 dict->GetWithoutPathExpansion(it.key(), &sub_value); | 894 subschema != schema_list.end(); |
777 if (!subschema.Normalize(sub_value, | 895 ++subschema) { |
Joao da Silva
2014/04/02 09:51:11
These 2 lines can be joined
binjin
2014/04/03 10:13:37
Done.
| |
778 StrategyForNextLevel(strategy), | 896 base::Value* sub_value = NULL; |
779 error_path, | 897 dict->GetWithoutPathExpansion(it.key(), &sub_value); |
780 error, | 898 if (!subschema->Normalize(sub_value, |
781 changed)) { | 899 StrategyForNextLevel(strategy), |
782 // Invalid property was detected. | 900 error_path, |
783 AddDictKeyPrefixToPath(it.key(), error_path); | 901 error, |
784 if (StrategyAllowInvalidOnTopLevel(strategy)) | 902 changed)) { |
785 drop_list.push_back(it.key()); | 903 // Invalid property was detected. |
786 else | 904 AddDictKeyPrefixToPath(it.key(), error_path); |
787 return false; | 905 if (StrategyAllowInvalidOnTopLevel(strategy)) |
906 drop_it = true; | |
Joao da Silva
2014/04/02 09:51:11
Why not just push it here and break from the inner
binjin
2014/04/03 10:13:37
Done.
| |
907 else | |
908 return false; | |
909 } | |
788 } | 910 } |
789 } | 911 } |
912 if (drop_it) | |
913 drop_list.push_back(it.key()); | |
790 } | 914 } |
791 if (changed && !drop_list.empty()) | 915 if (changed && !drop_list.empty()) |
792 *changed = true; | 916 *changed = true; |
793 for (std::vector<std::string>::const_iterator it = drop_list.begin(); | 917 for (std::vector<std::string>::const_iterator it = drop_list.begin(); |
794 it != drop_list.end(); | 918 it != drop_list.end(); |
795 ++it) { | 919 ++it) { |
796 dict->RemoveWithoutPathExpansion(*it, NULL); | 920 dict->RemoveWithoutPathExpansion(*it, NULL); |
797 } | 921 } |
798 return true; | 922 return true; |
799 } else if (value->GetAsList(&list)) { | 923 } else if (value->GetAsList(&list)) { |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
892 | 1016 |
893 Schema Schema::GetAdditionalProperties() const { | 1017 Schema Schema::GetAdditionalProperties() const { |
894 CHECK(valid()); | 1018 CHECK(valid()); |
895 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); | 1019 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); |
896 const PropertiesNode* node = storage_->properties(node_->extra); | 1020 const PropertiesNode* node = storage_->properties(node_->extra); |
897 if (node->additional == kInvalid) | 1021 if (node->additional == kInvalid) |
898 return Schema(); | 1022 return Schema(); |
899 return Schema(storage_, storage_->schema(node->additional)); | 1023 return Schema(storage_, storage_->schema(node->additional)); |
900 } | 1024 } |
901 | 1025 |
1026 Schema::SchemaList Schema::GetPatternProperties(const std::string& key) const { | |
1027 CHECK(valid()); | |
1028 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); | |
1029 const PropertiesNode* node = storage_->properties(node_->extra); | |
1030 const PropertyNode* begin = storage_->property(node->end); | |
1031 const PropertyNode* end = storage_->property(node->pattern_end); | |
1032 Schema::SchemaList matching_properties; | |
1033 for (const PropertyNode* it = begin; it != end; ++it) { | |
1034 if (re2::RE2::PartialMatch(key, *storage_->CompileRegex(it->key))) { | |
1035 matching_properties.push_back( | |
1036 Schema(storage_, storage_->schema(it->schema))); | |
1037 } | |
1038 } | |
1039 return matching_properties; | |
1040 } | |
1041 | |
902 Schema Schema::GetProperty(const std::string& key) const { | 1042 Schema Schema::GetProperty(const std::string& key) const { |
903 Schema schema = GetKnownProperty(key); | 1043 Schema schema = GetKnownProperty(key); |
904 return schema.valid() ? schema : GetAdditionalProperties(); | 1044 if (schema.valid()) |
1045 return schema; | |
1046 return GetAdditionalProperties(); | |
1047 } | |
1048 | |
1049 Schema::SchemaList Schema::GetMatchingProperties(const std::string& key) const { | |
1050 Schema::SchemaList schema_list; | |
1051 | |
1052 Schema known_property = GetKnownProperty(key); | |
1053 if (known_property.valid()) | |
1054 schema_list.push_back(known_property); | |
1055 | |
1056 Schema::SchemaList pattern_properties = GetPatternProperties(key); | |
1057 schema_list.insert( | |
1058 schema_list.end(), pattern_properties.begin(), pattern_properties.end()); | |
1059 | |
1060 if (schema_list.empty()) { | |
1061 Schema additional_property = GetAdditionalProperties(); | |
1062 if (additional_property.valid()) | |
1063 schema_list.push_back(additional_property); | |
1064 } | |
1065 | |
1066 return schema_list; | |
905 } | 1067 } |
906 | 1068 |
907 Schema Schema::GetItems() const { | 1069 Schema Schema::GetItems() const { |
908 CHECK(valid()); | 1070 CHECK(valid()); |
909 CHECK_EQ(base::Value::TYPE_LIST, type()); | 1071 CHECK_EQ(base::Value::TYPE_LIST, type()); |
910 if (node_->extra == kInvalid) | 1072 if (node_->extra == kInvalid) |
911 return Schema(); | 1073 return Schema(); |
912 return Schema(storage_, storage_->schema(node_->extra)); | 1074 return Schema(storage_, storage_->schema(node_->extra)); |
913 } | 1075 } |
914 | 1076 |
915 bool Schema::ValidateIntegerRestriction(int index, int value) const { | 1077 bool Schema::ValidateIntegerRestriction(int index, int value) const { |
916 const RestrictionNode* rnode = storage_->restriction(index); | 1078 const RestrictionNode* rnode = storage_->restriction(index); |
917 if (rnode->ranged_restriction.min_value <= | 1079 if (rnode->ranged_restriction.min_value <= |
918 rnode->ranged_restriction.max_value) { | 1080 rnode->ranged_restriction.max_value) { |
919 return rnode->ranged_restriction.min_value <= value && | 1081 return rnode->ranged_restriction.min_value <= value && |
920 rnode->ranged_restriction.max_value >= value; | 1082 rnode->ranged_restriction.max_value >= value; |
921 } else { | 1083 } else { |
922 for (int i = rnode->enumeration_restriction.offset_begin; | 1084 for (int i = rnode->enumeration_restriction.offset_begin; |
923 i < rnode->enumeration_restriction.offset_end; i++) { | 1085 i < rnode->enumeration_restriction.offset_end; i++) { |
Joao da Silva
2014/04/02 09:51:11
++i
binjin
2014/04/03 10:13:37
Done.
| |
924 if (*storage_->int_enums(i) == value) | 1086 if (*storage_->int_enums(i) == value) |
925 return true; | 1087 return true; |
926 } | 1088 } |
927 return false; | 1089 return false; |
928 } | 1090 } |
929 } | 1091 } |
930 | 1092 |
931 bool Schema::ValidateStringRestriction(int index, const char* str) const { | 1093 bool Schema::ValidateStringRestriction(int index, const char* str) const { |
932 const RestrictionNode* rnode = storage_->restriction(index); | 1094 const RestrictionNode* rnode = storage_->restriction(index); |
933 for (int i = rnode->enumeration_restriction.offset_begin; | 1095 if (rnode->enumeration_restriction.offset_begin < |
934 i < rnode->enumeration_restriction.offset_end; i++) { | 1096 rnode->enumeration_restriction.offset_end) { |
935 if (strcmp(*storage_->string_enums(i), str) == 0) | 1097 for (int i = rnode->enumeration_restriction.offset_begin; |
936 return true; | 1098 i < rnode->enumeration_restriction.offset_end; i++) { |
Joao da Silva
2014/04/02 09:51:11
++i
binjin
2014/04/03 10:13:37
Done.
| |
1099 if (strcmp(*storage_->string_enums(i), str) == 0) | |
1100 return true; | |
1101 } | |
1102 return false; | |
1103 } else { | |
1104 int index = rnode->string_pattern_restriction.pattern_index; | |
1105 DCHECK(index == rnode->string_pattern_restriction.pattern_index_backup); | |
1106 re2::RE2* regex = storage_->CompileRegex(*storage_->string_enums(index)); | |
1107 return re2::RE2::PartialMatch(str, *regex); | |
937 } | 1108 } |
938 return false; | |
939 } | 1109 } |
940 | 1110 |
941 } // namespace policy | 1111 } // namespace policy |
OLD | NEW |