[BlackBerry] JavaScriptVariant can crash when operator= is called with itself
[WebKit-https.git] / Source / WebKit / blackberry / Api / JavaScriptVariant.cpp
1 /*
2  * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "JavaScriptVariant.h"
21
22 #include "JavaScriptVariant_p.h"
23 #include "WebPage.h"
24 #include <JSStringRef.h>
25 #include <JSValueRef.h>
26 #include <stdlib.h>
27 #include <wtf/Vector.h>
28
29 namespace BlackBerry {
30 namespace WebKit {
31
32 JavaScriptVariant JSValueRefToBlackBerryJavaScriptVariant(const JSGlobalContextRef& ctx, const JSValueRef& value)
33 {
34     JavaScriptVariant returnValue;
35
36     switch (JSValueGetType(ctx, value)) {
37     case kJSTypeNull:
38         returnValue.setType(JavaScriptVariant::Null);
39         break;
40     case kJSTypeBoolean:
41         returnValue.setBoolean(JSValueToBoolean(ctx, value));
42         break;
43     case kJSTypeNumber:
44         returnValue.setDouble(JSValueToNumber(ctx, value, 0));
45         break;
46     case kJSTypeString: {
47         JSStringRef stringRef = JSValueToStringCopy(ctx, value, 0);
48         size_t bufferSize = JSStringGetMaximumUTF8CStringSize(stringRef);
49         WTF::Vector<char> buffer(bufferSize);
50         JSStringGetUTF8CString(stringRef, buffer.data(), bufferSize);
51         returnValue.setString(WebString::fromUtf8(buffer.data()).utf8().c_str());
52         break;
53     }
54     case kJSTypeObject:
55         returnValue.setType(JavaScriptVariant::Object);
56         break;
57     case kJSTypeUndefined:
58         returnValue.setType(JavaScriptVariant::Undefined);
59         break;
60     }
61     return returnValue;
62 }
63
64 JSValueRef BlackBerryJavaScriptVariantToJSValueRef(const JSGlobalContextRef& ctx, const JavaScriptVariant& variant)
65 {
66     JSValueRef ref = 0;
67     switch (variant.type()) {
68     case JavaScriptVariant::Undefined:
69         ref = JSValueMakeUndefined(ctx);
70         break;
71     case JavaScriptVariant::Null:
72         ref = JSValueMakeNull(ctx);
73         break;
74     case JavaScriptVariant::Boolean:
75         ref = JSValueMakeBoolean(ctx, variant.booleanValue());
76         break;
77     case JavaScriptVariant::Number:
78         ref = JSValueMakeNumber(ctx, variant.doubleValue());
79         break;
80     case JavaScriptVariant::String: {
81         JSStringRef str = JSStringCreateWithUTF8CString(variant.stringValue());
82         ref = JSValueMakeString(ctx, str);
83         JSStringRelease(str);
84         break;
85     }
86     case JavaScriptVariant::Exception:
87     case JavaScriptVariant::Object:
88         ASSERT_NOT_REACHED();
89         break;
90     }
91     return ref;
92 }
93
94 JavaScriptVariant::JavaScriptVariant()
95     : m_type(Undefined)
96     , m_stringValue(0)
97 {
98 }
99
100 JavaScriptVariant::JavaScriptVariant(double value)
101     : m_type(Undefined)
102     , m_stringValue(0)
103 {
104     setDouble(value);
105 }
106
107 JavaScriptVariant::JavaScriptVariant(int value)
108     : m_type(Undefined)
109     , m_stringValue(0)
110 {
111     setDouble(value);
112 }
113
114 JavaScriptVariant::JavaScriptVariant(const char* value)
115     : m_type(Undefined)
116     , m_stringValue(0)
117 {
118     setString(value);
119 }
120
121 JavaScriptVariant::JavaScriptVariant(const std::string& value)
122     : m_type(Undefined)
123     , m_stringValue(0)
124 {
125     setString(value.c_str());
126 }
127
128 JavaScriptVariant::JavaScriptVariant(bool value)
129     : m_type(Undefined)
130     , m_stringValue(0)
131 {
132     setBoolean(value);
133 }
134
135 JavaScriptVariant::JavaScriptVariant(const JavaScriptVariant &v)
136     : m_type(Undefined)
137     , m_stringValue(0)
138 {
139     this->operator=(v);
140 }
141
142 JavaScriptVariant::~JavaScriptVariant()
143 {
144     // Prevent memory leaks if we have strings
145     setType(Undefined);
146 }
147
148 JavaScriptVariant& JavaScriptVariant::operator=(const JavaScriptVariant& v)
149 {
150     if (&v == this)
151         return *this;
152
153     switch (v.type()) {
154     case Boolean:
155         setBoolean(v.booleanValue());
156         break;
157     case Number:
158         setDouble(v.doubleValue());
159         break;
160     case String:
161         setString(v.stringValue());
162         break;
163     default:
164         setType(v.type());
165         break;
166     }
167
168     return *this;
169 }
170
171 void JavaScriptVariant::setType(const DataType& type)
172 {
173     if (m_type == String)
174         free(m_stringValue);
175     m_type = type;
176     m_stringValue = 0;
177 }
178
179 JavaScriptVariant::DataType JavaScriptVariant::type() const
180 {
181     return m_type;
182 }
183
184 void JavaScriptVariant::setDouble(double value)
185 {
186     setType(Number);
187     m_doubleValue = value;
188 }
189
190 double JavaScriptVariant::doubleValue() const
191 {
192     return m_doubleValue;
193 }
194
195 void JavaScriptVariant::setString(const char* value)
196 {
197     setType(String);
198     m_stringValue = strdup(value);
199 }
200
201 char* JavaScriptVariant::stringValue() const
202 {
203     return m_stringValue;
204 }
205
206 void JavaScriptVariant::setBoolean(bool value)
207 {
208     setType(Boolean);
209     m_booleanValue = value;
210 }
211
212 bool JavaScriptVariant::booleanValue() const
213 {
214     return m_booleanValue;
215 }
216
217 }
218 }