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 |