Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 // This file contains definitions for CppVariant.
      6 
      7 #include <limits>
      8 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
      9 #include "webkit/glue/cpp_variant.h"
     10 #include "base/logging.h"
     11 #include "base/string_util.h"
     12 #include "base/stringprintf.h"
     13 #include "base/utf_string_conversions.h"
     14 
     15 using WebKit::WebBindings;
     16 
     17 CppVariant::CppVariant() {
     18   type = NPVariantType_Null;
     19 }
     20 
     21 // Note that Set() performs a deep copy, which is necessary to safely
     22 // call FreeData() on the value in the destructor.
     23 CppVariant::CppVariant(const CppVariant& original) {
     24   type = NPVariantType_Null;
     25   Set(original);
     26 }
     27 
     28 // See comment for copy constructor, above.
     29 CppVariant& CppVariant::operator=(const CppVariant& original) {
     30   if (&original != this)
     31     Set(original);
     32   return *this;
     33 }
     34 
     35 CppVariant::~CppVariant() {
     36   FreeData();
     37 }
     38 
     39 void CppVariant::FreeData() {
     40   WebBindings::releaseVariantValue(this);
     41 }
     42 
     43 bool CppVariant::isEqual(const CppVariant& other) const {
     44   if (type != other.type)
     45     return false;
     46 
     47   switch (type) {
     48     case NPVariantType_Bool: {
     49       return (value.boolValue == other.value.boolValue);
     50     }
     51     case NPVariantType_Int32: {
     52       return (value.intValue == other.value.intValue);
     53     }
     54     case NPVariantType_Double: {
     55       return (value.doubleValue == other.value.doubleValue);
     56     }
     57     case NPVariantType_String: {
     58       const NPString *this_value = &value.stringValue;
     59       const NPString *other_value = &other.value.stringValue;
     60       uint32_t len = this_value->UTF8Length;
     61       return (len == other_value->UTF8Length &&
     62               !strncmp(this_value->UTF8Characters, other_value->UTF8Characters,
     63                        len));
     64     }
     65     case NPVariantType_Null:
     66     case NPVariantType_Void: {
     67       return true;
     68     }
     69     case NPVariantType_Object: {
     70       NPObject *this_value = value.objectValue;
     71       NPObject *other_value = other.value.objectValue;
     72       return (this_value->_class == other_value->_class &&
     73               this_value->referenceCount == other_value->referenceCount);
     74     }
     75   }
     76   return false;
     77 }
     78 
     79 void CppVariant::CopyToNPVariant(NPVariant* result) const {
     80   result->type = type;
     81   switch (type) {
     82     case NPVariantType_Bool:
     83       result->value.boolValue = value.boolValue;
     84       break;
     85     case NPVariantType_Int32:
     86       result->value.intValue = value.intValue;
     87       break;
     88     case NPVariantType_Double:
     89       result->value.doubleValue = value.doubleValue;
     90       break;
     91     case NPVariantType_String:
     92       WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
     93       break;
     94     case NPVariantType_Null:
     95     case NPVariantType_Void:
     96       // Nothing to set.
     97       break;
     98     case NPVariantType_Object:
     99       result->type = NPVariantType_Object;
    100       result->value.objectValue = WebBindings::retainObject(value.objectValue);
    101       break;
    102   }
    103 }
    104 
    105 void CppVariant::Set(const NPVariant& new_value) {
    106   FreeData();
    107   switch (new_value.type) {
    108     case NPVariantType_Bool:
    109       Set(new_value.value.boolValue);
    110       break;
    111     case NPVariantType_Int32:
    112       Set(new_value.value.intValue);
    113       break;
    114     case NPVariantType_Double:
    115       Set(new_value.value.doubleValue);
    116       break;
    117     case NPVariantType_String:
    118       Set(new_value.value.stringValue);
    119       break;
    120     case NPVariantType_Null:
    121     case NPVariantType_Void:
    122       type = new_value.type;
    123       break;
    124     case NPVariantType_Object:
    125       Set(new_value.value.objectValue);
    126       break;
    127   }
    128 }
    129 
    130 void CppVariant::SetNull() {
    131   FreeData();
    132   type = NPVariantType_Null;
    133 }
    134 
    135 void CppVariant::Set(bool new_value) {
    136   FreeData();
    137   type = NPVariantType_Bool;
    138   value.boolValue = new_value;
    139 }
    140 
    141 void CppVariant::Set(int32_t new_value) {
    142   FreeData();
    143   type = NPVariantType_Int32;
    144   value.intValue = new_value;
    145 }
    146 
    147 void CppVariant::Set(double new_value) {
    148   FreeData();
    149   type = NPVariantType_Double;
    150   value.doubleValue = new_value;
    151 }
    152 
    153 // The new_value must be a null-terminated string.
    154 void CppVariant::Set(const char* new_value) {
    155   FreeData();
    156   type = NPVariantType_String;
    157   NPString new_string = {new_value,
    158                          static_cast<uint32_t>(strlen(new_value))};
    159   WebBindings::initializeVariantWithStringCopy(this, &new_string);
    160 }
    161 
    162 void CppVariant::Set(const std::string& new_value) {
    163   FreeData();
    164   type = NPVariantType_String;
    165   NPString new_string = {new_value.data(),
    166                          static_cast<uint32_t>(new_value.size())};
    167   WebBindings::initializeVariantWithStringCopy(this, &new_string);
    168 }
    169 void CppVariant::Set(const NPString& new_value) {
    170   FreeData();
    171   type = NPVariantType_String;
    172   WebBindings::initializeVariantWithStringCopy(this, &new_value);
    173 }
    174 
    175 void CppVariant::Set(NPObject* new_value) {
    176   FreeData();
    177   type = NPVariantType_Object;
    178   value.objectValue = WebBindings::retainObject(new_value);
    179 }
    180 
    181 std::string CppVariant::ToString() const {
    182   DCHECK(isString());
    183   return std::string(value.stringValue.UTF8Characters,
    184                      value.stringValue.UTF8Length);
    185 }
    186 
    187 int32_t CppVariant::ToInt32() const {
    188   if (isInt32()) {
    189     return value.intValue;
    190   } else if (isDouble()) {
    191     return static_cast<int32_t>(value.doubleValue);
    192   } else {
    193     NOTREACHED();
    194     return 0;
    195   }
    196 }
    197 
    198 double CppVariant::ToDouble() const {
    199   if (isInt32()) {
    200     return static_cast<double>(value.intValue);
    201   } else if (isDouble()) {
    202     return value.doubleValue;
    203   } else {
    204     NOTREACHED();
    205     return 0.0;
    206   }
    207 }
    208 
    209 bool CppVariant::ToBoolean() const {
    210   DCHECK(isBool());
    211   return value.boolValue;
    212 }
    213 
    214 std::vector<CppVariant> CppVariant::ToVector() const {
    215   DCHECK(isObject());
    216   std::vector<CppVariant> vector;
    217   NPObject* np_value = value.objectValue;
    218   NPIdentifier length_id = WebBindings::getStringIdentifier("length");
    219 
    220   if (WebBindings::hasProperty(NULL, np_value, length_id)) {
    221     CppVariant length_value;
    222     if (WebBindings::getProperty(NULL, np_value, length_id, &length_value)) {
    223       int length = 0;
    224       // The length is a double in some cases.
    225       if (NPVARIANT_IS_DOUBLE(length_value))
    226         length = static_cast<int>(NPVARIANT_TO_DOUBLE(length_value));
    227       else if (NPVARIANT_IS_INT32(length_value))
    228         length = NPVARIANT_TO_INT32(length_value);
    229       else
    230         NOTREACHED();
    231 
    232       // For sanity, only allow 60000 items.
    233       length = std::min(60000, length);
    234       for (int i = 0; i < length; ++i) {
    235         // Get each of the items.
    236         NPIdentifier index = WebBindings::getIntIdentifier(i);
    237         if (WebBindings::hasProperty(NULL, np_value, index)) {
    238           CppVariant index_value;
    239           if (WebBindings::getProperty(NULL, np_value, index, &index_value))
    240             vector.push_back(index_value);
    241         }
    242       }
    243     }
    244   } else {
    245     NOTREACHED();
    246   }
    247   return vector;
    248 }
    249 
    250 bool CppVariant::Invoke(const std::string& method, const CppVariant* args,
    251                         uint32 arg_count, CppVariant& result) const {
    252   DCHECK(isObject());
    253   NPIdentifier method_name = WebBindings::getStringIdentifier(method.c_str());
    254   NPObject* np_object = value.objectValue;
    255   if (WebBindings::hasMethod(NULL, np_object, method_name)) {
    256     NPVariant r;
    257     bool status = WebBindings::invoke(NULL, np_object, method_name, args, arg_count, &r);
    258     result.Set(r);
    259     return status;
    260   } else {
    261     return false;
    262   }
    263 }
    264