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 } 135 NOTREACHED(); 136 return false; 137 } 138 139 // Helper function for CreateVarFromValue(). It only looks at |value| but not 140 // its descendants. The conversion result is stored in |var|. If |value| is list 141 // or dictionary, a new node is pushed onto |state|. 142 // 143 // Returns false on failure. 144 bool CreateVarFromValueHelper(const base::Value& value, 145 ScopedPPVar* var, 146 std::stack<ValueNode>* state) { 147 switch (value.GetType()) { 148 case base::Value::TYPE_NULL: { 149 *var = PP_MakeNull(); 150 return true; 151 } 152 case base::Value::TYPE_BOOLEAN: { 153 bool result = false; 154 if (value.GetAsBoolean(&result)) { 155 *var = PP_MakeBool(PP_FromBool(result)); 156 return true; 157 } 158 return false; 159 } 160 case base::Value::TYPE_INTEGER: { 161 int result = 0; 162 if (value.GetAsInteger(&result)) { 163 *var = PP_MakeInt32(result); 164 return true; 165 } 166 return false; 167 } 168 case base::Value::TYPE_DOUBLE: { 169 double result = 0; 170 if (value.GetAsDouble(&result)) { 171 *var = PP_MakeDouble(result); 172 return true; 173 } 174 return false; 175 } 176 case base::Value::TYPE_STRING: { 177 std::string result; 178 if (value.GetAsString(&result)) { 179 *var = ScopedPPVar(ScopedPPVar::PassRef(), 180 StringVar::StringToPPVar(result)); 181 return true; 182 } 183 return false; 184 } 185 case base::Value::TYPE_BINARY: { 186 const base::BinaryValue& binary_value = 187 static_cast<const base::BinaryValue&>(value); 188 189 size_t size = binary_value.GetSize(); 190 if (size > std::numeric_limits<uint32>::max()) 191 return false; 192 193 ScopedPPVar temp( 194 ScopedPPVar::PassRef(), 195 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 196 static_cast<uint32>(size), binary_value.GetBuffer())); 197 if (temp.get().type == PP_VARTYPE_ARRAY_BUFFER) { 198 *var = temp; 199 return true; 200 } 201 return false; 202 } 203 case base::Value::TYPE_DICTIONARY: { 204 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 205 *var = ScopedPPVar(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 206 state->push(ValueNode(var->get(), &value)); 207 return true; 208 } 209 case base::Value::TYPE_LIST: { 210 scoped_refptr<ArrayVar> array_var(new ArrayVar()); 211 *var = ScopedPPVar(ScopedPPVar::PassRef(), array_var->GetPPVar()); 212 state->push(ValueNode(var->get(), &value)); 213 return true; 214 } 215 } 216 NOTREACHED(); 217 return false; 218 } 219 220 } // namespace 221 222 base::Value* CreateValueFromVar(const PP_Var& var) { 223 // Used to detect circular references. 224 std::set<int64_t> parent_ids; 225 std::stack<VarNode> state; 226 scoped_ptr<base::Value> root_value; 227 228 if (!CreateValueFromVarHelper(parent_ids, var, &root_value, &state)) 229 return NULL; 230 231 while (!state.empty()) { 232 VarNode& top = state.top(); 233 if (top.sentinel) { 234 parent_ids.erase(top.var.value.as_id); 235 state.pop(); 236 } else if (top.var.type == PP_VARTYPE_DICTIONARY) { 237 parent_ids.insert(top.var.value.as_id); 238 top.sentinel = true; 239 240 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var); 241 if (!dict_var) 242 return NULL; 243 244 DCHECK(top.value->GetType() == base::Value::TYPE_DICTIONARY); 245 base::DictionaryValue* dict_value = 246 static_cast<base::DictionaryValue*>(top.value); 247 248 for (DictionaryVar::KeyValueMap::const_iterator iter = 249 dict_var->key_value_map().begin(); 250 iter != dict_var->key_value_map().end(); 251 ++iter) { 252 // Skip the key-value pair if the value is undefined or null. 253 if (iter->second.get().type == PP_VARTYPE_UNDEFINED || 254 iter->second.get().type == PP_VARTYPE_NULL) { 255 continue; 256 } 257 258 scoped_ptr<base::Value> child_value; 259 if (!CreateValueFromVarHelper(parent_ids, iter->second.get(), 260 &child_value, &state)) { 261 return NULL; 262 } 263 264 dict_value->SetWithoutPathExpansion(iter->first, child_value.release()); 265 } 266 } else if (top.var.type == PP_VARTYPE_ARRAY) { 267 parent_ids.insert(top.var.value.as_id); 268 top.sentinel = true; 269 270 ArrayVar* array_var = ArrayVar::FromPPVar(top.var); 271 if (!array_var) 272 return NULL; 273 274 DCHECK(top.value->GetType() == base::Value::TYPE_LIST); 275 base::ListValue* list_value = static_cast<base::ListValue*>(top.value); 276 277 for (ArrayVar::ElementVector::const_iterator iter = 278 array_var->elements().begin(); 279 iter != array_var->elements().end(); 280 ++iter) { 281 scoped_ptr<base::Value> child_value; 282 if (!CreateValueFromVarHelper(parent_ids, iter->get(), &child_value, 283 &state)) { 284 return NULL; 285 } 286 287 list_value->Append(child_value.release()); 288 } 289 } else { 290 NOTREACHED(); 291 return NULL; 292 } 293 } 294 DCHECK(parent_ids.empty()); 295 return root_value.release(); 296 } 297 298 PP_Var CreateVarFromValue(const base::Value& value) { 299 std::stack<ValueNode> state; 300 ScopedPPVar root_var; 301 302 if (!CreateVarFromValueHelper(value, &root_var, &state)) 303 return PP_MakeUndefined(); 304 305 while (!state.empty()) { 306 ValueNode top = state.top(); 307 state.pop(); 308 309 if (top.value->GetType() == base::Value::TYPE_DICTIONARY) { 310 const base::DictionaryValue* dict_value = 311 static_cast<const base::DictionaryValue*>(top.value); 312 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var); 313 DCHECK(dict_var); 314 for (base::DictionaryValue::Iterator iter(*dict_value); 315 !iter.IsAtEnd(); 316 iter.Advance()) { 317 ScopedPPVar child_var; 318 if (!CreateVarFromValueHelper(iter.value(), &child_var, &state) || 319 !dict_var->SetWithStringKey(iter.key(), child_var.get())) { 320 return PP_MakeUndefined(); 321 } 322 } 323 } else if (top.value->GetType() == base::Value::TYPE_LIST) { 324 const base::ListValue* list_value = 325 static_cast<const base::ListValue*>(top.value); 326 ArrayVar* array_var = ArrayVar::FromPPVar(top.var); 327 DCHECK(array_var); 328 for (base::ListValue::const_iterator iter = list_value->begin(); 329 iter != list_value->end(); 330 ++iter) { 331 ScopedPPVar child_var; 332 if (!CreateVarFromValueHelper(**iter, &child_var, &state)) 333 return PP_MakeUndefined(); 334 335 array_var->elements().push_back(child_var); 336 } 337 } else { 338 NOTREACHED(); 339 return PP_MakeUndefined(); 340 } 341 } 342 343 return root_var.Release(); 344 } 345 346 base::ListValue* CreateListValueFromVarVector( 347 const std::vector<PP_Var>& vars) { 348 scoped_ptr<base::ListValue> list_value(new base::ListValue()); 349 350 for (std::vector<PP_Var>::const_iterator iter = vars.begin(); 351 iter != vars.end(); 352 ++iter) { 353 base::Value* value = CreateValueFromVar(*iter); 354 if (!value) 355 return NULL; 356 list_value->Append(value); 357 } 358 return list_value.release(); 359 } 360 361 bool CreateVarVectorFromListValue(const base::ListValue& list_value, 362 std::vector<PP_Var>* vars) { 363 if (!vars) 364 return false; 365 366 std::vector<ScopedPPVar> result; 367 result.reserve(list_value.GetSize()); 368 for (base::ListValue::const_iterator iter = list_value.begin(); 369 iter != list_value.end(); 370 ++iter) { 371 ScopedPPVar child_var(ScopedPPVar::PassRef(), 372 CreateVarFromValue(**iter)); 373 if (child_var.get().type == PP_VARTYPE_UNDEFINED) 374 return false; 375 376 result.push_back(child_var); 377 } 378 379 vars->clear(); 380 vars->reserve(result.size()); 381 for (std::vector<ScopedPPVar>::iterator iter = result.begin(); 382 iter != result.end(); 383 ++iter) { 384 vars->push_back(iter->Release()); 385 } 386 387 return true; 388 } 389 390 } // namespace ppapi 391 392