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