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