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