Home | History | Annotate | Download | only in runner
      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 "CppVariant.h"
     32 
     33 #include "TestCommon.h"
     34 #include <limits>
     35 
     36 using namespace blink;
     37 using namespace std;
     38 
     39 namespace WebTestRunner {
     40 
     41 CppVariant::CppVariant()
     42 {
     43     type = NPVariantType_Null;
     44 }
     45 
     46 // Note that Set() performs a deep copy, which is necessary to safely
     47 // call FreeData() on the value in the destructor.
     48 CppVariant::CppVariant(const CppVariant& original)
     49 {
     50     type = NPVariantType_Null;
     51     set(original);
     52 }
     53 
     54 // See comment for copy constructor, above.
     55 CppVariant& CppVariant::operator=(const CppVariant& original)
     56 {
     57     if (&original != this)
     58         set(original);
     59     return *this;
     60 }
     61 
     62 CppVariant::~CppVariant()
     63 {
     64     freeData();
     65 }
     66 
     67 void CppVariant::freeData()
     68 {
     69     WebBindings::releaseVariantValue(this);
     70 }
     71 
     72 bool CppVariant::isEqual(const CppVariant& other) const
     73 {
     74     if (type != other.type)
     75         return false;
     76 
     77     switch (type) {
     78     case NPVariantType_Bool:
     79         return (value.boolValue == other.value.boolValue);
     80     case NPVariantType_Int32:
     81         return (value.intValue == other.value.intValue);
     82     case NPVariantType_Double:
     83         return (value.doubleValue == other.value.doubleValue);
     84     case NPVariantType_String: {
     85         const NPString *this_value = &value.stringValue;
     86         const NPString *other_value = &other.value.stringValue;
     87         uint32_t len = this_value->UTF8Length;
     88         return len == other_value->UTF8Length
     89             && !strncmp(this_value->UTF8Characters,
     90                         other_value->UTF8Characters, len);
     91     }
     92     case NPVariantType_Null:
     93     case NPVariantType_Void:
     94         return true;
     95     case NPVariantType_Object: {
     96         NPObject* thisValue = value.objectValue;
     97         NPObject* otherValue = other.value.objectValue;
     98         return thisValue->_class == otherValue->_class
     99             && thisValue->referenceCount == otherValue->referenceCount;
    100     }
    101     }
    102     return false;
    103 }
    104 
    105 void CppVariant::copyToNPVariant(NPVariant* result) const
    106 {
    107     result->type = type;
    108     switch (type) {
    109     case NPVariantType_Bool:
    110         result->value.boolValue = value.boolValue;
    111         break;
    112     case NPVariantType_Int32:
    113         result->value.intValue = value.intValue;
    114         break;
    115     case NPVariantType_Double:
    116         result->value.doubleValue = value.doubleValue;
    117         break;
    118     case NPVariantType_String:
    119         WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
    120         break;
    121     case NPVariantType_Null:
    122     case NPVariantType_Void:
    123         // Nothing to set.
    124         break;
    125     case NPVariantType_Object:
    126         result->type = NPVariantType_Object;
    127         result->value.objectValue = WebBindings::retainObject(value.objectValue);
    128         break;
    129     }
    130 }
    131 
    132 void CppVariant::set(const NPVariant& newValue)
    133 {
    134     freeData();
    135     switch (newValue.type) {
    136     case NPVariantType_Bool:
    137         set(newValue.value.boolValue);
    138         break;
    139     case NPVariantType_Int32:
    140         set(newValue.value.intValue);
    141         break;
    142     case NPVariantType_Double:
    143         set(newValue.value.doubleValue);
    144         break;
    145     case NPVariantType_String:
    146         set(newValue.value.stringValue);
    147         break;
    148     case NPVariantType_Null:
    149     case NPVariantType_Void:
    150         type = newValue.type;
    151         break;
    152     case NPVariantType_Object:
    153         set(newValue.value.objectValue);
    154         break;
    155     }
    156 }
    157 
    158 void CppVariant::setNull()
    159 {
    160     freeData();
    161     type = NPVariantType_Null;
    162 }
    163 
    164 void CppVariant::set(bool newValue)
    165 {
    166     freeData();
    167     type = NPVariantType_Bool;
    168     value.boolValue = newValue;
    169 }
    170 
    171 void CppVariant::set(int32_t newValue)
    172 {
    173     freeData();
    174     type = NPVariantType_Int32;
    175     value.intValue = newValue;
    176 }
    177 
    178 void CppVariant::set(double newValue)
    179 {
    180     freeData();
    181     type = NPVariantType_Double;
    182     value.doubleValue = newValue;
    183 }
    184 
    185 // The newValue must be a null-terminated string.
    186 void CppVariant::set(const char* newValue)
    187 {
    188     freeData();
    189     type = NPVariantType_String;
    190     NPString newString = {newValue,
    191                           static_cast<uint32_t>(strlen(newValue))};
    192     WebBindings::initializeVariantWithStringCopy(this, &newString);
    193 }
    194 
    195 void CppVariant::set(const string& newValue)
    196 {
    197     freeData();
    198     type = NPVariantType_String;
    199     NPString newString = {newValue.data(),
    200                           static_cast<uint32_t>(newValue.size())};
    201     WebBindings::initializeVariantWithStringCopy(this, &newString);
    202 }
    203 
    204 void CppVariant::set(const NPString& newValue)
    205 {
    206     freeData();
    207     type = NPVariantType_String;
    208     WebBindings::initializeVariantWithStringCopy(this, &newValue);
    209 }
    210 
    211 void CppVariant::set(NPObject* newValue)
    212 {
    213     freeData();
    214     type = NPVariantType_Object;
    215     value.objectValue = WebBindings::retainObject(newValue);
    216 }
    217 
    218 string CppVariant::toString() const
    219 {
    220     BLINK_ASSERT(isString());
    221     return string(value.stringValue.UTF8Characters,
    222                   value.stringValue.UTF8Length);
    223 }
    224 
    225 int32_t CppVariant::toInt32() const
    226 {
    227     if (isInt32())
    228         return value.intValue;
    229     if (isDouble())
    230         return static_cast<int32_t>(value.doubleValue);
    231     BLINK_ASSERT_NOT_REACHED();
    232     return 0;
    233 }
    234 
    235 double CppVariant::toDouble() const
    236 {
    237     if (isInt32())
    238         return static_cast<double>(value.intValue);
    239     if (isDouble())
    240         return value.doubleValue;
    241     BLINK_ASSERT_NOT_REACHED();
    242     return 0;
    243 }
    244 
    245 bool CppVariant::toBoolean() const
    246 {
    247     BLINK_ASSERT(isBool());
    248     return value.boolValue;
    249 }
    250 
    251 vector<string> CppVariant::toStringVector() const
    252 {
    253 
    254     BLINK_ASSERT(isObject());
    255     vector<string> stringVector;
    256     NPObject* npValue = value.objectValue;
    257     NPIdentifier lengthId = WebBindings::getStringIdentifier("length");
    258 
    259     if (!WebBindings::hasProperty(0, npValue, lengthId))
    260         return stringVector;
    261 
    262     NPVariant lengthValue;
    263     if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue))
    264         return stringVector;
    265 
    266     int length = 0;
    267     // The length is a double in some cases.
    268     if (NPVARIANT_IS_DOUBLE(lengthValue))
    269         length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue));
    270     else if (NPVARIANT_IS_INT32(lengthValue))
    271         length = NPVARIANT_TO_INT32(lengthValue);
    272     WebBindings::releaseVariantValue(&lengthValue);
    273 
    274     // For sanity, only allow 100 items.
    275     length = min(100, length);
    276     for (int i = 0; i < length; ++i) {
    277         // Get each of the items.
    278         char indexInChar[20]; // Enough size to store 32-bit integer
    279         snprintf(indexInChar, 20, "%d", i);
    280         string index(indexInChar);
    281         NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str());
    282         if (!WebBindings::hasProperty(0, npValue, indexId))
    283             continue;
    284         NPVariant indexValue;
    285         if (!WebBindings::getProperty(0, npValue, indexId, &indexValue))
    286             continue;
    287         if (NPVARIANT_IS_STRING(indexValue)) {
    288             string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters,
    289                         NPVARIANT_TO_STRING(indexValue).UTF8Length);
    290             stringVector.push_back(item);
    291         }
    292         WebBindings::releaseVariantValue(&indexValue);
    293     }
    294     return stringVector;
    295 }
    296 
    297 bool CppVariant::invoke(const string& method, const CppVariant* arguments,
    298                         uint32_t argumentCount, CppVariant& result) const
    299 {
    300     BLINK_ASSERT(isObject());
    301     NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str());
    302     NPObject* npObject = value.objectValue;
    303     if (!WebBindings::hasMethod(0, npObject, methodName))
    304         return false;
    305     NPVariant r;
    306     bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r);
    307     result.set(r);
    308     return status;
    309 }
    310 
    311 bool CppVariant::invokeDefault(const CppVariant* arguments, uint32_t argumentCount,
    312                                CppVariant& result) const
    313 {
    314     BLINK_ASSERT(isObject());
    315     NPObject* npObject = value.objectValue;
    316     NPVariant r;
    317     bool status = WebBindings::invokeDefault(0, npObject, arguments, argumentCount, &r);
    318     result.set(r);
    319     return status;
    320 }
    321 
    322 }
    323