1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file. 4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/policy/core/common/schema.h" 6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include <algorithm> 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <map> 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <utility> 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <vector> 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/compiler_specific.h" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/logging.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_vector.h" 15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/json_schema/json_schema_constants.h" 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/json_schema/json_schema_validator.h" 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/policy/core/common/schema_internal.h" 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace schema = json_schema_constants; 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace policy { 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using internal::PropertiesNode; 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using internal::PropertyNode; 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using internal::SchemaData; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using internal::SchemaNode; 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace { 29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Maps schema "id" attributes to the corresponding SchemaNode index. 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)typedef std::map<std::string, int> IdMap; 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// List of pairs of references to be assigned later. The string is the "id" 34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// whose corresponding index should be stored in the pointer, once all the IDs 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// are available. 36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)typedef std::vector<std::pair<std::string, int*> > ReferenceList; 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sizes for the storage arrays. These are calculated in advance so that the 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// arrays don't have to be resized during parsing, which would invalidate 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// pointers into their contents (i.e. string's c_str() and address of indices 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// for "$ref" attributes). 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct StorageSizes { 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StorageSizes() 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : strings(0), schema_nodes(0), property_nodes(0), properties_nodes(0) {} 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) size_t strings; 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) size_t schema_nodes; 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) size_t property_nodes; 48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) size_t properties_nodes; 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// An invalid index, indicating that a node is not present; similar to a NULL 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// pointer. 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kInvalid = -1; 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool SchemaTypeToValueType(const std::string& type_string, 56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Value::Type* type) { 57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Note: "any" is not an accepted type. 58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) static const struct { 59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const char* schema_type; 60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Value::Type value_type; 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } kSchemaToValueTypeMap[] = { 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kArray, base::Value::TYPE_LIST }, 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kBoolean, base::Value::TYPE_BOOLEAN }, 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kInteger, base::Value::TYPE_INTEGER }, 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kNull, base::Value::TYPE_NULL }, 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kNumber, base::Value::TYPE_DOUBLE }, 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kObject, base::Value::TYPE_DICTIONARY }, 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) { schema::kString, base::Value::TYPE_STRING }, 69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) }; 70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { 71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (kSchemaToValueTypeMap[i].schema_type == type_string) { 72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *type = kSchemaToValueTypeMap[i].value_type; 73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return true; 74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return false; 77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 78d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 79d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} // namespace 80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Contains the internal data representation of a Schema. This can either wrap 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// is generated at compile time), or it can own its own SchemaData. 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class Schema::InternalStorage 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : public base::RefCountedThreadSafe<InternalStorage> { 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static scoped_refptr<const InternalStorage> ParseSchema( 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue& schema, 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string* error); 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SchemaData* data() const { return &schema_data_; } 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SchemaNode* root_node() const { 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return schema(0); 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SchemaNode* schema(int index) const { 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return schema_data_.schema_nodes + index; 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertiesNode* properties(int index) const { 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return schema_data_.properties_nodes + index; 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertyNode* property(int index) const { 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return schema_data_.property_nodes + index; 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) friend class base::RefCountedThreadSafe<InternalStorage>; 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) InternalStorage(); 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ~InternalStorage(); 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Determines the expected |sizes| of the storage for the representation 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // of |schema|. 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static void DetermineStorageSizes(const base::DictionaryValue& schema, 120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StorageSizes* sizes); 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Parses the JSON schema in |schema|. 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If |schema| has a "$ref" attribute then a pending reference is appended 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // to the |reference_list|, and nothing else is done. 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Otherwise, |index| gets assigned the index of the corresponding SchemaNode 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // in |schema_nodes_|. If the |schema| contains an "id" then that ID is mapped 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // to the |index| in the |id_map|. 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If |schema| is invalid then |error| gets the error reason and false is 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // returned. Otherwise returns true. 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool Parse(const base::DictionaryValue& schema, 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int* index, 135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error); 138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Helper for Parse() that gets an already assigned |schema_node| instead of 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // an |index| pointer. 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool ParseDictionary(const base::DictionaryValue& schema, 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SchemaNode* schema_node, 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error); 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Helper for Parse() that gets an already assigned |schema_node| instead of 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // an |index| pointer. 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool ParseList(const base::DictionaryValue& schema, 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SchemaNode* schema_node, 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error); 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Assigns the IDs in |id_map| to the pending references in the 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // |reference_list|. If an ID is missing then |error| is set and false is 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // returned; otherwise returns true. 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static bool ResolveReferences(const IdMap& id_map, 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const ReferenceList& reference_list, 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error); 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SchemaData schema_data_; 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string> strings_; 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector<SchemaNode> schema_nodes_; 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector<PropertyNode> property_nodes_; 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector<PropertiesNode> properties_nodes_; 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(InternalStorage); 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::InternalStorage::InternalStorage() {} 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::InternalStorage::~InternalStorage() {} 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SchemaData* data) { 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) InternalStorage* storage = new InternalStorage(); 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) storage->schema_data_.schema_nodes = data->schema_nodes; 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) storage->schema_data_.property_nodes = data->property_nodes; 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) storage->schema_data_.properties_nodes = data->properties_nodes; 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return storage; 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_refptr<const Schema::InternalStorage> 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::InternalStorage::ParseSchema(const base::DictionaryValue& schema, 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string* error) { 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Determine the sizes of the storage arrays and reserve the capacity before 190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // starting to append nodes and strings. This is important to prevent the 191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // arrays from being reallocated, which would invalidate the c_str() pointers 192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // and the addresses of indices to fix. 193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StorageSizes sizes; 194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DetermineStorageSizes(schema, &sizes); 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_refptr<InternalStorage> storage = new InternalStorage(); 197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) storage->strings_.reserve(sizes.strings); 198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) storage->schema_nodes_.reserve(sizes.schema_nodes); 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) storage->property_nodes_.reserve(sizes.property_nodes); 200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) storage->properties_nodes_.reserve(sizes.properties_nodes); 201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int root_index = kInvalid; 203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap id_map; 204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList reference_list; 205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!storage->Parse(schema, &root_index, &id_map, &reference_list, error)) 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return NULL; 207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (root_index == kInvalid) { 209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *error = "The main schema can't have a $ref"; 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return NULL; 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // None of this should ever happen without having been already detected. 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // But, if it does happen, then it will lead to corrupted memory; drop 215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // everything in that case. 216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (root_index != 0 || 217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes.strings != storage->strings_.size() || 218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes.schema_nodes != storage->schema_nodes_.size() || 219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes.property_nodes != storage->property_nodes_.size() || 220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes.properties_nodes != storage->properties_nodes_.size()) { 221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *error = "Failed to parse the schema due to a Chrome bug. Please file a " 222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "new issue at http://crbug.com"; 223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return NULL; 224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!ResolveReferences(id_map, reference_list, error)) 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return NULL; 228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SchemaData* data = &storage->schema_data_; 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) data->schema_nodes = vector_as_array(&storage->schema_nodes_); 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) data->property_nodes = vector_as_array(&storage->property_nodes_); 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) data->properties_nodes = vector_as_array(&storage->properties_nodes_); 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return storage; 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// static 237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Schema::InternalStorage::DetermineStorageSizes( 238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::DictionaryValue& schema, 239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StorageSizes* sizes) { 240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string ref_string; 241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetString(schema::kRef, &ref_string)) { 242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Schemas with a "$ref" attribute don't take additional storage. 243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string type_string; 247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Value::Type type = base::Value::TYPE_NULL; 248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!schema.GetString(schema::kType, &type_string) || 249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !SchemaTypeToValueType(type_string, &type)) { 250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This schema is invalid. 251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes->schema_nodes++; 255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (type == base::Value::TYPE_LIST) { 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::DictionaryValue* items = NULL; 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetDictionary(schema::kItems, &items)) 259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DetermineStorageSizes(*items, sizes); 260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else if (type == base::Value::TYPE_DICTIONARY) { 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes->properties_nodes++; 262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::DictionaryValue* dict = NULL; 264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) 265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DetermineStorageSizes(*dict, sizes); 266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::DictionaryValue* properties = NULL; 268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetDictionary(schema::kProperties, &properties)) { 269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (base::DictionaryValue::Iterator it(*properties); 270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !it.IsAtEnd(); it.Advance()) { 271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This should have been verified by the JSONSchemaValidator. 272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CHECK(it.value().GetAsDictionary(&dict)); 273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DetermineStorageSizes(*dict, sizes); 274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes->strings++; 275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sizes->property_nodes++; 276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, 282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int* index, 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error) { 286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string ref_string; 287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetString(schema::kRef, &ref_string)) { 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string id_string; 289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetString(schema::kId, &id_string)) { 290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *error = "Schemas with a $ref can't have an id"; 291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) reference_list->push_back(std::make_pair(ref_string, index)); 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string type_string; 298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!schema.GetString(schema::kType, &type_string)) { 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *error = "The schema type must be declared."; 300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Value::Type type = base::Value::TYPE_NULL; 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!SchemaTypeToValueType(type_string, &type)) { 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *error = "Type not supported: " + type_string; 306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *index = static_cast<int>(schema_nodes_.size()); 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) schema_nodes_.push_back(SchemaNode()); 311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SchemaNode* schema_node = &schema_nodes_.back(); 312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) schema_node->type = type; 313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) schema_node->extra = kInvalid; 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (type == base::Value::TYPE_DICTIONARY) { 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!ParseDictionary(schema, schema_node, id_map, reference_list, error)) 317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else if (type == base::Value::TYPE_LIST) { 319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!ParseList(schema, schema_node, id_map, reference_list, error)) 320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string id_string; 324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetString(schema::kId, &id_string)) { 325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (ContainsKey(*id_map, id_string)) { 326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *error = "Duplicated id: " + id_string; 327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (*id_map)[id_string] = *index; 330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Schema::InternalStorage::ParseDictionary( 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue& schema, 337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SchemaNode* schema_node, 338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string* error) { 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int extra = static_cast<int>(properties_nodes_.size()); 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_.push_back(PropertiesNode()); 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_[extra].begin = kInvalid; 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_[extra].end = kInvalid; 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_[extra].additional = kInvalid; 346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) schema_node->extra = extra; 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue* dict = NULL; 349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetDictionary(schema::kAdditionalProperties, &dict)) { 350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!Parse(*dict, &properties_nodes_[extra].additional, 351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) id_map, reference_list, error)) { 352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue* properties = NULL; 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (schema.GetDictionary(schema::kProperties, &properties)) { 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int base_index = static_cast<int>(property_nodes_.size()); 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This reserves nodes for all of the |properties|, and makes sure they 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // are contiguous. Recursive calls to Parse() will append after these 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // elements. 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) property_nodes_.resize(base_index + properties->size()); 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int index = base_index; 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (base::DictionaryValue::Iterator it(*properties); 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !it.IsAtEnd(); it.Advance(), ++index) { 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This should have been verified by the JSONSchemaValidator. 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(it.value().GetAsDictionary(&dict)); 369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) strings_.push_back(it.key()); 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) property_nodes_[index].key = strings_.back().c_str(); 371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!Parse(*dict, &property_nodes_[index].schema, 372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) id_map, reference_list, error)) { 373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK_EQ(static_cast<int>(properties->size()), index - base_index); 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_[extra].begin = base_index; 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) properties_nodes_[extra].end = index; 379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, 385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SchemaNode* schema_node, 386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap* id_map, 387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ReferenceList* reference_list, 388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error) { 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue* dict = NULL; 390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!schema.GetDictionary(schema::kItems, &dict)) { 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *error = "Arrays must declare a single schema for their items."; 392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return Parse(*dict, &schema_node->extra, id_map, reference_list, error); 395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// static 398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Schema::InternalStorage::ResolveReferences( 399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const IdMap& id_map, 400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const ReferenceList& reference_list, 401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string* error) { 402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (ReferenceList::const_iterator ref = reference_list.begin(); 403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ref != reference_list.end(); ++ref) { 404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IdMap::const_iterator id = id_map.find(ref->first); 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (id == id_map.end()) { 406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *error = "Invalid $ref: " + ref->first; 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *ref->second = id->second; 410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::Iterator::Iterator(const scoped_refptr<const InternalStorage>& storage, 415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertiesNode* node) 416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : storage_(storage), 417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) it_(storage->property(node->begin)), 418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) end_(storage->property(node->end)) {} 419d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 420d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Schema::Iterator::Iterator(const Iterator& iterator) 421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : storage_(iterator.storage_), 422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) it_(iterator.it_), 423d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) end_(iterator.end_) {} 424d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 425d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Schema::Iterator::~Iterator() {} 426d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 427d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) { 428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) storage_ = iterator.storage_; 429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) it_ = iterator.it_; 430d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) end_ = iterator.end_; 431d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return *this; 432d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 433d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool Schema::Iterator::IsAtEnd() const { 435d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return it_ == end_; 436d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 437d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 438d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Schema::Iterator::Advance() { 439d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ++it_; 440d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 441d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 442d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const char* Schema::Iterator::key() const { 443d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return it_->key; 444d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 445d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 446d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Schema Schema::Iterator::schema() const { 447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage_, storage_->schema(it_->schema)); 448d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 449d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::Schema() : node_(NULL) {} 451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::Schema(const scoped_refptr<const InternalStorage>& storage, 453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SchemaNode* node) 454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : storage_(storage), node_(node) {} 45568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::Schema(const Schema& schema) 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : storage_(schema.storage_), node_(schema.node_) {} 458d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::~Schema() {} 460d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 461d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Schema& Schema::operator=(const Schema& schema) { 462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) storage_ = schema.storage_; 463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) node_ = schema.node_; 464d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return *this; 465d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 466d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::Wrap(const SchemaData* data) { 469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); 470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage, storage->root_node()); 471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 472d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool Schema::Validate(const base::Value& value) const { 474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!valid()) { 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Schema not found, invalid entry. 476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 478d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!value.IsType(type())) 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 481d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::DictionaryValue* dict = NULL; 483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::ListValue* list = NULL; 484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (value.GetAsDictionary(&dict)) { 485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) it.Advance()) { 487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!GetProperty(it.key()).Validate(it.value())) 488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else if (value.GetAsList(&list)) { 491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (base::ListValue::const_iterator it = list->begin(); 492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) it != list->end(); ++it) { 493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!*it || !GetItems().Validate(**it)) 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 497d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 499d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 500d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 501d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static 502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::Parse(const std::string& content, std::string* error) { 503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Validate as a generic JSON schema, and ignore unknown attributes; they 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // may become used in a future version of the schema format. 505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( 506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); 507d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!dict) 508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 509d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 510d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Validate the main type. 511d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) std::string string_value; 512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!dict->GetString(schema::kType, &string_value) || 513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) string_value != schema::kObject) { 514d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *error = 515d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) "The main schema must have a type attribute with \"object\" value."; 516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 517d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 518d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Checks for invalid attributes at the top-level. 520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (dict->HasKey(schema::kAdditionalProperties) || 521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) dict->HasKey(schema::kPatternProperties)) { 522d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *error = "\"additionalProperties\" and \"patternProperties\" are not " 523d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) "supported at the main schema."; 524f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 525d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 526d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 527f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_refptr<const InternalStorage> storage = 528f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) InternalStorage::ParseSchema(*dict, error); 529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!storage) 530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage, storage->root_node()); 532d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 533d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)base::Value::Type Schema::type() const { 535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(valid()); 536f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return node_->type; 537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 538d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema::Iterator Schema::GetPropertiesIterator() const { 540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(valid()); 541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Iterator(storage_, storage_->properties(node_->extra)); 543d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace { 546d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool CompareKeys(const PropertyNode& node, const std::string& key) { 548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return node.key < key; 549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 550d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace 552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::GetKnownProperty(const std::string& key) const { 554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(valid()); 555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertiesNode* node = storage_->properties(node_->extra); 557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertyNode* begin = storage_->property(node->begin); 558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertyNode* end = storage_->property(node->end); 559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys); 560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (it != end && it->key == key) 561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage_, storage_->schema(it->schema)); 562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 564d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::GetAdditionalProperties() const { 566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(valid()); 567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const PropertiesNode* node = storage_->properties(node_->extra); 569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (node->additional == kInvalid) 570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage_, storage_->schema(node->additional)); 572d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 573d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::GetProperty(const std::string& key) const { 575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Schema schema = GetKnownProperty(key); 576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return schema.valid() ? schema : GetAdditionalProperties(); 577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 578d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Schema Schema::GetItems() const { 580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(valid()); 581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK_EQ(base::Value::TYPE_LIST, type()); 582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (node_->extra == kInvalid) 583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(); 584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Schema(storage_, storage_->schema(node_->extra)); 585d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 586d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 587d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} // namespace policy 588