Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: components/policy/core/common/schema.cc

Issue 31273002: Generate the Chrome policy schema at compile time. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <vector>
8 9
9 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_vector.h"
11 #include "components/json_schema/json_schema_constants.h" 13 #include "components/json_schema/json_schema_constants.h"
12 #include "components/json_schema/json_schema_validator.h" 14 #include "components/json_schema/json_schema_validator.h"
13 #include "components/policy/core/common/schema_internal.h" 15 #include "components/policy/core/common/schema_internal.h"
14 16
15 namespace policy { 17 namespace policy {
16 18
19 using internal::PropertiesNode;
20 using internal::PropertyNode;
21 using internal::SchemaData;
22 using internal::SchemaNode;
23
17 namespace { 24 namespace {
18 25
26 const int kInvalid = -1;
27
19 bool SchemaTypeToValueType(const std::string& type_string, 28 bool SchemaTypeToValueType(const std::string& type_string,
20 base::Value::Type* type) { 29 base::Value::Type* type) {
21 // Note: "any" is not an accepted type. 30 // Note: "any" is not an accepted type.
22 static const struct { 31 static const struct {
23 const char* schema_type; 32 const char* schema_type;
24 base::Value::Type value_type; 33 base::Value::Type value_type;
25 } kSchemaToValueTypeMap[] = { 34 } kSchemaToValueTypeMap[] = {
26 { json_schema_constants::kArray, base::Value::TYPE_LIST }, 35 { json_schema_constants::kArray, base::Value::TYPE_LIST },
27 { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN }, 36 { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN },
28 { json_schema_constants::kInteger, base::Value::TYPE_INTEGER }, 37 { json_schema_constants::kInteger, base::Value::TYPE_INTEGER },
29 { json_schema_constants::kNull, base::Value::TYPE_NULL }, 38 { json_schema_constants::kNull, base::Value::TYPE_NULL },
30 { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE }, 39 { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE },
31 { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY }, 40 { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY },
32 { json_schema_constants::kString, base::Value::TYPE_STRING }, 41 { json_schema_constants::kString, base::Value::TYPE_STRING },
33 }; 42 };
34 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { 43 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) {
35 if (kSchemaToValueTypeMap[i].schema_type == type_string) { 44 if (kSchemaToValueTypeMap[i].schema_type == type_string) {
36 *type = kSchemaToValueTypeMap[i].value_type; 45 *type = kSchemaToValueTypeMap[i].value_type;
37 return true; 46 return true;
38 } 47 }
39 } 48 }
40 return false; 49 return false;
41 } 50 }
42 51
43 } // namespace 52 } // namespace
44 53
45 Schema::Iterator::Iterator(const internal::PropertiesNode* properties) 54 // A SchemaOwner can either Wrap() a SchemaData owned elsewhere (currently used
46 : it_(properties->begin), 55 // to wrap the Chrome schema, which is generated at compile time), or it can
47 end_(properties->end) {} 56 // own its own SchemaData. In that case, the Internal class holds the data
57 // referenced by the SchemaData substructures.
58 class SchemaOwner::Internal {
59 public:
60 Internal() {}
61 ~Internal() {}
62
63 SchemaData schema_data;
64 ScopedVector<std::string> strings;
65 std::vector<SchemaNode> schema_nodes;
66 std::vector<PropertyNode> property_nodes;
67 std::vector<PropertiesNode> properties_nodes;
68
69 private:
70 DISALLOW_COPY_AND_ASSIGN(Internal);
71 };
72
73 Schema::Iterator::Iterator(const SchemaData* data, const PropertiesNode* node)
74 : data_(data),
75 it_(data->property_nodes + node->begin),
76 end_(data->property_nodes + node->end) {}
48 77
49 Schema::Iterator::Iterator(const Iterator& iterator) 78 Schema::Iterator::Iterator(const Iterator& iterator)
50 : it_(iterator.it_), 79 : data_(iterator.data_),
80 it_(iterator.it_),
51 end_(iterator.end_) {} 81 end_(iterator.end_) {}
52 82
53 Schema::Iterator::~Iterator() {} 83 Schema::Iterator::~Iterator() {}
54 84
55 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) { 85 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) {
86 data_ = iterator.data_;
56 it_ = iterator.it_; 87 it_ = iterator.it_;
57 end_ = iterator.end_; 88 end_ = iterator.end_;
58 return *this; 89 return *this;
59 } 90 }
60 91
61 bool Schema::Iterator::IsAtEnd() const { 92 bool Schema::Iterator::IsAtEnd() const {
62 return it_ == end_; 93 return it_ == end_;
63 } 94 }
64 95
65 void Schema::Iterator::Advance() { 96 void Schema::Iterator::Advance() {
66 ++it_; 97 ++it_;
67 } 98 }
68 99
69 const char* Schema::Iterator::key() const { 100 const char* Schema::Iterator::key() const {
70 return it_->key; 101 return it_->key;
71 } 102 }
72 103
73 Schema Schema::Iterator::schema() const { 104 Schema Schema::Iterator::schema() const {
74 return Schema(it_->schema); 105 return Schema(data_, data_->schema_nodes + it_->schema);
75 } 106 }
76 107
77 Schema::Schema() : schema_(NULL) {} 108 Schema::Schema() : data_(NULL), node_(NULL) {}
78 109
79 Schema::Schema(const internal::SchemaNode* schema) : schema_(schema) {} 110 Schema::Schema(const SchemaData* data, const SchemaNode* node)
111 : data_(data), node_(node) {}
80 112
81 Schema::Schema(const Schema& schema) : schema_(schema.schema_) {} 113 Schema::Schema(const Schema& schema)
114 : data_(schema.data_), node_(schema.node_) {}
82 115
83 Schema& Schema::operator=(const Schema& schema) { 116 Schema& Schema::operator=(const Schema& schema) {
84 schema_ = schema.schema_; 117 data_ = schema.data_;
118 node_ = schema.node_;
85 return *this; 119 return *this;
86 } 120 }
87 121
88 base::Value::Type Schema::type() const { 122 base::Value::Type Schema::type() const {
89 CHECK(valid()); 123 CHECK(valid());
90 return schema_->type; 124 return node_->type;
91 } 125 }
92 126
93 Schema::Iterator Schema::GetPropertiesIterator() const { 127 Schema::Iterator Schema::GetPropertiesIterator() const {
94 CHECK(valid()); 128 CHECK(valid());
95 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 129 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
96 return Iterator( 130 return Iterator(data_, data_->properties_nodes + node_->extra);
97 static_cast<const internal::PropertiesNode*>(schema_->extra));
98 } 131 }
99 132
100 namespace { 133 namespace {
101 134
102 bool CompareKeys(const internal::PropertyNode& node, const std::string& key) { 135 bool CompareKeys(const PropertyNode& node, const std::string& key) {
103 return node.key < key; 136 return node.key < key;
104 } 137 }
105 138
106 } // namespace 139 } // namespace
107 140
108 Schema Schema::GetKnownProperty(const std::string& key) const { 141 Schema Schema::GetKnownProperty(const std::string& key) const {
109 CHECK(valid()); 142 CHECK(valid());
110 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 143 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
111 const internal::PropertiesNode* properties_node = 144 const PropertiesNode* node = data_->properties_nodes + node_->extra;
112 static_cast<const internal::PropertiesNode*>(schema_->extra); 145 const PropertyNode* begin = data_->property_nodes + node->begin;
113 const internal::PropertyNode* it = std::lower_bound( 146 const PropertyNode* end = data_->property_nodes + node->end;
114 properties_node->begin, properties_node->end, key, CompareKeys); 147 const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys);
115 if (it != properties_node->end && it->key == key) 148 if (it != end && it->key == key)
116 return Schema(it->schema); 149 return Schema(data_, data_->schema_nodes + it->schema);
117 return Schema(); 150 return Schema();
118 } 151 }
119 152
120 Schema Schema::GetAdditionalProperties() const { 153 Schema Schema::GetAdditionalProperties() const {
121 CHECK(valid()); 154 CHECK(valid());
122 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 155 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
123 return Schema( 156 const PropertiesNode* node = data_->properties_nodes + node_->extra;
124 static_cast<const internal::PropertiesNode*>(schema_->extra)->additional); 157 if (node->additional == kInvalid)
158 return Schema();
159 return Schema(data_, data_->schema_nodes + node->additional);
125 } 160 }
126 161
127 Schema Schema::GetProperty(const std::string& key) const { 162 Schema Schema::GetProperty(const std::string& key) const {
128 Schema schema = GetKnownProperty(key); 163 Schema schema = GetKnownProperty(key);
129 return schema.valid() ? schema : GetAdditionalProperties(); 164 return schema.valid() ? schema : GetAdditionalProperties();
130 } 165 }
131 166
132 Schema Schema::GetItems() const { 167 Schema Schema::GetItems() const {
133 CHECK(valid()); 168 CHECK(valid());
134 CHECK_EQ(base::Value::TYPE_LIST, type()); 169 CHECK_EQ(base::Value::TYPE_LIST, type());
135 return Schema(static_cast<const internal::SchemaNode*>(schema_->extra)); 170 if (node_->extra == kInvalid)
171 return Schema();
172 return Schema(data_, data_->schema_nodes + node_->extra);
136 } 173 }
137 174
138 SchemaOwner::SchemaOwner(const internal::SchemaNode* root) : root_(root) {} 175 SchemaOwner::SchemaOwner(const SchemaData* data, scoped_ptr<Internal> internal)
176 : internal_(internal.Pass()), data_(data) {}
139 177
140 SchemaOwner::~SchemaOwner() { 178 SchemaOwner::~SchemaOwner() {}
141 for (size_t i = 0; i < property_nodes_.size(); ++i) 179
142 delete[] property_nodes_[i]; 180 Schema SchemaOwner::schema() const {
181 // data_->schema_nodes[0] is the root node.
182 return Schema(data_, data_->schema_nodes + 0);
143 } 183 }
144 184
145 // static 185 // static
146 scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const internal::SchemaNode* schema) { 186 scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const SchemaData* data) {
147 return scoped_ptr<SchemaOwner>(new SchemaOwner(schema)); 187 return make_scoped_ptr(new SchemaOwner(data, scoped_ptr<Internal>()));
148 } 188 }
149 189
150 // static 190 // static
151 scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content, 191 scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content,
152 std::string* error) { 192 std::string* error) {
153 // Validate as a generic JSON schema. 193 // Validate as a generic JSON schema.
154 scoped_ptr<base::DictionaryValue> dict = 194 scoped_ptr<base::DictionaryValue> dict =
155 JSONSchemaValidator::IsValidSchema(content, error); 195 JSONSchemaValidator::IsValidSchema(content, error);
156 if (!dict) 196 if (!dict)
157 return scoped_ptr<SchemaOwner>(); 197 return scoped_ptr<SchemaOwner>();
158 198
159 // Validate the main type. 199 // Validate the main type.
160 std::string string_value; 200 std::string string_value;
161 if (!dict->GetString(json_schema_constants::kType, &string_value) || 201 if (!dict->GetString(json_schema_constants::kType, &string_value) ||
162 string_value != json_schema_constants::kObject) { 202 string_value != json_schema_constants::kObject) {
163 *error = 203 *error =
164 "The main schema must have a type attribute with \"object\" value."; 204 "The main schema must have a type attribute with \"object\" value.";
165 return scoped_ptr<SchemaOwner>(); 205 return scoped_ptr<SchemaOwner>();
166 } 206 }
167 207
168 // Checks for invalid attributes at the top-level. 208 // Checks for invalid attributes at the top-level.
169 if (dict->HasKey(json_schema_constants::kAdditionalProperties) || 209 if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
170 dict->HasKey(json_schema_constants::kPatternProperties)) { 210 dict->HasKey(json_schema_constants::kPatternProperties)) {
171 *error = "\"additionalProperties\" and \"patternProperties\" are not " 211 *error = "\"additionalProperties\" and \"patternProperties\" are not "
172 "supported at the main schema."; 212 "supported at the main schema.";
173 return scoped_ptr<SchemaOwner>(); 213 return scoped_ptr<SchemaOwner>();
174 } 214 }
175 215
176 scoped_ptr<SchemaOwner> impl(new SchemaOwner(NULL)); 216 scoped_ptr<Internal> internal(new Internal);
177 impl->root_ = impl->Parse(*dict, error); 217 if (Parse(*dict, error, internal.get()) == kInvalid)
178 if (!impl->root_) 218 return scoped_ptr<SchemaOwner>();
179 impl.reset(); 219 SchemaData* data = &internal->schema_data;
180 return impl.PassAs<SchemaOwner>(); 220 data->schema_nodes = vector_as_array(&internal->schema_nodes);
221 data->property_nodes = vector_as_array(&internal->property_nodes);
222 data->properties_nodes = vector_as_array(&internal->properties_nodes);
223 return make_scoped_ptr(new SchemaOwner(data, internal.Pass()));
181 } 224 }
182 225
183 const internal::SchemaNode* SchemaOwner::Parse( 226 // static
227 int SchemaOwner::Parse(
184 const base::DictionaryValue& schema, 228 const base::DictionaryValue& schema,
185 std::string* error) { 229 std::string* error,
230 Internal* internal) {
186 std::string type_string; 231 std::string type_string;
187 if (!schema.GetString(json_schema_constants::kType, &type_string)) { 232 if (!schema.GetString(json_schema_constants::kType, &type_string)) {
188 *error = "The schema type must be declared."; 233 *error = "The schema type must be declared.";
189 return NULL; 234 return kInvalid;
190 } 235 }
191 236
192 base::Value::Type type = base::Value::TYPE_NULL; 237 base::Value::Type type = base::Value::TYPE_NULL;
193 if (!SchemaTypeToValueType(type_string, &type)) { 238 if (!SchemaTypeToValueType(type_string, &type)) {
194 *error = "Type not supported: " + type_string; 239 *error = "Type not supported: " + type_string;
195 return NULL; 240 return kInvalid;
196 } 241 }
197 242
198 if (type == base::Value::TYPE_DICTIONARY) 243 if (type == base::Value::TYPE_DICTIONARY)
199 return ParseDictionary(schema, error); 244 return ParseDictionary(schema, error, internal);
200 if (type == base::Value::TYPE_LIST) 245 if (type == base::Value::TYPE_LIST)
201 return ParseList(schema, error); 246 return ParseList(schema, error, internal);
202 247
203 internal::SchemaNode* node = new internal::SchemaNode; 248 int index = static_cast<int>(internal->schema_nodes.size());
204 node->type = type; 249 internal->schema_nodes.push_back(SchemaNode());
205 node->extra = NULL; 250 SchemaNode& node = internal->schema_nodes.back();
206 schema_nodes_.push_back(node); 251 node.type = type;
207 return node; 252 node.extra = kInvalid;
253 return index;
208 } 254 }
209 255
210 const internal::SchemaNode* SchemaOwner::ParseDictionary( 256 // static
257 int SchemaOwner::ParseDictionary(
211 const base::DictionaryValue& schema, 258 const base::DictionaryValue& schema,
212 std::string* error) { 259 std::string* error,
213 internal::PropertiesNode* properties_node = new internal::PropertiesNode; 260 Internal* internal) {
214 properties_node->begin = NULL; 261 // Note: recursive calls to Parse() invalidate iterators and references into
215 properties_node->end = NULL; 262 // the vectors.
216 properties_node->additional = NULL; 263
217 properties_nodes_.push_back(properties_node); 264 // Reserve an index for this dictionary at the front, so that the root node
265 // is at index 0.
266 int index = static_cast<int>(internal->schema_nodes.size());
267 internal->schema_nodes.push_back(SchemaNode());
268
269 int extra = static_cast<int>(internal->properties_nodes.size());
270 internal->properties_nodes.push_back(PropertiesNode());
271 internal->properties_nodes[extra].begin = kInvalid;
272 internal->properties_nodes[extra].end = kInvalid;
273 internal->properties_nodes[extra].additional = kInvalid;
218 274
219 const base::DictionaryValue* dict = NULL; 275 const base::DictionaryValue* dict = NULL;
220 const base::DictionaryValue* properties = NULL; 276 const base::DictionaryValue* properties = NULL;
277
278 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties,
279 &dict)) {
280 int additional = Parse(*dict, error, internal);
281 if (additional == kInvalid)
282 return kInvalid;
283 internal->properties_nodes[extra].additional = additional;
284 }
285
221 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { 286 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) {
222 internal::PropertyNode* property_nodes = 287 int base_index = static_cast<int>(internal->property_nodes.size());
223 new internal::PropertyNode[properties->size()]; 288 // This reserves nodes for all of the |properties|, and makes sure they
224 property_nodes_.push_back(property_nodes); 289 // are contiguous. Recursive calls to Parse() will append after these
290 // elements.
291 internal->property_nodes.resize(base_index + properties->size());
225 292
226 size_t index = 0; 293 int index = base_index;
227 for (base::DictionaryValue::Iterator it(*properties); 294 for (base::DictionaryValue::Iterator it(*properties);
228 !it.IsAtEnd(); it.Advance(), ++index) { 295 !it.IsAtEnd(); it.Advance(), ++index) {
229 // This should have been verified by the JSONSchemaValidator. 296 // This should have been verified by the JSONSchemaValidator.
230 CHECK(it.value().GetAsDictionary(&dict)); 297 CHECK(it.value().GetAsDictionary(&dict));
231 const internal::SchemaNode* sub_schema = Parse(*dict, error); 298 int extra = Parse(*dict, error, internal);
232 if (!sub_schema) 299 if (extra == kInvalid)
233 return NULL; 300 return kInvalid;
234 std::string* key = new std::string(it.key()); 301 internal->strings.push_back(new std::string(it.key()));
235 keys_.push_back(key); 302 internal->property_nodes[index].key = internal->strings.back()->c_str();
236 property_nodes[index].key = key->c_str(); 303 internal->property_nodes[index].schema = extra;
237 property_nodes[index].schema = sub_schema;
238 } 304 }
239 CHECK_EQ(properties->size(), index); 305 CHECK_EQ(static_cast<int>(properties->size()), index - base_index);
240 properties_node->begin = property_nodes; 306 internal->properties_nodes[extra].begin = base_index;
241 properties_node->end = property_nodes + index; 307 internal->properties_nodes[extra].end = index;
242 } 308 }
243 309
244 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, 310 internal->schema_nodes[index].type = base::Value::TYPE_DICTIONARY;
245 &dict)) { 311 internal->schema_nodes[index].extra = extra;
246 const internal::SchemaNode* sub_schema = Parse(*dict, error); 312 return index;
247 if (!sub_schema)
248 return NULL;
249 properties_node->additional = sub_schema;
250 }
251
252 internal::SchemaNode* schema_node = new internal::SchemaNode;
253 schema_node->type = base::Value::TYPE_DICTIONARY;
254 schema_node->extra = properties_node;
255 schema_nodes_.push_back(schema_node);
256 return schema_node;
257 } 313 }
258 314
259 const internal::SchemaNode* SchemaOwner::ParseList( 315 // static
316 int SchemaOwner::ParseList(
260 const base::DictionaryValue& schema, 317 const base::DictionaryValue& schema,
261 std::string* error) { 318 std::string* error,
319 Internal* internal) {
262 const base::DictionaryValue* dict = NULL; 320 const base::DictionaryValue* dict = NULL;
263 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { 321 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
264 *error = "Arrays must declare a single schema for their items."; 322 *error = "Arrays must declare a single schema for their items.";
265 return NULL; 323 return kInvalid;
266 } 324 }
267 const internal::SchemaNode* items_schema_node = Parse(*dict, error); 325 int extra = Parse(*dict, error, internal);
268 if (!items_schema_node) 326 if (extra == kInvalid)
269 return NULL; 327 return kInvalid;
270 328 int index = static_cast<int>(internal->schema_nodes.size());
271 internal::SchemaNode* schema_node = new internal::SchemaNode; 329 internal->schema_nodes.push_back(SchemaNode());
272 schema_node->type = base::Value::TYPE_LIST; 330 internal->schema_nodes[index].type = base::Value::TYPE_LIST;
273 schema_node->extra = items_schema_node; 331 internal->schema_nodes[index].extra = extra;
274 schema_nodes_.push_back(schema_node); 332 return index;
275 return schema_node;
276 } 333 }
277 334
278 } // namespace policy 335 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698