Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "CppVariant.h"
     33 
     34 #include "WebBindings.h"
     35 #include <limits>
     36 #include <wtf/Assertions.h>
     37 #include <wtf/StringExtras.h>
     38 
     39 using namespace WebKit;
     40 using namespace std;
     41 
     42 CppVariant::CppVariant()
     43 {
     44     type = NPVariantType_Null;
     45 }
     46 
     47 // Note that Set() performs a deep copy, which is necessary to safely
     48 // call FreeData() on the value in the destructor.
     49 CppVariant::CppVariant(const CppVariant& original)
     50 {
     51     type = NPVariantType_Null;
     52     set(original);
     53 }
     54 
     55 // See comment for copy constructor, above.
     56 CppVariant& CppVariant::operator=(const CppVariant& original)
     57 {
     58     if (&original != this)
     59         set(original);
     60     return *this;
     61 }
     62 
     63 CppVariant::~CppVariant()
     64 {
     65     freeData();
     66 }
     67 
     68 void CppVariant::freeData()
     69 {
     70     WebBindings::releaseVariantValue(this);
     71 }
     72 
     73 bool CppVariant::isEqual(const CppVariant& other) const
     74 {
     75     if (type != other.type)
     76         return false;
     77 
     78     switch (type) {
     79     case NPVariantType_Bool:
     80         return (value.boolValue == other.value.boolValue);
     81     case NPVariantType_Int32:
     82         return (value.intValue == other.value.intValue);
     83     case NPVariantType_Double:
     84         return (value.doubleValue == other.value.doubleValue);
     85     case NPVariantType_String: {
     86         const NPString *this_value = &value.stringValue;
     87         const NPString *other_value = &other.value.stringValue;
     88         uint32_t len = this_value->UTF8Length;
     89         return len == other_value->UTF8Length
     90             && !strncmp(this_value->UTF8Characters,
     91                         other_value->UTF8Characters, len);
     92     }
     93     case NPVariantType_Null:
     94     case NPVariantType_Void:
     95         return true;
     96     case NPVariantType_Object: {
     97         NPObject* thisValue = value.objectValue;
     98         NPObject* otherValue = other.value.objectValue;
     99         return thisValue->_class == otherValue->_class
    100             && thisValue->referenceCount == otherValue->referenceCount;
    101     }
    102     }
    103     return false;
    104 }
    105 
    106 void CppVariant::copyToNPVariant(NPVariant* result) const
    107 {
    108     result->type = type;
    109     switch (type) {
    110     case NPVariantType_Bool:
    111         result->value.boolValue = value.boolValue;
    112         break;
    113     case NPVariantType_Int32:
    114         result->value.intValue = value.intValue;
    115         break;
    116     case NPVariantType_Double:
    117         result->value.doubleValue = value.doubleValue;
    118         break;
    119     case NPVariantType_String:
    120         WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
    121         break;
    122     case NPVariantType_Null:
    123     case NPVariantType_Void:
    124         // Nothing to set.
    125         break;
    126     case NPVariantType_Object:
    127         result->type = NPVariantType_Object;
    128         result->value.objectValue = WebBindings::retainObject(value.objectValue);
    129         break;
    130     }
    131 }
    132 
    133 void CppVariant::set(const NPVariant& newValue)
    134 {
    135     freeData();
    136     switch (newValue.type) {
    137     case NPVariantType_Bool:
    138         set(newValue.value.boolValue);
    139         break;
    140     case NPVariantType_Int32:
    141         set(newValue.value.intValue);
    142         break;
    143     case NPVariantType_Double:
    144         set(newValue.value.doubleValue);
    145         break;
    146     case NPVariantType_String:
    147         set(newValue.value.stringValue);
    148         break;
    149     case NPVariantType_Null:
    150     case NPVariantType_Void:
    151         type = newValue.type;
    152         break;
    153     case NPVariantType_Object:
    154         set(newValue.value.objectValue);
    155         break;
    156     }
    157 }
    158 
    159 void CppVariant::setNull()
    160 {
    161     freeData();
    162     type = NPVariantType_Null;
    163 }
    164 
    165 void CppVariant::set(bool newValue)
    166 {
    167     freeData();
    168     type = NPVariantType_Bool;
    169     value.boolValue = newValue;
    170 }
    171 
    172 void CppVariant::set(int32_t newValue)
    173 {
    174     freeData();
    175     type = NPVariantType_Int32;
    176     value.intValue = newValue;
    177 }
    178 
    179 void CppVariant::set(double newValue)
    180 {
    181     freeData();
    182     type = NPVariantType_Double;
    183     value.doubleValue = newValue;
    184 }
    185 
    186 // The newValue must be a null-terminated string.
    187 void CppVariant::set(const char* newValue)
    188 {
    189     freeData();
    190     type = NPVariantType_String;
    191     NPString newString = {newValue,
    192                           static_cast<uint32_t>(strlen(newValue))};
    193     WebBindings::initializeVariantWithStringCopy(this, &newString);
    194 }
    195 
    196 void CppVariant::set(const string& newValue)
    197 {
    198     freeData();
    199     type = NPVariantType_String;
    200     NPString newString = {newValue.data(),
    201                           static_cast<uint32_t>(newValue.size())};
    202     WebBindings::initializeVariantWithStringCopy(this, &newString);
    203 }
    204 
    205 void CppVariant::set(const NPString& newValue)
    206 {
    207     freeData();
    208     type = NPVariantType_String;
    209     WebBindings::initializeVariantWithStringCopy(this, &newValue);
    210 }
    211 
    212 void CppVariant::set(NPObject* newValue)
    213 {
    214     freeData();
    215     type = NPVariantType_Object;
    216     value.objectValue = WebBindings::retainObject(newValue);
    217 }
    218 
    219 string CppVariant::toString() const
    220 {
    221     ASSERT(isString());
    222     return string(value.stringValue.UTF8Characters,
    223                   value.stringValue.UTF8Length);
    224 }
    225 
    226 int32_t CppVariant::toInt32() const
    227 {
    228     if (isInt32())
    229         return value.intValue;
    230     if (isDouble())
    231         return static_cast<int32_t>(value.doubleValue);
    232     ASSERT_NOT_REACHED();
    233     return 0;
    234 }
    235 
    236 double CppVariant::toDouble() const
    237 {
    238     if (isInt32())
    239         return static_cast<double>(value.intValue);
    240     if (isDouble())
    241         return value.doubleValue;
    242     ASSERT_NOT_REACHED();
    243     return 0;
    244 }
    245 
    246 bool CppVariant::toBoolean() const
    247 {
    248     ASSERT(isBool());
    249     return value.boolValue;
    250 }
    251 
    252 Vector<string> CppVariant::toStringVector() const
    253 {
    254 
    255     ASSERT(isObject());
    256     Vector<string> stringVector;
    257     NPObject* npValue = value.objectValue;
    258     NPIdentifier lengthId = WebBindings::getStringIdentifier("length");
    259 
    260     if (!WebBindings::hasProperty(0, npValue, lengthId))
    261         return stringVector;
    262 
    263     NPVariant lengthValue;
    264     if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue))
    265         return stringVector;
    266 
    267     int length = 0;
    268     // The length is a double in some cases.
    269     if (NPVARIANT_IS_DOUBLE(lengthValue))
    270         length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue));
    271     else if (NPVARIANT_IS_INT32(lengthValue))
    272         length = NPVARIANT_TO_INT32(lengthValue);
    273     WebBindings::releaseVariantValue(&lengthValue);
    274 
    275     // For sanity, only allow 100 items.
    276     length = min(100, length);
    277     for (int i = 0; i < length; ++i) {
    278         // Get each of the items.
    279         char indexInChar[20]; // Enough size to store 32-bit integer
    280         snprintf(indexInChar, 20, "%d", i);
    281         string index(indexInChar);
    282         NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str());
    283         if (!WebBindings::hasProperty(0, npValue, indexId))
    284             continue;
    285         NPVariant indexValue;
    286         if (!WebBindings::getProperty(0, npValue, indexId, &indexValue))
    287             continue;
    288         if (NPVARIANT_IS_STRING(indexValue)) {
    289             string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters,
    290                         NPVARIANT_TO_STRING(indexValue).UTF8Length);
    291             stringVector.append(item);
    292         }
    293         WebBindings::releaseVariantValue(&indexValue);
    294     }
    295     return stringVector;
    296 }
    297 
    298 bool CppVariant::invoke(const string& method, const CppVariant* arguments,
    299                         uint32_t argumentCount, CppVariant& result) const
    300 {
    301     ASSERT(isObject());
    302     NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str());
    303     NPObject* npObject = value.objectValue;
    304     if (!WebBindings::hasMethod(0, npObject, methodName))
    305         return false;
    306     NPVariant r;
    307     bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r);
    308     result.set(r);
    309     return status;
    310 }
    311