Move prefs::kLastPolicyStatisticsUpdate to the policy component.
[chromium-blink-merge.git] / ppapi / shared_impl / var_value_conversions.cc
blobe3a5bddc4f01ee71dcef26c417bbd14484a1e970
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/shared_impl/var_value_conversions.h"
7 #include <limits>
8 #include <set>
9 #include <stack>
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stl_util.h"
15 #include "base/values.h"
16 #include "ppapi/c/pp_bool.h"
17 #include "ppapi/c/pp_stdint.h"
18 #include "ppapi/shared_impl/array_var.h"
19 #include "ppapi/shared_impl/dictionary_var.h"
20 #include "ppapi/shared_impl/ppapi_globals.h"
21 #include "ppapi/shared_impl/scoped_pp_var.h"
22 #include "ppapi/shared_impl/var.h"
23 #include "ppapi/shared_impl/var_tracker.h"
25 namespace ppapi {
27 namespace {
29 // In CreateValueFromVar(), a stack is used to keep track of conversion progress
30 // of array and dictionary vars. VarNode represents elements of that stack.
31 struct VarNode {
32 VarNode(const PP_Var& in_var, base::Value* in_value)
33 : var(in_var),
34 value(in_value),
35 sentinel(false) {
38 // This object doesn't hold a reference to it.
39 PP_Var var;
40 // It is not owned by this object.
41 base::Value* value;
42 // When this is set to true for a node in the stack, it means that we have
43 // finished processing the node itself. However, we keep it in the stack as
44 // a sentinel. When it becomes the top element of the stack again, we know
45 // that we have processed all the descendants of this node.
46 bool sentinel;
49 // In CreateVarFromValue(), a stack is used to keep track of conversion progress
50 // of list and dictionary values. ValueNode represents elements of that stack.
51 struct ValueNode {
52 ValueNode(const PP_Var& in_var, const base::Value* in_value)
53 : var(in_var),
54 value(in_value) {
57 // This object doesn't hold a reference to it.
58 PP_Var var;
59 // It is not owned by this object.
60 const base::Value* value;
63 // Helper function for CreateValueFromVar(). It only looks at |var| but not its
64 // descendants. The conversion result is stored in |value|. If |var| is array or
65 // dictionary, a new node is pushed onto |state|.
67 // Returns false on failure.
68 bool CreateValueFromVarHelper(const std::set<int64_t>& parent_ids,
69 const PP_Var& var,
70 scoped_ptr<base::Value>* value,
71 std::stack<VarNode>* state) {
72 switch (var.type) {
73 case PP_VARTYPE_UNDEFINED:
74 case PP_VARTYPE_NULL: {
75 value->reset(base::Value::CreateNullValue());
76 return true;
78 case PP_VARTYPE_BOOL: {
79 value->reset(new base::FundamentalValue(PP_ToBool(var.value.as_bool)));
80 return true;
82 case PP_VARTYPE_INT32: {
83 value->reset(new base::FundamentalValue(var.value.as_int));
84 return true;
86 case PP_VARTYPE_DOUBLE: {
87 value->reset(new base::FundamentalValue(var.value.as_double));
88 return true;
90 case PP_VARTYPE_STRING: {
91 StringVar* string_var = StringVar::FromPPVar(var);
92 if (!string_var)
93 return false;
95 value->reset(new base::StringValue(string_var->value()));
96 return true;
98 case PP_VARTYPE_OBJECT: {
99 return false;
101 case PP_VARTYPE_ARRAY: {
102 if (ContainsKey(parent_ids, var.value.as_id)) {
103 // A circular reference is found.
104 return false;
107 value->reset(new base::ListValue());
108 state->push(VarNode(var, value->get()));
109 return true;
111 case PP_VARTYPE_DICTIONARY: {
112 if (ContainsKey(parent_ids, var.value.as_id)) {
113 // A circular reference is found.
114 return false;
117 value->reset(new base::DictionaryValue());
118 state->push(VarNode(var, value->get()));
119 return true;
121 case PP_VARTYPE_ARRAY_BUFFER: {
122 ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(var);
123 if (!array_buffer)
124 return false;
126 base::BinaryValue* binary_value =
127 base::BinaryValue::CreateWithCopiedBuffer(
128 static_cast<const char*>(array_buffer->Map()),
129 array_buffer->ByteLength());
130 array_buffer->Unmap();
131 value->reset(binary_value);
132 return true;
134 case PP_VARTYPE_RESOURCE: {
135 return false;
138 NOTREACHED();
139 return false;
142 // Helper function for CreateVarFromValue(). It only looks at |value| but not
143 // its descendants. The conversion result is stored in |var|. If |value| is list
144 // or dictionary, a new node is pushed onto |state|.
146 // Returns false on failure.
147 bool CreateVarFromValueHelper(const base::Value& value,
148 ScopedPPVar* var,
149 std::stack<ValueNode>* state) {
150 switch (value.GetType()) {
151 case base::Value::TYPE_NULL: {
152 *var = PP_MakeNull();
153 return true;
155 case base::Value::TYPE_BOOLEAN: {
156 bool result = false;
157 if (value.GetAsBoolean(&result)) {
158 *var = PP_MakeBool(PP_FromBool(result));
159 return true;
161 return false;
163 case base::Value::TYPE_INTEGER: {
164 int result = 0;
165 if (value.GetAsInteger(&result)) {
166 *var = PP_MakeInt32(result);
167 return true;
169 return false;
171 case base::Value::TYPE_DOUBLE: {
172 double result = 0;
173 if (value.GetAsDouble(&result)) {
174 *var = PP_MakeDouble(result);
175 return true;
177 return false;
179 case base::Value::TYPE_STRING: {
180 std::string result;
181 if (value.GetAsString(&result)) {
182 *var = ScopedPPVar(ScopedPPVar::PassRef(),
183 StringVar::StringToPPVar(result));
184 return true;
186 return false;
188 case base::Value::TYPE_BINARY: {
189 const base::BinaryValue& binary_value =
190 static_cast<const base::BinaryValue&>(value);
192 size_t size = binary_value.GetSize();
193 if (size > std::numeric_limits<uint32>::max())
194 return false;
196 ScopedPPVar temp(
197 ScopedPPVar::PassRef(),
198 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
199 static_cast<uint32>(size), binary_value.GetBuffer()));
200 if (temp.get().type == PP_VARTYPE_ARRAY_BUFFER) {
201 *var = temp;
202 return true;
204 return false;
206 case base::Value::TYPE_DICTIONARY: {
207 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
208 *var = ScopedPPVar(ScopedPPVar::PassRef(), dict_var->GetPPVar());
209 state->push(ValueNode(var->get(), &value));
210 return true;
212 case base::Value::TYPE_LIST: {
213 scoped_refptr<ArrayVar> array_var(new ArrayVar());
214 *var = ScopedPPVar(ScopedPPVar::PassRef(), array_var->GetPPVar());
215 state->push(ValueNode(var->get(), &value));
216 return true;
219 NOTREACHED();
220 return false;
223 } // namespace
225 base::Value* CreateValueFromVar(const PP_Var& var) {
226 // Used to detect circular references.
227 std::set<int64_t> parent_ids;
228 std::stack<VarNode> state;
229 scoped_ptr<base::Value> root_value;
231 if (!CreateValueFromVarHelper(parent_ids, var, &root_value, &state))
232 return NULL;
234 while (!state.empty()) {
235 VarNode& top = state.top();
236 if (top.sentinel) {
237 parent_ids.erase(top.var.value.as_id);
238 state.pop();
239 } else if (top.var.type == PP_VARTYPE_DICTIONARY) {
240 parent_ids.insert(top.var.value.as_id);
241 top.sentinel = true;
243 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var);
244 if (!dict_var)
245 return NULL;
247 DCHECK(top.value->GetType() == base::Value::TYPE_DICTIONARY);
248 base::DictionaryValue* dict_value =
249 static_cast<base::DictionaryValue*>(top.value);
251 for (DictionaryVar::KeyValueMap::const_iterator iter =
252 dict_var->key_value_map().begin();
253 iter != dict_var->key_value_map().end();
254 ++iter) {
255 // Skip the key-value pair if the value is undefined or null.
256 if (iter->second.get().type == PP_VARTYPE_UNDEFINED ||
257 iter->second.get().type == PP_VARTYPE_NULL) {
258 continue;
261 scoped_ptr<base::Value> child_value;
262 if (!CreateValueFromVarHelper(parent_ids, iter->second.get(),
263 &child_value, &state)) {
264 return NULL;
267 dict_value->SetWithoutPathExpansion(iter->first, child_value.release());
269 } else if (top.var.type == PP_VARTYPE_ARRAY) {
270 parent_ids.insert(top.var.value.as_id);
271 top.sentinel = true;
273 ArrayVar* array_var = ArrayVar::FromPPVar(top.var);
274 if (!array_var)
275 return NULL;
277 DCHECK(top.value->GetType() == base::Value::TYPE_LIST);
278 base::ListValue* list_value = static_cast<base::ListValue*>(top.value);
280 for (ArrayVar::ElementVector::const_iterator iter =
281 array_var->elements().begin();
282 iter != array_var->elements().end();
283 ++iter) {
284 scoped_ptr<base::Value> child_value;
285 if (!CreateValueFromVarHelper(parent_ids, iter->get(), &child_value,
286 &state)) {
287 return NULL;
290 list_value->Append(child_value.release());
292 } else {
293 NOTREACHED();
294 return NULL;
297 DCHECK(parent_ids.empty());
298 return root_value.release();
301 PP_Var CreateVarFromValue(const base::Value& value) {
302 std::stack<ValueNode> state;
303 ScopedPPVar root_var;
305 if (!CreateVarFromValueHelper(value, &root_var, &state))
306 return PP_MakeUndefined();
308 while (!state.empty()) {
309 ValueNode top = state.top();
310 state.pop();
312 if (top.value->GetType() == base::Value::TYPE_DICTIONARY) {
313 const base::DictionaryValue* dict_value =
314 static_cast<const base::DictionaryValue*>(top.value);
315 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var);
316 DCHECK(dict_var);
317 for (base::DictionaryValue::Iterator iter(*dict_value);
318 !iter.IsAtEnd();
319 iter.Advance()) {
320 ScopedPPVar child_var;
321 if (!CreateVarFromValueHelper(iter.value(), &child_var, &state) ||
322 !dict_var->SetWithStringKey(iter.key(), child_var.get())) {
323 return PP_MakeUndefined();
326 } else if (top.value->GetType() == base::Value::TYPE_LIST) {
327 const base::ListValue* list_value =
328 static_cast<const base::ListValue*>(top.value);
329 ArrayVar* array_var = ArrayVar::FromPPVar(top.var);
330 DCHECK(array_var);
331 for (base::ListValue::const_iterator iter = list_value->begin();
332 iter != list_value->end();
333 ++iter) {
334 ScopedPPVar child_var;
335 if (!CreateVarFromValueHelper(**iter, &child_var, &state))
336 return PP_MakeUndefined();
338 array_var->elements().push_back(child_var);
340 } else {
341 NOTREACHED();
342 return PP_MakeUndefined();
346 return root_var.Release();
349 base::ListValue* CreateListValueFromVarVector(
350 const std::vector<PP_Var>& vars) {
351 scoped_ptr<base::ListValue> list_value(new base::ListValue());
353 for (std::vector<PP_Var>::const_iterator iter = vars.begin();
354 iter != vars.end();
355 ++iter) {
356 base::Value* value = CreateValueFromVar(*iter);
357 if (!value)
358 return NULL;
359 list_value->Append(value);
361 return list_value.release();
364 bool CreateVarVectorFromListValue(const base::ListValue& list_value,
365 std::vector<PP_Var>* vars) {
366 if (!vars)
367 return false;
369 std::vector<ScopedPPVar> result;
370 result.reserve(list_value.GetSize());
371 for (base::ListValue::const_iterator iter = list_value.begin();
372 iter != list_value.end();
373 ++iter) {
374 ScopedPPVar child_var(ScopedPPVar::PassRef(),
375 CreateVarFromValue(**iter));
376 if (child_var.get().type == PP_VARTYPE_UNDEFINED)
377 return false;
379 result.push_back(child_var);
382 vars->clear();
383 vars->reserve(result.size());
384 for (std::vector<ScopedPPVar>::iterator iter = result.begin();
385 iter != result.end();
386 ++iter) {
387 vars->push_back(iter->Release());
390 return true;
393 } // namespace ppapi