Change copyrights from Nokia to Digia
[profile/ivi/qtdeclarative.git] / src / qml / qml / v8 / qjsconverter_impl_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qjsconverter_p.h"
43 #include <stdlib.h>
44
45 #ifndef QJSCONVERTER_IMPL_P_H
46 #define QJSCONVERTER_IMPL_P_H
47
48 #ifdef Q_OS_QNX
49 #include <malloc.h>
50 #endif
51
52 QT_BEGIN_NAMESPACE
53
54 extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
55 Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
56
57
58 quint32 QJSConverter::toArrayIndex(const QString& string)
59 {
60     // FIXME this function should be exported by JSC C API.
61     bool ok;
62     quint32 idx = string.toUInt(&ok);
63     if (!ok || toString(idx) != string)
64         idx = 0xffffffff;
65
66     return idx;
67 }
68
69 QString QJSConverter::toString(v8::Handle<v8::String> jsString)
70 {
71     if (jsString.IsEmpty())
72         return QString();
73     QString qstr;
74     qstr.resize(jsString->Length());
75     jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
76     return qstr;
77 }
78
79 v8::Local<v8::String> QJSConverter::toString(const QString& string)
80 {
81     return v8::String::New(reinterpret_cast<const uint16_t*>(string.data()), string.size());
82 }
83
84 QString QJSConverter::toString(double value)
85 {
86     // FIXME this should be easier. The ideal fix is to create
87     // a new function in V8 API which could cover the functionality.
88
89     if (qIsNaN(value))
90         return QString::fromLatin1("NaN");
91     if (qIsInf(value))
92         return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity");
93     if (!value)
94         return QString::fromLatin1("0");
95
96     QVarLengthArray<char, 25> buf;
97     int decpt;
98     int sign;
99     char* result = 0;
100     char* endresult;
101     (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result);
102
103     if (!result)
104         return QString();
105
106     int resultLen = endresult - result;
107     if (decpt <= 0 && decpt > -6) {
108         buf.resize(-decpt + 2 + sign);
109         memset(buf.data(), '0', -decpt + 2 + sign);
110         if (sign) // fix the sign.
111             buf[0] = '-';
112         buf[sign + 1] = '.';
113         buf.append(result, resultLen);
114     } else {
115         if (sign)
116             buf.append('-');
117         int length = buf.size() - sign + resultLen;
118         if (decpt <= 21 && decpt > 0) {
119             if (length <= decpt) {
120                 const char* zeros = "0000000000000000000000000";
121                 buf.append(result, resultLen);
122                 buf.append(zeros, decpt - length);
123             } else {
124                 buf.append(result, decpt);
125                 buf.append('.');
126                 buf.append(result + decpt, resultLen - decpt);
127             }
128         } else if (result[0] >= '0' && result[0] <= '9') {
129             if (length > 1) {
130                 buf.append(result, 1);
131                 buf.append('.');
132                 buf.append(result + 1, resultLen - 1);
133             } else
134                 buf.append(result, resultLen);
135             buf.append('e');
136             buf.append(decpt >= 0 ? '+' : '-');
137             int e = qAbs(decpt - 1);
138             if (e >= 100)
139                 buf.append('0' + e / 100);
140             if (e >= 10)
141                 buf.append('0' + (e % 100) / 10);
142             buf.append('0' + e % 10);
143         }
144     }
145     free(result);
146     buf.append(0);
147     return QString::fromLatin1(buf.constData());
148 }
149
150 // return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
151 uint QJSConverter::toPropertyAttributes(const QFlags<QJSValuePrivate::PropertyFlag>& flags)
152 {
153     uint attr = 0;
154     if (flags.testFlag(QJSValuePrivate::ReadOnly))
155         attr |= v8::ReadOnly;
156     if (flags.testFlag(QJSValuePrivate::Undeletable))
157         attr |= v8::DontDelete;
158     if (flags.testFlag(QJSValuePrivate::SkipInEnumeration))
159         attr |= v8::DontEnum;
160     //        if (flags.testFlag(QScriptValue::PropertyGetter))
161     //            attr |= QScriptValue::PropertyGetter;
162     //        if (flags.testFlag(QScriptValue::PropertySetter))
163     //            attr |= QScriptValue::PropertySetter;
164     return attr;
165 }
166
167 // Converts a JS RegExp to a QRegExp.
168 // The conversion is not 100% exact since ECMA regexp and QRegExp
169 // have different semantics/flags, but we try to do our best.
170 QRegExp QJSConverter::toRegExp(v8::Handle<v8::RegExp> jsRegExp)
171 {
172     QString pattern = QJSConverter::toString(jsRegExp->GetSource());
173     Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
174     if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
175         caseSensitivity = Qt::CaseInsensitive;
176     return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
177 }
178
179 // Converts a QRegExp to a JS RegExp.
180 // The conversion is not 100% exact since ECMA regexp and QRegExp
181 // have different semantics/flags, but we try to do our best.
182 v8::Local<v8::RegExp> QJSConverter::toRegExp(const QRegExp &re)
183 {
184     // Convert the pattern to a ECMAScript pattern.
185     QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax());
186     if (re.isMinimal()) {
187         QString ecmaPattern;
188         int len = pattern.length();
189         ecmaPattern.reserve(len);
190         int i = 0;
191         const QChar *wc = pattern.unicode();
192         bool inBracket = false;
193         while (i < len) {
194             QChar c = wc[i++];
195             ecmaPattern += c;
196             switch (c.unicode()) {
197             case '?':
198             case '+':
199             case '*':
200             case '}':
201                 if (!inBracket)
202                     ecmaPattern += QLatin1Char('?');
203                 break;
204             case '\\':
205                 if (i < len)
206                     ecmaPattern += wc[i++];
207                 break;
208             case '[':
209                 inBracket = true;
210                 break;
211             case ']':
212                 inBracket = false;
213                 break;
214             default:
215                 break;
216             }
217         }
218         pattern = ecmaPattern;
219     }
220
221     int flags = v8::RegExp::kNone;
222     if (re.caseSensitivity() == Qt::CaseInsensitive)
223         flags |= v8::RegExp::kIgnoreCase;
224
225     return v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(flags));
226 }
227
228 // Converts a QStringList to JS.
229 // The result is a new Array object with length equal to the length
230 // of the QStringList, and the elements being the QStringList's
231 // elements converted to JS Strings.
232 v8::Local<v8::Array> QJSConverter::toStringList(const QStringList &lst)
233 {
234     v8::Local<v8::Array> result = v8::Array::New(lst.size());
235     for (int i = 0; i < lst.size(); ++i)
236         result->Set(i, toString(lst.at(i)));
237     return result;
238 }
239
240 // Converts a JS Array object to a QStringList.
241 // The result is a QStringList with length equal to the length
242 // of the JS Array, and elements being the JS Array's elements
243 // converted to QStrings.
244 QStringList QJSConverter::toStringList(v8::Handle<v8::Array> jsArray)
245 {
246     QStringList result;
247     uint32_t length = jsArray->Length();
248     for (uint32_t i = 0; i < length; ++i)
249         result.append(toString(jsArray->Get(i)->ToString()));
250     return result;
251 }
252
253
254 // Converts a JS Date to a QDateTime.
255 QDateTime QJSConverter::toDateTime(v8::Handle<v8::Date> jsDate)
256 {
257     return QDateTime::fromMSecsSinceEpoch(jsDate->NumberValue());
258 }
259
260 // Converts a QDateTime to a JS Date.
261 v8::Local<v8::Value> QJSConverter::toDateTime(const QDateTime &dt)
262 {
263     double date;
264     if (!dt.isValid())
265         date = qSNaN();
266     else
267         date = dt.toMSecsSinceEpoch();
268     return v8::Date::New(date);
269 }
270
271 QT_END_NAMESPACE
272
273 #endif // QJSCONVERTER_IMPL_P_H