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 "public/web/WebBindings.h" 35 #include <limits> 36 37 using namespace WebKit; 38 using namespace std; 39 40 namespace WebTestRunner { 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 WEBKIT_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 WEBKIT_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 WEBKIT_ASSERT_NOT_REACHED(); 243 return 0; 244 } 245 246 bool CppVariant::toBoolean() const 247 { 248 WEBKIT_ASSERT(isBool()); 249 return value.boolValue; 250 } 251 252 vector<string> CppVariant::toStringVector() const 253 { 254 255 WEBKIT_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.push_back(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 WEBKIT_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 312 bool CppVariant::invokeDefault(const CppVariant* arguments, uint32_t argumentCount, 313 CppVariant& result) const 314 { 315 WEBKIT_ASSERT(isObject()); 316 NPObject* npObject = value.objectValue; 317 NPVariant r; 318 bool status = WebBindings::invokeDefault(0, npObject, arguments, argumentCount, &r); 319 result.set(r); 320 return status; 321 } 322 323 } 324