Home | History | Annotate | Download | only in cpp
      1 // Copyright (c) 2012 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/cpp/var.h"
      6 
      7 #include <stdio.h>
      8 #include <string.h>
      9 
     10 #include <algorithm>
     11 
     12 #include "ppapi/c/pp_var.h"
     13 #include "ppapi/c/ppb_var.h"
     14 #include "ppapi/cpp/instance.h"
     15 #include "ppapi/cpp/logging.h"
     16 #include "ppapi/cpp/module.h"
     17 #include "ppapi/cpp/module_impl.h"
     18 
     19 // Define equivalent to snprintf on Windows.
     20 #if defined(_MSC_VER)
     21 #  define snprintf sprintf_s
     22 #endif
     23 
     24 namespace pp {
     25 
     26 namespace {
     27 
     28 template <> const char* interface_name<PPB_Var_1_2>() {
     29   return PPB_VAR_INTERFACE_1_2;
     30 }
     31 template <> const char* interface_name<PPB_Var_1_1>() {
     32   return PPB_VAR_INTERFACE_1_1;
     33 }
     34 template <> const char* interface_name<PPB_Var_1_0>() {
     35   return PPB_VAR_INTERFACE_1_0;
     36 }
     37 
     38 // Technically you can call AddRef and Release on any Var, but it may involve
     39 // cross-process calls depending on the plugin. This is an optimization so we
     40 // only do refcounting on the necessary objects.
     41 inline bool NeedsRefcounting(const PP_Var& var) {
     42   return var.type > PP_VARTYPE_DOUBLE;
     43 }
     44 
     45 // This helper function uses the latest available version of VarFromUtf8. Note
     46 // that version 1.0 of this method has a different API to later versions.
     47 PP_Var VarFromUtf8Helper(const char* utf8_str, uint32_t len) {
     48   if (has_interface<PPB_Var_1_2>()) {
     49     return get_interface<PPB_Var_1_2>()->VarFromUtf8(utf8_str, len);
     50   } else if (has_interface<PPB_Var_1_1>()) {
     51     return get_interface<PPB_Var_1_1>()->VarFromUtf8(utf8_str, len);
     52   } else if (has_interface<PPB_Var_1_0>()) {
     53     return get_interface<PPB_Var_1_0>()->VarFromUtf8(Module::Get()->pp_module(),
     54                                                      utf8_str,
     55                                                      len);
     56   }
     57   return PP_MakeNull();
     58 }
     59 
     60 // This helper function uses the latest available version of AddRef.
     61 // Returns true on success, false if no appropriate interface was available.
     62 bool AddRefHelper(const PP_Var& var) {
     63   if (has_interface<PPB_Var_1_2>()) {
     64     get_interface<PPB_Var_1_2>()->AddRef(var);
     65     return true;
     66   } else if (has_interface<PPB_Var_1_1>()) {
     67     get_interface<PPB_Var_1_1>()->AddRef(var);
     68     return true;
     69   } else if (has_interface<PPB_Var_1_0>()) {
     70     get_interface<PPB_Var_1_0>()->AddRef(var);
     71     return true;
     72   }
     73   return false;
     74 }
     75 
     76 // This helper function uses the latest available version of Release.
     77 // Returns true on success, false if no appropriate interface was available.
     78 bool ReleaseHelper(const PP_Var& var) {
     79   if (has_interface<PPB_Var_1_2>()) {
     80     get_interface<PPB_Var_1_2>()->Release(var);
     81     return true;
     82   } else if (has_interface<PPB_Var_1_1>()) {
     83     get_interface<PPB_Var_1_1>()->Release(var);
     84     return true;
     85   } else if (has_interface<PPB_Var_1_0>()) {
     86     get_interface<PPB_Var_1_0>()->Release(var);
     87     return true;
     88   }
     89   return false;
     90 }
     91 
     92 }  // namespace
     93 
     94 Var::Var() {
     95   memset(&var_, 0, sizeof(var_));
     96   var_.type = PP_VARTYPE_UNDEFINED;
     97   is_managed_ = true;
     98 }
     99 
    100 Var::Var(Null) {
    101   memset(&var_, 0, sizeof(var_));
    102   var_.type = PP_VARTYPE_NULL;
    103   is_managed_ = true;
    104 }
    105 
    106 Var::Var(bool b) {
    107   var_.type = PP_VARTYPE_BOOL;
    108   var_.padding = 0;
    109   var_.value.as_bool = PP_FromBool(b);
    110   is_managed_ = true;
    111 }
    112 
    113 Var::Var(int32_t i) {
    114   var_.type = PP_VARTYPE_INT32;
    115   var_.padding = 0;
    116   var_.value.as_int = i;
    117   is_managed_ = true;
    118 }
    119 
    120 Var::Var(double d) {
    121   var_.type = PP_VARTYPE_DOUBLE;
    122   var_.padding = 0;
    123   var_.value.as_double = d;
    124   is_managed_ = true;
    125 }
    126 
    127 Var::Var(const char* utf8_str) {
    128   uint32_t len = utf8_str ? static_cast<uint32_t>(strlen(utf8_str)) : 0;
    129   var_ = VarFromUtf8Helper(utf8_str, len);
    130   is_managed_ = true;
    131 }
    132 
    133 Var::Var(const std::string& utf8_str) {
    134   var_ = VarFromUtf8Helper(utf8_str.c_str(),
    135                            static_cast<uint32_t>(utf8_str.size()));
    136   is_managed_ = true;
    137 }
    138 
    139 Var::Var(const pp::Resource& resource) {
    140   if (has_interface<PPB_Var_1_2>()) {
    141     var_ = get_interface<PPB_Var_1_2>()->VarFromResource(
    142         resource.pp_resource());
    143   } else {
    144     PP_NOTREACHED();
    145     return;
    146   }
    147   // Set |is_managed_| to true, so |var_| will be properly released upon
    148   // destruction.
    149   is_managed_ = true;
    150 }
    151 
    152 
    153 Var::Var(const PP_Var& var) {
    154   var_ = var;
    155   is_managed_ = true;
    156   if (NeedsRefcounting(var_)) {
    157     if (!AddRefHelper(var_))
    158       var_.type = PP_VARTYPE_NULL;
    159   }
    160 }
    161 
    162 Var::Var(const Var& other) {
    163   var_ = other.var_;
    164   is_managed_ = true;
    165   if (NeedsRefcounting(var_)) {
    166     if (!AddRefHelper(var_))
    167       var_.type = PP_VARTYPE_NULL;
    168   }
    169 }
    170 
    171 Var::~Var() {
    172   if (NeedsRefcounting(var_) && is_managed_)
    173     ReleaseHelper(var_);
    174 }
    175 
    176 Var& Var::operator=(const Var& other) {
    177   // Early return for self-assignment. Note however, that two distinct vars
    178   // can refer to the same object, so we still need to be careful about the
    179   // refcounting below.
    180   if (this == &other)
    181     return *this;
    182 
    183   // Be careful to keep the ref alive for cases where we're assigning an
    184   // object to itself by addrefing the new one before releasing the old one.
    185   bool old_is_managed = is_managed_;
    186   is_managed_ = true;
    187   if (NeedsRefcounting(other.var_)) {
    188     AddRefHelper(other.var_);
    189   }
    190   if (NeedsRefcounting(var_) && old_is_managed)
    191     ReleaseHelper(var_);
    192 
    193   var_ = other.var_;
    194   return *this;
    195 }
    196 
    197 bool Var::operator==(const Var& other) const {
    198   if (var_.type != other.var_.type)
    199     return false;
    200   switch (var_.type) {
    201     case PP_VARTYPE_UNDEFINED:
    202     case PP_VARTYPE_NULL:
    203       return true;
    204     case PP_VARTYPE_BOOL:
    205       return AsBool() == other.AsBool();
    206     case PP_VARTYPE_INT32:
    207       return AsInt() == other.AsInt();
    208     case PP_VARTYPE_DOUBLE:
    209       return AsDouble() == other.AsDouble();
    210     case PP_VARTYPE_STRING:
    211       if (var_.value.as_id == other.var_.value.as_id)
    212         return true;
    213       return AsString() == other.AsString();
    214     case PP_VARTYPE_OBJECT:
    215     case PP_VARTYPE_ARRAY:
    216     case PP_VARTYPE_ARRAY_BUFFER:
    217     case PP_VARTYPE_DICTIONARY:
    218     case PP_VARTYPE_RESOURCE:
    219     default:  // Objects, arrays, dictionaries, resources.
    220       return var_.value.as_id == other.var_.value.as_id;
    221   }
    222 }
    223 
    224 bool Var::AsBool() const {
    225   if (!is_bool()) {
    226     PP_NOTREACHED();
    227     return false;
    228   }
    229   return PP_ToBool(var_.value.as_bool);
    230 }
    231 
    232 int32_t Var::AsInt() const {
    233   if (is_int())
    234     return var_.value.as_int;
    235   if (is_double())
    236     return static_cast<int>(var_.value.as_double);
    237   PP_NOTREACHED();
    238   return 0;
    239 }
    240 
    241 double Var::AsDouble() const {
    242   if (is_double())
    243     return var_.value.as_double;
    244   if (is_int())
    245     return static_cast<double>(var_.value.as_int);
    246   PP_NOTREACHED();
    247   return 0.0;
    248 }
    249 
    250 std::string Var::AsString() const {
    251   if (!is_string()) {
    252     PP_NOTREACHED();
    253     return std::string();
    254   }
    255 
    256   uint32_t len;
    257   const char* str;
    258   if (has_interface<PPB_Var_1_2>())
    259     str = get_interface<PPB_Var_1_2>()->VarToUtf8(var_, &len);
    260   else if (has_interface<PPB_Var_1_1>())
    261     str = get_interface<PPB_Var_1_1>()->VarToUtf8(var_, &len);
    262   else if (has_interface<PPB_Var_1_0>())
    263     str = get_interface<PPB_Var_1_0>()->VarToUtf8(var_, &len);
    264   else
    265     return std::string();
    266   return std::string(str, len);
    267 }
    268 
    269 pp::Resource Var::AsResource() const {
    270   if (!is_resource()) {
    271     PP_NOTREACHED();
    272     return pp::Resource();
    273   }
    274 
    275   if (has_interface<PPB_Var_1_2>()) {
    276     return pp::Resource(pp::PASS_REF,
    277                         get_interface<PPB_Var_1_2>()->VarToResource(var_));
    278   } else {
    279     return pp::Resource();
    280   }
    281 }
    282 
    283 std::string Var::DebugString() const {
    284   char buf[256];
    285   if (is_undefined()) {
    286     snprintf(buf, sizeof(buf), "Var(UNDEFINED)");
    287   } else if (is_null()) {
    288     snprintf(buf, sizeof(buf), "Var(NULL)");
    289   } else if (is_bool()) {
    290     snprintf(buf, sizeof(buf), AsBool() ? "Var(true)" : "Var(false)");
    291   } else if (is_int()) {
    292     snprintf(buf, sizeof(buf), "Var(%d)", static_cast<int>(AsInt()));
    293   } else if (is_double()) {
    294     snprintf(buf, sizeof(buf), "Var(%f)", AsDouble());
    295   } else if (is_string()) {
    296     char format[] = "Var<'%s'>";
    297     size_t decoration = sizeof(format) - 2;  // The %s is removed.
    298     size_t available = sizeof(buf) - decoration;
    299     std::string str = AsString();
    300     if (str.length() > available) {
    301       str.resize(available - 3);  // Reserve space for ellipsis.
    302       str.append("...");
    303     }
    304     snprintf(buf, sizeof(buf), format, str.c_str());
    305   } else if (is_object()) {
    306     snprintf(buf, sizeof(buf), "Var(OBJECT)");
    307   } else if (is_array()) {
    308     snprintf(buf, sizeof(buf), "Var(ARRAY)");
    309   } else if (is_dictionary()) {
    310     snprintf(buf, sizeof(buf), "Var(DICTIONARY)");
    311   } else if (is_array_buffer()) {
    312     snprintf(buf, sizeof(buf), "Var(ARRAY_BUFFER)");
    313   } else if (is_resource()) {
    314     snprintf(buf, sizeof(buf), "Var(RESOURCE)");
    315   } else {
    316     buf[0] = '\0';
    317   }
    318   return buf;
    319 }
    320 
    321 }  // namespace pp
    322