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