Home | History | Annotate | Download | only in shared_impl
      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 
    395