Index: components/policy/core/common/schema.cc |
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc |
index 5f0cc18db875a1e34c2695699fdf5867f7b85461..712332261fb28cbd13a8cfd008fb7d08a5c1af04 100644 |
--- a/components/policy/core/common/schema.cc |
+++ b/components/policy/core/common/schema.cc |
@@ -5,6 +5,7 @@ |
#include "components/policy/core/common/schema.h" |
#include <algorithm> |
+#include <climits> |
#include <map> |
#include <utility> |
#include <vector> |
@@ -22,6 +23,7 @@ namespace policy { |
using internal::PropertiesNode; |
using internal::PropertyNode; |
+using internal::RestrictionNode; |
using internal::SchemaData; |
using internal::SchemaNode; |
@@ -41,11 +43,15 @@ typedef std::vector<std::pair<std::string, int*> > ReferenceList; |
// for "$ref" attributes). |
struct StorageSizes { |
StorageSizes() |
- : strings(0), schema_nodes(0), property_nodes(0), properties_nodes(0) {} |
+ : strings(0), schema_nodes(0), property_nodes(0), properties_nodes(0), |
+ restriction_nodes(0), int_enums(0), string_enums(0) { } |
size_t strings; |
size_t schema_nodes; |
size_t property_nodes; |
size_t properties_nodes; |
+ size_t restriction_nodes; |
+ size_t int_enums; |
+ size_t string_enums; |
}; |
// An invalid index, indicating that a node is not present; similar to a NULL |
@@ -108,6 +114,18 @@ class Schema::InternalStorage |
return schema_data_.property_nodes + index; |
} |
+ const RestrictionNode* restriction(int index) const { |
+ return schema_data_.restriction_nodes + index; |
+ } |
+ |
+ const int* int_enums(int index) const { |
+ return schema_data_.int_enums + index; |
+ } |
+ |
+ const char** string_enums(int index) const { |
+ return schema_data_.string_enums + index; |
+ } |
+ |
private: |
friend class base::RefCountedThreadSafe<InternalStorage>; |
@@ -152,6 +170,15 @@ class Schema::InternalStorage |
ReferenceList* reference_list, |
std::string* error); |
+ bool ParseEnum(const base::DictionaryValue& schema, |
+ base::Value::Type type, |
+ SchemaNode* schema_node, |
+ std::string* error); |
+ |
+ bool ParseRangedInt(const base::DictionaryValue& schema, |
+ SchemaNode* schema_node, |
+ std::string* error); |
+ |
// Assigns the IDs in |id_map| to the pending references in the |
// |reference_list|. If an ID is missing then |error| is set and false is |
// returned; otherwise returns true. |
@@ -164,6 +191,9 @@ class Schema::InternalStorage |
std::vector<SchemaNode> schema_nodes_; |
std::vector<PropertyNode> property_nodes_; |
std::vector<PropertiesNode> properties_nodes_; |
+ std::vector<RestrictionNode> restriction_nodes_; |
+ std::vector<int> int_enums_; |
+ std::vector<const char*> string_enums_; |
DISALLOW_COPY_AND_ASSIGN(InternalStorage); |
}; |
@@ -179,6 +209,9 @@ scoped_refptr<const Schema::InternalStorage> Schema::InternalStorage::Wrap( |
storage->schema_data_.schema_nodes = data->schema_nodes; |
storage->schema_data_.property_nodes = data->property_nodes; |
storage->schema_data_.properties_nodes = data->properties_nodes; |
+ storage->schema_data_.restriction_nodes = data->restriction_nodes; |
+ storage->schema_data_.int_enums = data->int_enums; |
+ storage->schema_data_.string_enums = data->string_enums; |
return storage; |
} |
@@ -198,6 +231,9 @@ Schema::InternalStorage::ParseSchema(const base::DictionaryValue& schema, |
storage->schema_nodes_.reserve(sizes.schema_nodes); |
storage->property_nodes_.reserve(sizes.property_nodes); |
storage->properties_nodes_.reserve(sizes.properties_nodes); |
+ storage->restriction_nodes_.reserve(sizes.restriction_nodes); |
+ storage->int_enums_.reserve(sizes.int_enums); |
+ storage->string_enums_.reserve(sizes.string_enums); |
int root_index = kInvalid; |
IdMap id_map; |
@@ -217,7 +253,10 @@ Schema::InternalStorage::ParseSchema(const base::DictionaryValue& schema, |
sizes.strings != storage->strings_.size() || |
sizes.schema_nodes != storage->schema_nodes_.size() || |
sizes.property_nodes != storage->property_nodes_.size() || |
- sizes.properties_nodes != storage->properties_nodes_.size()) { |
+ sizes.properties_nodes != storage->properties_nodes_.size() || |
+ sizes.restriction_nodes != storage->restriction_nodes_.size() || |
+ sizes.int_enums != storage->int_enums_.size() || |
+ sizes.string_enums != storage->string_enums_.size()) { |
*error = "Failed to parse the schema due to a Chrome bug. Please file a " |
"new issue at http://crbug.com"; |
return NULL; |
@@ -230,6 +269,9 @@ Schema::InternalStorage::ParseSchema(const base::DictionaryValue& schema, |
data->schema_nodes = vector_as_array(&storage->schema_nodes_); |
data->property_nodes = vector_as_array(&storage->property_nodes_); |
data->properties_nodes = vector_as_array(&storage->properties_nodes_); |
+ data->restriction_nodes = vector_as_array(&storage->restriction_nodes_); |
+ data->int_enums = vector_as_array(&storage->int_enums_); |
+ data->string_enums = vector_as_array(&storage->string_enums_); |
return storage; |
} |
@@ -275,6 +317,20 @@ void Schema::InternalStorage::DetermineStorageSizes( |
sizes->property_nodes++; |
} |
} |
+ } else if (schema.HasKey(schema::kEnum)) { |
+ const base::ListValue* possible_values = NULL; |
+ if (schema.GetList(schema::kEnum, &possible_values)) { |
+ if (type == base::Value::TYPE_INTEGER) { |
+ sizes->int_enums += possible_values->GetSize(); |
+ } else if (type == base::Value::TYPE_STRING) { |
+ sizes->string_enums += possible_values->GetSize(); |
+ sizes->strings += possible_values->GetSize(); |
+ } |
+ sizes->restriction_nodes++; |
+ } |
+ } else if (type == base::Value::TYPE_INTEGER) { |
+ if (schema.HasKey(schema::kMinimum) || schema.HasKey(schema::kMaximum)) |
+ sizes->restriction_nodes++; |
} |
} |
@@ -318,8 +374,18 @@ bool Schema::InternalStorage::Parse(const base::DictionaryValue& schema, |
} else if (type == base::Value::TYPE_LIST) { |
if (!ParseList(schema, schema_node, id_map, reference_list, error)) |
return false; |
+ } else if (schema.HasKey(schema::kEnum)) { |
+ if (!ParseEnum(schema, type, schema_node, error)) |
+ return false; |
+ } else if (schema.HasKey(schema::kMinimum) || |
+ schema.HasKey(schema::kMaximum)) { |
+ if (type != base::Value::TYPE_INTEGER) { |
+ *error = "Only integers can have minimum and maximum"; |
+ return false; |
+ } |
+ if (!ParseRangedInt(schema, schema_node, error)) |
+ return false; |
} |
- |
std::string id_string; |
if (schema.GetString(schema::kId, &id_string)) { |
if (ContainsKey(*id_map, id_string)) { |
@@ -394,6 +460,79 @@ bool Schema::InternalStorage::ParseList(const base::DictionaryValue& schema, |
return Parse(*dict, &schema_node->extra, id_map, reference_list, error); |
} |
+bool Schema::InternalStorage::ParseEnum(const base::DictionaryValue& schema, |
+ base::Value::Type type, |
+ SchemaNode* schema_node, |
+ std::string* error) { |
+ const base::ListValue *possible_values = NULL; |
+ if (!schema.GetList(schema::kEnum, &possible_values)) { |
+ *error = "Enum attribute must be a list value"; |
+ return false; |
+ } |
+ if (possible_values->empty()) { |
+ *error = "Enum attribute must be non-empty"; |
+ return false; |
+ } |
+ int offset_begin; |
+ int offset_end; |
+ if (type == base::Value::TYPE_INTEGER) { |
+ offset_begin = static_cast<int>(int_enums_.size()); |
+ int value; |
+ for (base::ListValue::const_iterator it = possible_values->begin(); |
+ it != possible_values->end(); ++it) { |
+ if (!(*it)->GetAsInteger(&value)) { |
+ *error = "Invalid enumeration member type"; |
+ return false; |
+ } |
+ int_enums_.push_back(value); |
+ } |
+ offset_end = static_cast<int>(int_enums_.size()); |
+ } else if (type == base::Value::TYPE_STRING) { |
+ offset_begin = static_cast<int>(string_enums_.size()); |
+ std::string value; |
+ for (base::ListValue::const_iterator it = possible_values->begin(); |
+ it != possible_values->end(); ++it) { |
+ if (!(*it)->GetAsString(&value)) { |
+ *error = "Invalid enumeration member type"; |
+ return false; |
+ } |
+ strings_.push_back(value); |
+ string_enums_.push_back(strings_.back().c_str()); |
+ } |
+ offset_end = static_cast<int>(string_enums_.size()); |
+ } else { |
+ *error = "Enumeration is only supported for integer and string."; |
+ return false; |
+ } |
+ schema_node->extra = static_cast<int>(restriction_nodes_.size()); |
+ restriction_nodes_.push_back(RestrictionNode()); |
+ restriction_nodes_.back().enumeration_restriction.offset_begin = offset_begin; |
+ restriction_nodes_.back().enumeration_restriction.offset_end = offset_end; |
+ return true; |
+} |
+ |
+bool Schema::InternalStorage::ParseRangedInt( |
+ const base::DictionaryValue& schema, |
+ SchemaNode* schema_node, |
+ std::string* error) { |
+ int min_value = INT_MIN; |
+ int max_value = INT_MAX; |
+ int value; |
+ if (schema.GetInteger(schema::kMinimum, &value)) |
+ min_value = value; |
+ if (schema.GetInteger(schema::kMaximum, &value)) |
+ max_value = value; |
+ if (min_value > max_value) { |
+ *error = "Invalid range restriction for int type."; |
+ return false; |
+ } |
+ schema_node->extra = static_cast<int>(restriction_nodes_.size()); |
+ restriction_nodes_.push_back(RestrictionNode()); |
+ restriction_nodes_.back().ranged_restriction.max_value = max_value; |
+ restriction_nodes_.back().ranged_restriction.min_value = min_value; |
+ return true; |
+} |
+ |
// static |
bool Schema::InternalStorage::ResolveReferences( |
const IdMap& id_map, |