tizen 2.4 release
[framework/web/wrt-plugins-common.git] / src / CommonsJavaScript / Converter.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 #include <sstream>
17 #include <limits>
18 #include <dpl/scoped_free.h>
19 #include "ScopedJSStringRef.h"
20 #include "Converter.h"
21 #include <dpl/log/log.h>
22
23 using namespace WrtDeviceApis::Commons;
24
25 namespace WrtDeviceApis {
26 namespace CommonsJavaScript {
27 Converter::Converter(JSContextRef context) : m_context(context)
28 {}
29
30 Converter::~Converter()
31 {}
32
33 JSObjectRef Converter::toJSObjectRef(const JSValueRef& arg)
34 {
35     if (!arg) {
36         Throw(NullPointerException);
37     }
38     JSValueRef exception = NULL;
39     JSObjectRef result = JSValueToObject(m_context, arg, &exception);
40     if ((NULL == result) || (NULL != exception)) {
41         ThrowMsg(ConversionException, "Couldn't convert to a JS Object.");
42     }
43     return result;
44 }
45
46 bool Converter::toBool(const JSValueRef& arg)
47 {
48     return JSValueToBoolean(m_context, arg);
49 }
50
51 unsigned char Converter::toUChar(const JSValueRef& arg)
52 {
53     double tmp = toNumber_(arg);
54     return (isNan(tmp) ? 0 : static_cast<unsigned char>(static_cast<unsigned long>(static_cast<long long>(tmp))));
55 }
56
57 char Converter::toChar(const JSValueRef& arg)
58 {
59     double tmp = toNumber_(arg);
60     return (isNan(tmp) ? 0 : static_cast<char>(static_cast<long>(static_cast<long long>(tmp))));
61 }
62
63 int Converter::toInt(const JSValueRef& arg)
64 {
65     double tmp = toNumber_(arg);
66     return (isNan(tmp) ? 0 : static_cast<int>(static_cast<long long>(tmp)));
67 }
68
69 int Converter::toInt(const std::string &arg)
70 {
71     return static_cast<int>(static_cast<long long>(toNumber_(arg)));
72 }
73
74 long Converter::toLong(const JSValueRef& arg)
75 {
76     double tmp = toNumber_(arg);
77     return (isNan(tmp) ? 0 : static_cast<long>(static_cast<long long>(tmp)));
78 }
79
80 long long Converter::toLongLong(const JSValueRef& arg)
81 {
82     double tmp = toNumber_(arg);
83     return (isNan(tmp) ? 0 : static_cast<long long>(tmp));
84 }
85
86 unsigned long Converter::toULong(const JSValueRef& arg)
87 {
88     double tmp = toNumber_(arg);
89     return (isNan(tmp) ? 0 : static_cast<unsigned long>(static_cast<long long>(tmp)));
90 }
91
92 std::size_t Converter::toSizeT(const JSValueRef& arg)
93 {
94     double tmp = toNumber_(arg);
95     return (isNan(tmp) ? 0 : static_cast<std::size_t>(tmp));
96 }
97
98 std::size_t Converter::toSizeT(const JSStringRef& arg)
99 {
100     return static_cast<std::size_t>(toNumber_(arg));
101 }
102
103 double Converter::toDouble(const JSValueRef& arg)
104 {
105     return toNumber_(arg);
106 }
107
108 std::string Converter::toString(int arg)
109 {
110     return toString_(arg);
111 }
112
113 std::string Converter::toString(unsigned long arg)
114 {
115     return toString_(arg);
116 }
117
118 std::string Converter::toString(long arg)
119 {
120     return toString_(arg);
121 }
122
123 std::string Converter::toString(std::size_t arg)
124 {
125     return toString_(arg);
126 }
127
128 std::string Converter::toString(const JSValueRef& arg)
129 {
130     return toString_(arg);
131 }
132
133 std::string Converter::tryString(const JSValueRef& arg)
134 {
135     if (!JSValueIsString(m_context, arg) &&
136         !JSValueIsNumber(m_context, arg) &&
137         !JSValueIsBoolean(m_context, arg))
138     {
139         ThrowMsg(ConversionException,
140                  "Argument is not convertable to JS String.");
141     }
142
143     return toString_(arg);
144 }
145
146 std::string Converter::toDateString(const JSValueRef& arg)
147 {
148     if (!JSValueIsObject(m_context, arg)) {
149         ThrowMsg(ConversionException, "Argument is not JS Date.");
150     }
151
152     return toString_(arg);
153 }
154
155 std::string Converter::toString(const JSStringRef& arg)
156 {
157     std::string result;
158     size_t jsSize = JSStringGetMaximumUTF8CStringSize(arg);
159     if (jsSize > 0) {
160         jsSize = jsSize + 1;
161         std::unique_ptr<char[]> buffer(new char[jsSize]);
162         size_t written = JSStringGetUTF8CString(arg, buffer.get(), jsSize);
163         if (written > jsSize) {
164             ThrowMsg(ConversionException,
165                      "Conversion could not be fully performed.");
166         }
167         result = buffer.get();
168     }
169
170     return result;
171 }
172
173 time_t Converter::toDateTimeT(const JSValueRef& arg)
174 {
175     struct tm tm = toDateTm(arg);
176     return mktime(&tm);
177 }
178
179 tm Converter::toDateTm(const JSValueRef& arg)
180 {
181     using namespace std::placeholders;
182
183     std::string stringDate = toDateString(arg);
184     struct tm result;
185     char* currentLocale = setlocale(LC_TIME, NULL);
186     if (currentLocale == NULL) {
187         ThrowMsg(ConversionException, "Couldn't get current locale.");
188     }
189     std::unique_ptr<char, void(*)(void*)> currentLocaleCopy(strdup(currentLocale), &free);
190     if (setlocale(LC_TIME, "C") == NULL) {
191         ThrowMsg(ConversionException, "Couldn't set POSIX locale.");
192     }
193     if (strptime(stringDate.c_str(), "%a %b %d %Y %T", &result) == NULL) {
194         ThrowMsg(ConversionException, "Couldn't convert supplied date.");
195     }
196     if (setlocale(LC_TIME, currentLocaleCopy.get()) == NULL) {
197         ThrowMsg(ConversionException, "Couldn't set previous locale back.");
198     }
199     //strptime function doesn't affect tm_isdst flag.
200     //It may cause -1hr conversion error. Setting it to -1 informs that
201     //there is no information about daylight saving time.
202     result.tm_isdst = -1;
203     return result;
204 }
205
206 std::vector<unsigned char> Converter::toVectorOfUChars(const JSValueRef& arg)
207 {
208     return toVectorOfT_(arg, &Converter::toUChar);
209 }
210
211 std::vector<char> Converter::toVectorOfChars(const JSValueRef& arg)
212 {
213     return toVectorOfT_(arg, &Converter::toChar);
214 }
215
216 std::vector<int> Converter::toVectorOfInts(const JSValueRef& arg)
217 {
218     return toVectorOfT_(arg, &Converter::toInt);
219 }
220
221 std::vector<std::string> Converter::toVectorOfStrings(const JSValueRef& arg)
222 {
223     return toVectorOfT_(arg, &Converter::toString);
224 }
225
226 std::vector<time_t> Converter::toVectorOfTimeT(const JSValueRef& arg)
227 {
228     return toVectorOfT_(arg, &Converter::toDateTimeT);
229 }
230
231 JSValueRef Converter::toJSValueRef(bool arg)
232 {
233     return JSValueMakeBoolean(m_context, arg);
234 }
235
236 JSValueRef Converter::toJSValueRef(int arg)
237 {
238     return JSValueMakeNumber(m_context, arg);
239 }
240
241 JSValueRef Converter::toJSValueRef(unsigned int arg)
242 {
243     return JSValueMakeNumber(m_context, arg);
244 }
245
246 JSValueRef Converter::toJSValueRef(unsigned long arg)
247 {
248     return JSValueMakeNumber(m_context, arg);
249 }
250
251 JSValueRef Converter::toJSValueRefLong(const long arg)
252 {
253     return JSValueMakeNumber(m_context, arg);
254 }
255
256 JSValueRef Converter::toJSValueRef(long long int arg)
257 {
258     return JSValueMakeNumber(m_context, arg);
259 }
260
261 JSValueRef Converter::toJSValueRef(double arg)
262 {
263     return JSValueMakeNumber(m_context, arg);
264 }
265
266 JSValueRef Converter::toJSValueRef(const std::string& arg)
267 {
268     JSValueRef result = NULL;
269     JSStringRef jsString = JSStringCreateWithUTF8CString(arg.c_str());
270     result = JSValueMakeString(m_context, jsString);
271     JSStringRelease(jsString);
272     return result;
273 }
274
275 JSValueRef Converter::toJSValueRef(const tm& arg)
276 {
277     JSValueRef args[6];
278     args[0] = JSValueMakeNumber(m_context, arg.tm_year + 1900);
279     args[1] = JSValueMakeNumber(m_context, arg.tm_mon);
280     args[2] = JSValueMakeNumber(m_context, arg.tm_mday);
281     args[3] = JSValueMakeNumber(m_context, arg.tm_hour);
282     args[4] = JSValueMakeNumber(m_context, arg.tm_min);
283     args[5] = JSValueMakeNumber(m_context, arg.tm_sec);
284
285     JSValueRef exception = NULL;
286     JSObjectRef result = JSObjectMakeDate(m_context, 6, args, &exception);
287     if (NULL != exception) {
288         ThrowMsg(ConversionException, "Couldn't convert to a JS Date.");
289     }
290
291     return result;
292 }
293
294 JSValueRef Converter::toJSValueRef(const time_t arg)
295 {
296     struct tm tminfo;
297     memset(&tminfo,0,sizeof(tminfo));
298     localtime_r(&arg, &tminfo);
299     return toJSValueRef(tminfo);
300 }
301
302 JSValueRef Converter::toJSValueRef(const std::vector<std::string>& arg)
303 {
304     return toJSValueRef_(arg);
305 }
306
307 JSValueRef Converter::toJSValueRef(const char* arg)
308 {
309     return toJSValueRef(std::string(arg));
310 }
311
312 JSValueRef Converter::toJSValueRef(const std::vector<int>& arg)
313 {
314     return toJSValueRef_(arg);
315 }
316
317 JSValueRef Converter::toJSValueRef(const std::vector<time_t>& arg)
318 {
319     return toJSValueRef_(arg);
320 }
321
322 JSValueRef Converter::toJSValueRef(JSValueRef arg)
323 {
324     return arg;
325 }
326
327 JSValueRef Converter::toJSValueRef(const std::vector<JSValueRef>& arg)
328 {
329     return toJSValueRef_(arg);
330 }
331
332 JSStringRef Converter::toJSStringRef(const std::string& arg)
333 {
334     return JSStringCreateWithUTF8CString(arg.c_str());
335 }
336
337 double Converter::toNumber_(const JSStringRef& arg)
338 {
339     return toNumber_(toString(arg));
340 }
341
342 double Converter::toNumber_(const std::string& arg)
343 {
344     double result;
345     std::stringstream ss(arg);
346     if (!(ss >> result)) {
347         Throw(ConversionException);
348     }
349     return result;
350 }
351
352 double Converter::toNumber_(const JSValueRef& arg)
353 {
354     JSValueRef exception = NULL;
355     double result = JSValueToNumber(m_context, arg, &exception);
356     if (NULL != exception) {
357         ThrowMsg(ConversionException, "Couldn't convert to a number.");
358     }
359     return result;
360 }
361
362 std::string Converter::toString_(const JSValueRef& arg)
363 {
364     std::string result;
365
366     JSValueRef exception = NULL;
367     JSStringRef str = JSValueToStringCopy(m_context, arg, &exception);
368     if (NULL == str) {
369         ThrowMsg(ConversionException, "Couldn't cast to a string.");
370     }
371
372     size_t jsSize = JSStringGetMaximumUTF8CStringSize(str);
373     if (jsSize > 0) {
374         std::unique_ptr<char[]> buffer(new char[jsSize]);
375         JSStringGetUTF8CString(str, buffer.get(), jsSize);
376         result = buffer.get();
377     }
378     JSStringRelease(str);
379     return result;
380 }
381
382 bool Converter::isNan(double value) const
383 {
384     // This should work unless -ffast-math (GCC) option is used.
385     STATIC_CHECK(std::numeric_limits<double>::is_iec559,
386                  NOT_IEEE754_REPRESENTATION);
387     return (value != value);
388 }
389 } // CommonsJavaScript
390 } // WrtDeviceApis
391