Home | History | Annotate | Download | only in api
      1 /*
      2     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      3 
      4     This library is free software; you can redistribute it and/or
      5     modify it under the terms of the GNU Library 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     Library General Public License for more details.
     13 
     14     You should have received a copy of the GNU Library General Public License
     15     along with this library; see the file COPYING.LIB.  If not, write to
     16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17     Boston, MA 02110-1301, USA.
     18 */
     19 
     20 #ifndef qscriptconverter_p_h
     21 #define qscriptconverter_p_h
     22 
     23 #include "qscriptvalue.h"
     24 #include <JavaScriptCore/JavaScript.h>
     25 #include <QtCore/qglobal.h>
     26 #include <QtCore/qnumeric.h>
     27 #include <QtCore/qstring.h>
     28 #include <QtCore/qvarlengtharray.h>
     29 
     30 extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
     31 
     32 /*
     33   \internal
     34   \class QScriptConverter
     35   QScriptValue and QScriptEngine helper class. This class's responsibility is to convert values
     36   between JS values and Qt/C++ values.
     37 
     38   This is a nice way to inline these functions in both QScriptValue and QScriptEngine.
     39 */
     40 class QScriptConverter {
     41 public:
     42     static quint32 toArrayIndex(const JSStringRef jsstring)
     43     {
     44         // FIXME this function should be exported by JSC C API.
     45         QString qstring = toString(jsstring);
     46 
     47         bool ok;
     48         quint32 idx = qstring.toUInt(&ok);
     49         if (!ok || toString(idx) != qstring)
     50             idx = 0xffffffff;
     51 
     52         return idx;
     53     }
     54 
     55     static QString toString(const JSStringRef str)
     56     {
     57         return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(str)), JSStringGetLength(str));
     58     }
     59     static JSStringRef toString(const QString& str)
     60     {
     61         return JSStringCreateWithUTF8CString(str.toUtf8().constData());
     62     }
     63     static JSStringRef toString(const char* str)
     64     {
     65         return JSStringCreateWithUTF8CString(str);
     66     }
     67     static QString toString(double value)
     68     {
     69         // FIXME this should be easier. The ideal fix is to create
     70         // a new function in JSC C API which could cover the functionality.
     71 
     72         if (qIsNaN(value))
     73             return QString::fromLatin1("NaN");
     74         if (qIsInf(value))
     75             return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity");
     76         if (!value)
     77             return QString::fromLatin1("0");
     78 
     79         QVarLengthArray<char, 25> buf;
     80         int decpt;
     81         int sign;
     82         char* result = 0;
     83         char* endresult;
     84         (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result);
     85 
     86         if (!result)
     87             return QString();
     88 
     89         int resultLen = endresult - result;
     90         if (decpt <= 0 && decpt > -6) {
     91             buf.resize(-decpt + 2 + sign);
     92             qMemSet(buf.data(), '0', -decpt + 2 + sign);
     93             if (sign) // fix the sign.
     94                 buf[0] = '-';
     95             buf[sign + 1] = '.';
     96             buf.append(result, resultLen);
     97         } else {
     98             if (sign)
     99                 buf.append('-');
    100             int length = buf.size() - sign + resultLen;
    101             if (decpt <= 21 && decpt > 0) {
    102                 if (length <= decpt) {
    103                     const char* zeros = "0000000000000000000000000";
    104                     buf.append(result, resultLen);
    105                     buf.append(zeros, decpt - length);
    106                 } else {
    107                     buf.append(result, decpt);
    108                     buf.append('.');
    109                     buf.append(result + decpt, resultLen - decpt);
    110                 }
    111             } else if (result[0] >= '0' && result[0] <= '9') {
    112                 if (length > 1) {
    113                     buf.append(result, 1);
    114                     buf.append('.');
    115                     buf.append(result + 1, resultLen - 1);
    116                 } else
    117                     buf.append(result, resultLen);
    118                 buf.append('e');
    119                 buf.append(decpt >= 0 ? '+' : '-');
    120                 int e = qAbs(decpt - 1);
    121                 if (e >= 100)
    122                     buf.append('0' + e / 100);
    123                 if (e >= 10)
    124                     buf.append('0' + (e % 100) / 10);
    125                 buf.append('0' + e % 10);
    126             }
    127         }
    128         free(result);
    129         buf.append(0);
    130         return QString::fromLatin1(buf.constData());
    131     }
    132 
    133     static JSPropertyAttributes toPropertyFlags(const QFlags<QScriptValue::PropertyFlag>& flags)
    134     {
    135         JSPropertyAttributes attr = 0;
    136         if (flags.testFlag(QScriptValue::ReadOnly))
    137             attr |= kJSPropertyAttributeReadOnly;
    138         if (flags.testFlag(QScriptValue::Undeletable))
    139             attr |= kJSPropertyAttributeDontDelete;
    140         if (flags.testFlag(QScriptValue::SkipInEnumeration))
    141             attr |= kJSPropertyAttributeDontEnum;
    142         return attr;
    143     }
    144 };
    145 
    146 #endif // qscriptconverter_p_h
    147