- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / shared_impl / var_value_conversions.cc
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.
4
5 #include "ppapi/shared_impl/var_value_conversions.h"
6
7 #include <limits>
8 #include <set>
9 #include <stack>
10
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"
24
25 namespace ppapi {
26
27 namespace {
28
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) {
36   }
37
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;
47 };
48
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) {
55   }
56
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;
61 };
62
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|.
66 //
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;
77     }
78     case PP_VARTYPE_BOOL: {
79       value->reset(new base::FundamentalValue(PP_ToBool(var.value.as_bool)));
80       return true;
81     }
82     case PP_VARTYPE_INT32: {
83       value->reset(new base::FundamentalValue(var.value.as_int));
84       return true;
85     }
86     case PP_VARTYPE_DOUBLE: {
87       value->reset(new base::FundamentalValue(var.value.as_double));
88       return true;
89     }
90     case PP_VARTYPE_STRING: {
91       StringVar* string_var = StringVar::FromPPVar(var);
92       if (!string_var)
93         return false;
94
95       value->reset(new base::StringValue(string_var->value()));
96       return true;
97     }
98     case PP_VARTYPE_OBJECT: {
99       return false;
100     }
101     case PP_VARTYPE_ARRAY: {
102       if (ContainsKey(parent_ids, var.value.as_id)) {
103         // A circular reference is found.
104         return false;
105       }
106
107       value->reset(new base::ListValue());
108       state->push(VarNode(var, value->get()));
109       return true;
110     }
111     case PP_VARTYPE_DICTIONARY: {
112       if (ContainsKey(parent_ids, var.value.as_id)) {
113         // A circular reference is found.
114         return false;
115       }
116
117       value->reset(new base::DictionaryValue());
118       state->push(VarNode(var, value->get()));
119       return true;
120     }
121     case PP_VARTYPE_ARRAY_BUFFER: {
122       ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(var);
123       if (!array_buffer)
124         return false;
125
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;
133     }
134     case PP_VARTYPE_RESOURCE: {
135       return false;
136     }
137   }
138   NOTREACHED();
139   return false;
140 }
141
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|.
145 //
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;
154     }
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;
160       }
161       return false;
162     }
163     case base::Value::TYPE_INTEGER: {
164       int result = 0;
165       if (value.GetAsInteger(&result)) {
166         *var = PP_MakeInt32(result);
167         return true;
168       }
169       return false;
170     }
171     case base::Value::TYPE_DOUBLE: {
172       double result = 0;
173       if (value.GetAsDouble(&result)) {
174         *var = PP_MakeDouble(result);
175         return true;
176       }
177       return false;
178     }
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;
185       }
186       return false;
187     }
188     case base::Value::TYPE_BINARY: {
189       const base::BinaryValue& binary_value =
190           static_cast<const base::BinaryValue&>(value);
191
192       size_t size = binary_value.GetSize();
193       if (size > std::numeric_limits<uint32>::max())
194         return false;
195
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;
203       }
204       return false;
205     }
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;
211     }
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;
217     }
218   }
219   NOTREACHED();
220   return false;
221 }
222
223 }  // namespace
224
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;
230
231   if (!CreateValueFromVarHelper(parent_ids, var, &root_value, &state))
232     return NULL;
233
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;
242
243       DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var);
244       if (!dict_var)
245         return NULL;
246
247       DCHECK(top.value->GetType() == base::Value::TYPE_DICTIONARY);
248       base::DictionaryValue* dict_value =
249           static_cast<base::DictionaryValue*>(top.value);
250
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;
259         }
260
261         scoped_ptr<base::Value> child_value;
262         if (!CreateValueFromVarHelper(parent_ids, iter->second.get(),
263                                       &child_value, &state)) {
264           return NULL;
265         }
266
267         dict_value->SetWithoutPathExpansion(iter->first, child_value.release());
268       }
269     } else if (top.var.type == PP_VARTYPE_ARRAY) {
270       parent_ids.insert(top.var.value.as_id);
271       top.sentinel = true;
272
273       ArrayVar* array_var = ArrayVar::FromPPVar(top.var);
274       if (!array_var)
275         return NULL;
276
277       DCHECK(top.value->GetType() == base::Value::TYPE_LIST);
278       base::ListValue* list_value = static_cast<base::ListValue*>(top.value);
279
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;
288         }
289
290         list_value->Append(child_value.release());
291       }
292     } else {
293       NOTREACHED();
294       return NULL;
295     }
296   }
297   DCHECK(parent_ids.empty());
298   return root_value.release();
299 }
300
301 PP_Var CreateVarFromValue(const base::Value& value) {
302   std::stack<ValueNode> state;
303   ScopedPPVar root_var;
304
305   if (!CreateVarFromValueHelper(value, &root_var, &state))
306     return PP_MakeUndefined();
307
308   while (!state.empty()) {
309     ValueNode top = state.top();
310     state.pop();
311
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();
324         }
325       }
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();
337
338         array_var->elements().push_back(child_var);
339       }
340     } else {
341       NOTREACHED();
342       return PP_MakeUndefined();
343     }
344   }
345
346   return root_var.Release();
347 }
348
349 base::ListValue* CreateListValueFromVarVector(
350     const std::vector<PP_Var>& vars) {
351   scoped_ptr<base::ListValue> list_value(new base::ListValue());
352
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);
360   }
361   return list_value.release();
362 }
363
364 bool CreateVarVectorFromListValue(const base::ListValue& list_value,
365                                   std::vector<PP_Var>* vars) {
366   if (!vars)
367     return false;
368
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;
378
379     result.push_back(child_var);
380   }
381
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());
388   }
389
390   return true;
391 }
392
393 }  // namespace ppapi
394