1 // Copyright (c) 2012 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 "base/logging.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "third_party/WebKit/public/web/WebBindings.h" 13 #include "webkit/renderer/cpp_variant.h" 14 15 using blink::WebBindings; 16 17 namespace webkit_glue { 18 19 CppVariant::CppVariant() { 20 type = NPVariantType_Null; 21 } 22 23 // Note that Set() performs a deep copy, which is necessary to safely 24 // call FreeData() on the value in the destructor. 25 CppVariant::CppVariant(const CppVariant& original) { 26 type = NPVariantType_Null; 27 Set(original); 28 } 29 30 // See comment for copy constructor, above. 31 CppVariant& CppVariant::operator=(const CppVariant& original) { 32 if (&original != this) 33 Set(original); 34 return *this; 35 } 36 37 CppVariant::~CppVariant() { 38 FreeData(); 39 } 40 41 void CppVariant::FreeData() { 42 WebBindings::releaseVariantValue(this); 43 } 44 45 bool CppVariant::isEqual(const CppVariant& other) const { 46 if (type != other.type) 47 return false; 48 49 switch (type) { 50 case NPVariantType_Bool: { 51 return (value.boolValue == other.value.boolValue); 52 } 53 case NPVariantType_Int32: { 54 return (value.intValue == other.value.intValue); 55 } 56 case NPVariantType_Double: { 57 return (value.doubleValue == other.value.doubleValue); 58 } 59 case NPVariantType_String: { 60 const NPString *this_value = &value.stringValue; 61 const NPString *other_value = &other.value.stringValue; 62 uint32_t len = this_value->UTF8Length; 63 return (len == other_value->UTF8Length && 64 !strncmp(this_value->UTF8Characters, other_value->UTF8Characters, 65 len)); 66 } 67 case NPVariantType_Null: 68 case NPVariantType_Void: { 69 return true; 70 } 71 case NPVariantType_Object: { 72 NPObject *this_value = value.objectValue; 73 NPObject *other_value = other.value.objectValue; 74 return (this_value->_class == other_value->_class && 75 this_value->referenceCount == other_value->referenceCount); 76 } 77 } 78 return false; 79 } 80 81 void CppVariant::CopyToNPVariant(NPVariant* result) const { 82 result->type = type; 83 switch (type) { 84 case NPVariantType_Bool: 85 result->value.boolValue = value.boolValue; 86 break; 87 case NPVariantType_Int32: 88 result->value.intValue = value.intValue; 89 break; 90 case NPVariantType_Double: 91 result->value.doubleValue = value.doubleValue; 92 break; 93 case NPVariantType_String: 94 WebBindings::initializeVariantWithStringCopy(result, &value.stringValue); 95 break; 96 case NPVariantType_Null: 97 case NPVariantType_Void: 98 // Nothing to set. 99 break; 100 case NPVariantType_Object: 101 result->type = NPVariantType_Object; 102 result->value.objectValue = WebBindings::retainObject(value.objectValue); 103 break; 104 } 105 } 106 107 void CppVariant::Set(const NPVariant& new_value) { 108 FreeData(); 109 switch (new_value.type) { 110 case NPVariantType_Bool: 111 Set(new_value.value.boolValue); 112 break; 113 case NPVariantType_Int32: 114 Set(new_value.value.intValue); 115 break; 116 case NPVariantType_Double: 117 Set(new_value.value.doubleValue); 118 break; 119 case NPVariantType_String: 120 Set(new_value.value.stringValue); 121 break; 122 case NPVariantType_Null: 123 case NPVariantType_Void: 124 type = new_value.type; 125 break; 126 case NPVariantType_Object: 127 Set(new_value.value.objectValue); 128 break; 129 } 130 } 131 132 void CppVariant::SetNull() { 133 FreeData(); 134 type = NPVariantType_Null; 135 } 136 137 void CppVariant::Set(bool new_value) { 138 FreeData(); 139 type = NPVariantType_Bool; 140 value.boolValue = new_value; 141 } 142 143 void CppVariant::Set(int32_t new_value) { 144 FreeData(); 145 type = NPVariantType_Int32; 146 value.intValue = new_value; 147 } 148 149 void CppVariant::Set(double new_value) { 150 FreeData(); 151 type = NPVariantType_Double; 152 value.doubleValue = new_value; 153 } 154 155 // The new_value must be a null-terminated string. 156 void CppVariant::Set(const char* new_value) { 157 FreeData(); 158 type = NPVariantType_String; 159 NPString new_string = {new_value, 160 static_cast<uint32_t>(strlen(new_value))}; 161 WebBindings::initializeVariantWithStringCopy(this, &new_string); 162 } 163 164 void CppVariant::Set(const std::string& new_value) { 165 FreeData(); 166 type = NPVariantType_String; 167 NPString new_string = {new_value.data(), 168 static_cast<uint32_t>(new_value.size())}; 169 WebBindings::initializeVariantWithStringCopy(this, &new_string); 170 } 171 void CppVariant::Set(const NPString& new_value) { 172 FreeData(); 173 type = NPVariantType_String; 174 WebBindings::initializeVariantWithStringCopy(this, &new_value); 175 } 176 177 void CppVariant::Set(NPObject* new_value) { 178 FreeData(); 179 type = NPVariantType_Object; 180 value.objectValue = WebBindings::retainObject(new_value); 181 } 182 183 std::string CppVariant::ToString() const { 184 DCHECK(isString()); 185 return std::string(value.stringValue.UTF8Characters, 186 value.stringValue.UTF8Length); 187 } 188 189 int32_t CppVariant::ToInt32() const { 190 if (isInt32()) { 191 return value.intValue; 192 } else if (isDouble()) { 193 return static_cast<int32_t>(value.doubleValue); 194 } else { 195 NOTREACHED(); 196 return 0; 197 } 198 } 199 200 double CppVariant::ToDouble() const { 201 if (isInt32()) { 202 return static_cast<double>(value.intValue); 203 } else if (isDouble()) { 204 return value.doubleValue; 205 } else { 206 NOTREACHED(); 207 return 0.0; 208 } 209 } 210 211 bool CppVariant::ToBoolean() const { 212 DCHECK(isBool()); 213 return value.boolValue; 214 } 215 216 std::vector<CppVariant> CppVariant::ToVector() const { 217 DCHECK(isObject()); 218 std::vector<CppVariant> vector; 219 NPObject* np_value = value.objectValue; 220 NPIdentifier length_id = WebBindings::getStringIdentifier("length"); 221 222 if (WebBindings::hasProperty(NULL, np_value, length_id)) { 223 CppVariant length_value; 224 if (WebBindings::getProperty(NULL, np_value, length_id, &length_value)) { 225 int length = 0; 226 // The length is a double in some cases. 227 if (NPVARIANT_IS_DOUBLE(length_value)) 228 length = static_cast<int>(NPVARIANT_TO_DOUBLE(length_value)); 229 else if (NPVARIANT_IS_INT32(length_value)) 230 length = NPVARIANT_TO_INT32(length_value); 231 else 232 NOTREACHED(); 233 234 // For sanity, only allow 60000 items. 235 length = std::min(60000, length); 236 for (int i = 0; i < length; ++i) { 237 // Get each of the items. 238 NPIdentifier index = WebBindings::getIntIdentifier(i); 239 if (WebBindings::hasProperty(NULL, np_value, index)) { 240 CppVariant index_value; 241 if (WebBindings::getProperty(NULL, np_value, index, &index_value)) 242 vector.push_back(index_value); 243 } 244 } 245 } 246 } else { 247 NOTREACHED(); 248 } 249 return vector; 250 } 251 252 bool CppVariant::Invoke(const std::string& method, const CppVariant* args, 253 uint32 arg_count, CppVariant& result) const { 254 DCHECK(isObject()); 255 NPIdentifier method_name = WebBindings::getStringIdentifier(method.c_str()); 256 NPObject* np_object = value.objectValue; 257 if (WebBindings::hasMethod(NULL, np_object, method_name)) { 258 NPVariant r; 259 bool status = 260 WebBindings::invoke(NULL, np_object, method_name, args, arg_count, &r); 261 result.Set(r); 262 return status; 263 } else { 264 return false; 265 } 266 } 267 268 } // namespace webkit_glue 269