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
CppVariant()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.
CppVariant(const CppVariant & original)25 CppVariant::CppVariant(const CppVariant& original) {
26 type = NPVariantType_Null;
27 Set(original);
28 }
29
30 // See comment for copy constructor, above.
operator =(const CppVariant & original)31 CppVariant& CppVariant::operator=(const CppVariant& original) {
32 if (&original != this)
33 Set(original);
34 return *this;
35 }
36
~CppVariant()37 CppVariant::~CppVariant() {
38 FreeData();
39 }
40
FreeData()41 void CppVariant::FreeData() {
42 WebBindings::releaseVariantValue(this);
43 }
44
isEqual(const CppVariant & other) const45 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
CopyToNPVariant(NPVariant * result) const81 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
Set(const NPVariant & new_value)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
SetNull()132 void CppVariant::SetNull() {
133 FreeData();
134 type = NPVariantType_Null;
135 }
136
Set(bool new_value)137 void CppVariant::Set(bool new_value) {
138 FreeData();
139 type = NPVariantType_Bool;
140 value.boolValue = new_value;
141 }
142
Set(int32_t new_value)143 void CppVariant::Set(int32_t new_value) {
144 FreeData();
145 type = NPVariantType_Int32;
146 value.intValue = new_value;
147 }
148
Set(double new_value)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.
Set(const char * new_value)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
Set(const std::string & new_value)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 }
Set(const NPString & new_value)171 void CppVariant::Set(const NPString& new_value) {
172 FreeData();
173 type = NPVariantType_String;
174 WebBindings::initializeVariantWithStringCopy(this, &new_value);
175 }
176
Set(NPObject * new_value)177 void CppVariant::Set(NPObject* new_value) {
178 FreeData();
179 type = NPVariantType_Object;
180 value.objectValue = WebBindings::retainObject(new_value);
181 }
182
ToString() const183 std::string CppVariant::ToString() const {
184 DCHECK(isString());
185 return std::string(value.stringValue.UTF8Characters,
186 value.stringValue.UTF8Length);
187 }
188
ToInt32() const189 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
ToDouble() const200 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
ToBoolean() const211 bool CppVariant::ToBoolean() const {
212 DCHECK(isBool());
213 return value.boolValue;
214 }
215
ToVector() const216 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
Invoke(const std::string & method,const CppVariant * args,uint32 arg_count,CppVariant & result) const252 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