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 "config.h"
32 #include "CppVariant.h"
33
34 #include "WebBindings.h"
35 #include <limits>
36 #include <wtf/Assertions.h>
37 #include <wtf/StringExtras.h>
38
39 using namespace WebKit;
40 using namespace std;
41
CppVariant()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.
CppVariant(const CppVariant & original)49 CppVariant::CppVariant(const CppVariant& original)
50 {
51 type = NPVariantType_Null;
52 set(original);
53 }
54
55 // See comment for copy constructor, above.
operator =(const CppVariant & original)56 CppVariant& CppVariant::operator=(const CppVariant& original)
57 {
58 if (&original != this)
59 set(original);
60 return *this;
61 }
62
~CppVariant()63 CppVariant::~CppVariant()
64 {
65 freeData();
66 }
67
freeData()68 void CppVariant::freeData()
69 {
70 WebBindings::releaseVariantValue(this);
71 }
72
isEqual(const CppVariant & other) const73 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
copyToNPVariant(NPVariant * result) const106 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
set(const NPVariant & newValue)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
setNull()159 void CppVariant::setNull()
160 {
161 freeData();
162 type = NPVariantType_Null;
163 }
164
set(bool newValue)165 void CppVariant::set(bool newValue)
166 {
167 freeData();
168 type = NPVariantType_Bool;
169 value.boolValue = newValue;
170 }
171
set(int32_t newValue)172 void CppVariant::set(int32_t newValue)
173 {
174 freeData();
175 type = NPVariantType_Int32;
176 value.intValue = newValue;
177 }
178
set(double newValue)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.
set(const char * newValue)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
set(const string & newValue)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
set(const NPString & newValue)205 void CppVariant::set(const NPString& newValue)
206 {
207 freeData();
208 type = NPVariantType_String;
209 WebBindings::initializeVariantWithStringCopy(this, &newValue);
210 }
211
set(NPObject * newValue)212 void CppVariant::set(NPObject* newValue)
213 {
214 freeData();
215 type = NPVariantType_Object;
216 value.objectValue = WebBindings::retainObject(newValue);
217 }
218
toString() const219 string CppVariant::toString() const
220 {
221 ASSERT(isString());
222 return string(value.stringValue.UTF8Characters,
223 value.stringValue.UTF8Length);
224 }
225
toInt32() const226 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 ASSERT_NOT_REACHED();
233 return 0;
234 }
235
toDouble() const236 double CppVariant::toDouble() const
237 {
238 if (isInt32())
239 return static_cast<double>(value.intValue);
240 if (isDouble())
241 return value.doubleValue;
242 ASSERT_NOT_REACHED();
243 return 0;
244 }
245
toBoolean() const246 bool CppVariant::toBoolean() const
247 {
248 ASSERT(isBool());
249 return value.boolValue;
250 }
251
toStringVector() const252 Vector<string> CppVariant::toStringVector() const
253 {
254
255 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.append(item);
292 }
293 WebBindings::releaseVariantValue(&indexValue);
294 }
295 return stringVector;
296 }
297
invoke(const string & method,const CppVariant * arguments,uint32_t argumentCount,CppVariant & result) const298 bool CppVariant::invoke(const string& method, const CppVariant* arguments,
299 uint32_t argumentCount, CppVariant& result) const
300 {
301 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