• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CppVariant()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.
CppVariant(const CppVariant & original)23 CppVariant::CppVariant(const CppVariant& original) {
24   type = NPVariantType_Null;
25   Set(original);
26 }
27 
28 // See comment for copy constructor, above.
operator =(const CppVariant & original)29 CppVariant& CppVariant::operator=(const CppVariant& original) {
30   if (&original != this)
31     Set(original);
32   return *this;
33 }
34 
~CppVariant()35 CppVariant::~CppVariant() {
36   FreeData();
37 }
38 
FreeData()39 void CppVariant::FreeData() {
40   WebBindings::releaseVariantValue(this);
41 }
42 
isEqual(const CppVariant & other) const43 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 
CopyToNPVariant(NPVariant * result) const79 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 
Set(const NPVariant & new_value)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 
SetNull()130 void CppVariant::SetNull() {
131   FreeData();
132   type = NPVariantType_Null;
133 }
134 
Set(bool new_value)135 void CppVariant::Set(bool new_value) {
136   FreeData();
137   type = NPVariantType_Bool;
138   value.boolValue = new_value;
139 }
140 
Set(int32_t new_value)141 void CppVariant::Set(int32_t new_value) {
142   FreeData();
143   type = NPVariantType_Int32;
144   value.intValue = new_value;
145 }
146 
Set(double new_value)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.
Set(const char * new_value)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 
Set(const std::string & new_value)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 }
Set(const NPString & new_value)169 void CppVariant::Set(const NPString& new_value) {
170   FreeData();
171   type = NPVariantType_String;
172   WebBindings::initializeVariantWithStringCopy(this, &new_value);
173 }
174 
Set(NPObject * new_value)175 void CppVariant::Set(NPObject* new_value) {
176   FreeData();
177   type = NPVariantType_Object;
178   value.objectValue = WebBindings::retainObject(new_value);
179 }
180 
ToString() const181 std::string CppVariant::ToString() const {
182   DCHECK(isString());
183   return std::string(value.stringValue.UTF8Characters,
184                      value.stringValue.UTF8Length);
185 }
186 
ToInt32() const187 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 
ToDouble() const198 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 
ToBoolean() const209 bool CppVariant::ToBoolean() const {
210   DCHECK(isBool());
211   return value.boolValue;
212 }
213 
ToVector() const214 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 
Invoke(const std::string & method,const CppVariant * args,uint32 arg_count,CppVariant & result) const250 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