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 25namespace ppapi { 26 27namespace { 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. 31struct 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. 51struct 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. 68bool 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. 147bool 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 225base::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 301PP_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 349base::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 364bool 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 395