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

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: added comments 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 // TODO: compute the sizes of these arrays before filling them up to avoid
65 // having to resize them.
66 ScopedVector<std::string> strings;
67 std::vector<SchemaNode> schema_nodes;
68 std::vector<PropertyNode> property_nodes;
69 std::vector<PropertiesNode> properties_nodes;
70
71 private:
72 DISALLOW_COPY_AND_ASSIGN(Internal);
73 };
74
75 Schema::Iterator::Iterator(const SchemaData* data, const PropertiesNode* node)
76 : data_(data),
77 it_(data->property_nodes + node->begin),
78 end_(data->property_nodes + node->end) {}
48 79
49 Schema::Iterator::Iterator(const Iterator& iterator) 80 Schema::Iterator::Iterator(const Iterator& iterator)
50 : it_(iterator.it_), 81 : data_(iterator.data_),
82 it_(iterator.it_),
51 end_(iterator.end_) {} 83 end_(iterator.end_) {}
52 84
53 Schema::Iterator::~Iterator() {} 85 Schema::Iterator::~Iterator() {}
54 86
55 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) { 87 Schema::Iterator& Schema::Iterator::operator=(const Iterator& iterator) {
88 data_ = iterator.data_;
56 it_ = iterator.it_; 89 it_ = iterator.it_;
57 end_ = iterator.end_; 90 end_ = iterator.end_;
58 return *this; 91 return *this;
59 } 92 }
60 93
61 bool Schema::Iterator::IsAtEnd() const { 94 bool Schema::Iterator::IsAtEnd() const {
62 return it_ == end_; 95 return it_ == end_;
63 } 96 }
64 97
65 void Schema::Iterator::Advance() { 98 void Schema::Iterator::Advance() {
66 ++it_; 99 ++it_;
67 } 100 }
68 101
69 const char* Schema::Iterator::key() const { 102 const char* Schema::Iterator::key() const {
70 return it_->key; 103 return it_->key;
71 } 104 }
72 105
73 Schema Schema::Iterator::schema() const { 106 Schema Schema::Iterator::schema() const {
74 return Schema(it_->schema); 107 return Schema(data_, data_->schema_nodes + it_->schema);
75 } 108 }
76 109
77 Schema::Schema() : schema_(NULL) {} 110 Schema::Schema() : data_(NULL), node_(NULL) {}
78 111
79 Schema::Schema(const internal::SchemaNode* schema) : schema_(schema) {} 112 Schema::Schema(const SchemaData* data, const SchemaNode* node)
113 : data_(data), node_(node) {}
80 114
81 Schema::Schema(const Schema& schema) : schema_(schema.schema_) {} 115 Schema::Schema(const Schema& schema)
116 : data_(schema.data_), node_(schema.node_) {}
82 117
83 Schema& Schema::operator=(const Schema& schema) { 118 Schema& Schema::operator=(const Schema& schema) {
84 schema_ = schema.schema_; 119 data_ = schema.data_;
120 node_ = schema.node_;
85 return *this; 121 return *this;
86 } 122 }
87 123
88 base::Value::Type Schema::type() const { 124 base::Value::Type Schema::type() const {
89 CHECK(valid()); 125 CHECK(valid());
90 return schema_->type; 126 return node_->type;
91 } 127 }
92 128
93 Schema::Iterator Schema::GetPropertiesIterator() const { 129 Schema::Iterator Schema::GetPropertiesIterator() const {
94 CHECK(valid()); 130 CHECK(valid());
95 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 131 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
96 return Iterator( 132 return Iterator(data_, data_->properties_nodes + node_->extra);
97 static_cast<const internal::PropertiesNode*>(schema_->extra));
98 } 133 }
99 134
100 namespace { 135 namespace {
101 136
102 bool CompareKeys(const internal::PropertyNode& node, const std::string& key) { 137 bool CompareKeys(const PropertyNode& node, const std::string& key) {
103 return node.key < key; 138 return node.key < key;
104 } 139 }
105 140
106 } // namespace 141 } // namespace
107 142
108 Schema Schema::GetKnownProperty(const std::string& key) const { 143 Schema Schema::GetKnownProperty(const std::string& key) const {
109 CHECK(valid()); 144 CHECK(valid());
110 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 145 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
111 const internal::PropertiesNode* properties_node = 146 const PropertiesNode* node = data_->properties_nodes + node_->extra;
112 static_cast<const internal::PropertiesNode*>(schema_->extra); 147 const PropertyNode* begin = data_->property_nodes + node->begin;
113 const internal::PropertyNode* it = std::lower_bound( 148 const PropertyNode* end = data_->property_nodes + node->end;
114 properties_node->begin, properties_node->end, key, CompareKeys); 149 const PropertyNode* it = std::lower_bound(begin, end, key, CompareKeys);
115 if (it != properties_node->end && it->key == key) 150 if (it != end && it->key == key)
116 return Schema(it->schema); 151 return Schema(data_, data_->schema_nodes + it->schema);
117 return Schema(); 152 return Schema();
118 } 153 }
119 154
120 Schema Schema::GetAdditionalProperties() const { 155 Schema Schema::GetAdditionalProperties() const {
121 CHECK(valid()); 156 CHECK(valid());
122 CHECK_EQ(base::Value::TYPE_DICTIONARY, type()); 157 CHECK_EQ(base::Value::TYPE_DICTIONARY, type());
123 return Schema( 158 const PropertiesNode* node = data_->properties_nodes + node_->extra;
124 static_cast<const internal::PropertiesNode*>(schema_->extra)->additional); 159 if (node->additional == kInvalid)
160 return Schema();
161 return Schema(data_, data_->schema_nodes + node->additional);
125 } 162 }
126 163
127 Schema Schema::GetProperty(const std::string& key) const { 164 Schema Schema::GetProperty(const std::string& key) const {
128 Schema schema = GetKnownProperty(key); 165 Schema schema = GetKnownProperty(key);
129 return schema.valid() ? schema : GetAdditionalProperties(); 166 return schema.valid() ? schema : GetAdditionalProperties();
130 } 167 }
131 168
132 Schema Schema::GetItems() const { 169 Schema Schema::GetItems() const {
133 CHECK(valid()); 170 CHECK(valid());
134 CHECK_EQ(base::Value::TYPE_LIST, type()); 171 CHECK_EQ(base::Value::TYPE_LIST, type());
135 return Schema(static_cast<const internal::SchemaNode*>(schema_->extra)); 172 if (node_->extra == kInvalid)
173 return Schema();
174 return Schema(data_, data_->schema_nodes + node_->extra);
136 } 175 }
137 176
138 SchemaOwner::SchemaOwner(const internal::SchemaNode* root) : root_(root) {} 177 SchemaOwner::SchemaOwner(const SchemaData* data, scoped_ptr<Internal> internal)
178 : internal_(internal.Pass()), data_(data) {}
139 179
140 SchemaOwner::~SchemaOwner() { 180 SchemaOwner::~SchemaOwner() {}
141 for (size_t i = 0; i < property_nodes_.size(); ++i) 181
142 delete[] property_nodes_[i]; 182 Schema SchemaOwner::schema() const {
183 // data_->schema_nodes[0] is the root node.
184 return Schema(data_, data_->schema_nodes + 0);
pastarmovj 2013/10/22 09:30:46 I don't think this "+ 0" really adds much value he
Joao da Silva 2013/10/22 12:53:27 Done.
143 } 185 }
144 186
145 // static 187 // static
146 scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const internal::SchemaNode* schema) { 188 scoped_ptr<SchemaOwner> SchemaOwner::Wrap(const SchemaData* data) {
147 return scoped_ptr<SchemaOwner>(new SchemaOwner(schema)); 189 return make_scoped_ptr(new SchemaOwner(data, scoped_ptr<Internal>()));
148 } 190 }
149 191
150 // static 192 // static
151 scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content, 193 scoped_ptr<SchemaOwner> SchemaOwner::Parse(const std::string& content,
152 std::string* error) { 194 std::string* error) {
153 // Validate as a generic JSON schema. 195 // Validate as a generic JSON schema.
154 scoped_ptr<base::DictionaryValue> dict = 196 scoped_ptr<base::DictionaryValue> dict =
155 JSONSchemaValidator::IsValidSchema(content, error); 197 JSONSchemaValidator::IsValidSchema(content, error);
156 if (!dict) 198 if (!dict)
157 return scoped_ptr<SchemaOwner>(); 199 return scoped_ptr<SchemaOwner>();
158 200
159 // Validate the main type. 201 // Validate the main type.
160 std::string string_value; 202 std::string string_value;
161 if (!dict->GetString(json_schema_constants::kType, &string_value) || 203 if (!dict->GetString(json_schema_constants::kType, &string_value) ||
162 string_value != json_schema_constants::kObject) { 204 string_value != json_schema_constants::kObject) {
163 *error = 205 *error =
164 "The main schema must have a type attribute with \"object\" value."; 206 "The main schema must have a type attribute with \"object\" value.";
165 return scoped_ptr<SchemaOwner>(); 207 return scoped_ptr<SchemaOwner>();
166 } 208 }
167 209
168 // Checks for invalid attributes at the top-level. 210 // Checks for invalid attributes at the top-level.
169 if (dict->HasKey(json_schema_constants::kAdditionalProperties) || 211 if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
170 dict->HasKey(json_schema_constants::kPatternProperties)) { 212 dict->HasKey(json_schema_constants::kPatternProperties)) {
171 *error = "\"additionalProperties\" and \"patternProperties\" are not " 213 *error = "\"additionalProperties\" and \"patternProperties\" are not "
172 "supported at the main schema."; 214 "supported at the main schema.";
173 return scoped_ptr<SchemaOwner>(); 215 return scoped_ptr<SchemaOwner>();
174 } 216 }
175 217
176 scoped_ptr<SchemaOwner> impl(new SchemaOwner(NULL)); 218 scoped_ptr<Internal> internal(new Internal);
177 impl->root_ = impl->Parse(*dict, error); 219 if (Parse(*dict, error, internal.get()) == kInvalid)
178 if (!impl->root_) 220 return scoped_ptr<SchemaOwner>();
179 impl.reset(); 221 SchemaData* data = &internal->schema_data;
180 return impl.PassAs<SchemaOwner>(); 222 data->schema_nodes = vector_as_array(&internal->schema_nodes);
223 data->property_nodes = vector_as_array(&internal->property_nodes);
224 data->properties_nodes = vector_as_array(&internal->properties_nodes);
225 return make_scoped_ptr(new SchemaOwner(data, internal.Pass()));
181 } 226 }
182 227
183 const internal::SchemaNode* SchemaOwner::Parse( 228 // static
229 int SchemaOwner::Parse(
184 const base::DictionaryValue& schema, 230 const base::DictionaryValue& schema,
185 std::string* error) { 231 std::string* error,
232 Internal* internal) {
186 std::string type_string; 233 std::string type_string;
187 if (!schema.GetString(json_schema_constants::kType, &type_string)) { 234 if (!schema.GetString(json_schema_constants::kType, &type_string)) {
188 *error = "The schema type must be declared."; 235 *error = "The schema type must be declared.";
189 return NULL; 236 return kInvalid;
190 } 237 }
191 238
192 base::Value::Type type = base::Value::TYPE_NULL; 239 base::Value::Type type = base::Value::TYPE_NULL;
193 if (!SchemaTypeToValueType(type_string, &type)) { 240 if (!SchemaTypeToValueType(type_string, &type)) {
194 *error = "Type not supported: " + type_string; 241 *error = "Type not supported: " + type_string;
195 return NULL; 242 return kInvalid;
196 } 243 }
197 244
198 if (type == base::Value::TYPE_DICTIONARY) 245 if (type == base::Value::TYPE_DICTIONARY)
199 return ParseDictionary(schema, error); 246 return ParseDictionary(schema, error, internal);
200 if (type == base::Value::TYPE_LIST) 247 if (type == base::Value::TYPE_LIST)
201 return ParseList(schema, error); 248 return ParseList(schema, error, internal);
202 249
203 internal::SchemaNode* node = new internal::SchemaNode; 250 int index = static_cast<int>(internal->schema_nodes.size());
204 node->type = type; 251 internal->schema_nodes.push_back(SchemaNode());
205 node->extra = NULL; 252 SchemaNode& node = internal->schema_nodes.back();
206 schema_nodes_.push_back(node); 253 node.type = type;
207 return node; 254 node.extra = kInvalid;
255 return index;
208 } 256 }
209 257
210 const internal::SchemaNode* SchemaOwner::ParseDictionary( 258 // static
259 int SchemaOwner::ParseDictionary(
211 const base::DictionaryValue& schema, 260 const base::DictionaryValue& schema,
212 std::string* error) { 261 std::string* error,
213 internal::PropertiesNode* properties_node = new internal::PropertiesNode; 262 Internal* internal) {
214 properties_node->begin = NULL; 263 // Note: recursive calls to Parse() invalidate iterators and references into
215 properties_node->end = NULL; 264 // the vectors.
216 properties_node->additional = NULL; 265
217 properties_nodes_.push_back(properties_node); 266 // Reserve an index for this dictionary at the front, so that the root node
267 // is at index 0.
268 int index = static_cast<int>(internal->schema_nodes.size());
269 internal->schema_nodes.push_back(SchemaNode());
270
271 int extra = static_cast<int>(internal->properties_nodes.size());
272 internal->properties_nodes.push_back(PropertiesNode());
273 internal->properties_nodes[extra].begin = kInvalid;
274 internal->properties_nodes[extra].end = kInvalid;
275 internal->properties_nodes[extra].additional = kInvalid;
218 276
219 const base::DictionaryValue* dict = NULL; 277 const base::DictionaryValue* dict = NULL;
dconnelly 2013/10/22 11:55:52 Can these be moved closer to their first use?
Joao da Silva 2013/10/22 12:53:27 Done.
220 const base::DictionaryValue* properties = NULL; 278 const base::DictionaryValue* properties = NULL;
279
280 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties,
281 &dict)) {
282 int additional = Parse(*dict, error, internal);
283 if (additional == kInvalid)
284 return kInvalid;
285 internal->properties_nodes[extra].additional = additional;
286 }
287
221 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { 288 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) {
222 internal::PropertyNode* property_nodes = 289 int base_index = static_cast<int>(internal->property_nodes.size());
223 new internal::PropertyNode[properties->size()]; 290 // This reserves nodes for all of the |properties|, and makes sure they
224 property_nodes_.push_back(property_nodes); 291 // are contiguous. Recursive calls to Parse() will append after these
292 // elements.
293 internal->property_nodes.resize(base_index + properties->size());
225 294
226 size_t index = 0; 295 int index = base_index;
pastarmovj 2013/10/22 09:30:46 Just a warning that this redefines the variable in
Joao da Silva 2013/10/22 12:53:27 Renamed the outer "index" to "schema_index".
227 for (base::DictionaryValue::Iterator it(*properties); 296 for (base::DictionaryValue::Iterator it(*properties);
228 !it.IsAtEnd(); it.Advance(), ++index) { 297 !it.IsAtEnd(); it.Advance(), ++index) {
229 // This should have been verified by the JSONSchemaValidator. 298 // This should have been verified by the JSONSchemaValidator.
230 CHECK(it.value().GetAsDictionary(&dict)); 299 CHECK(it.value().GetAsDictionary(&dict));
231 const internal::SchemaNode* sub_schema = Parse(*dict, error); 300 int extra = Parse(*dict, error, internal);
232 if (!sub_schema) 301 if (extra == kInvalid)
233 return NULL; 302 return kInvalid;
234 std::string* key = new std::string(it.key()); 303 internal->strings.push_back(new std::string(it.key()));
235 keys_.push_back(key); 304 internal->property_nodes[index].key = internal->strings.back()->c_str();
236 property_nodes[index].key = key->c_str(); 305 internal->property_nodes[index].schema = extra;
237 property_nodes[index].schema = sub_schema;
238 } 306 }
239 CHECK_EQ(properties->size(), index); 307 CHECK_EQ(static_cast<int>(properties->size()), index - base_index);
240 properties_node->begin = property_nodes; 308 internal->properties_nodes[extra].begin = base_index;
241 properties_node->end = property_nodes + index; 309 internal->properties_nodes[extra].end = index;
242 } 310 }
243 311
244 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, 312 internal->schema_nodes[index].type = base::Value::TYPE_DICTIONARY;
245 &dict)) { 313 internal->schema_nodes[index].extra = extra;
246 const internal::SchemaNode* sub_schema = Parse(*dict, error); 314 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 } 315 }
258 316
259 const internal::SchemaNode* SchemaOwner::ParseList( 317 // static
318 int SchemaOwner::ParseList(
260 const base::DictionaryValue& schema, 319 const base::DictionaryValue& schema,
261 std::string* error) { 320 std::string* error,
321 Internal* internal) {
262 const base::DictionaryValue* dict = NULL; 322 const base::DictionaryValue* dict = NULL;
263 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { 323 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
264 *error = "Arrays must declare a single schema for their items."; 324 *error = "Arrays must declare a single schema for their items.";
265 return NULL; 325 return kInvalid;
266 } 326 }
267 const internal::SchemaNode* items_schema_node = Parse(*dict, error); 327 int extra = Parse(*dict, error, internal);
268 if (!items_schema_node) 328 if (extra == kInvalid)
269 return NULL; 329 return kInvalid;
270 330 int index = static_cast<int>(internal->schema_nodes.size());
271 internal::SchemaNode* schema_node = new internal::SchemaNode; 331 internal->schema_nodes.push_back(SchemaNode());
272 schema_node->type = base::Value::TYPE_LIST; 332 internal->schema_nodes[index].type = base::Value::TYPE_LIST;
273 schema_node->extra = items_schema_node; 333 internal->schema_nodes[index].extra = extra;
274 schema_nodes_.push_back(schema_node); 334 return index;
275 return schema_node;
276 } 335 }
277 336
278 } // namespace policy 337 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698