1 // This is the support for QString.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of PyQt5.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file.  Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license.  For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 
20 
21 #include <Python.h>
22 #include <string.h>
23 
24 #include <QString>
25 #include <QVector>
26 
27 #include "qpycore_api.h"
28 
29 #include "sipAPIQtCore.h"
30 
31 
32 // Work out if we should enable PEP 393 support.  This is complicated by the
33 // broken LLVM that XCode v4 installs.
34 #if PY_VERSION_HEX >= 0x03030000
35 #if defined(Q_OS_MAC)
36 #if !defined(__llvm__) || defined(__clang__)
37 // Python v3.3 or later on a Mac using either g++ or Clang, but not LLVM.
38 #define PYQT_PEP_393
39 #endif
40 #else
41 // Python v3.3 or later on a non-Mac.
42 #define PYQT_PEP_393
43 #endif
44 #endif
45 
46 
47 // Convert a QString to a Python Unicode object.
qpycore_PyObject_FromQString(const QString & qstr)48 PyObject *qpycore_PyObject_FromQString(const QString &qstr)
49 {
50     PyObject *obj;
51 
52 #if defined(PYQT_PEP_393)
53     // We have to work out exactly which kind to use.  We assume ASCII while we
54     // are checking so that we only go through the string once in the most
55     // common case.  Note that we can't use PyUnicode_FromKindAndData() because
56     // it doesn't handle surrogates in UCS2 strings.
57     int qt_len = qstr.length();
58     int kind;
59     void *data;
60 
61     if ((obj = sipUnicodeNew(qt_len, 0x007f, &kind, &data)) == NULL)
62         return NULL;
63 
64     const QChar *qch = qstr.constData();
65 
66     for (int qt_i = 0; qt_i < qt_len; ++qt_i)
67     {
68         ushort uch = qch->unicode();
69 
70         if (uch > 0x007f)
71         {
72             // This is useless.
73             Py_DECREF(obj);
74 
75             // Work out what kind we really need and what the Python length
76             // should be.
77             uint maxchar = 0x00ff;
78 
79             int py_len = qt_len;
80 
81             while (qt_i < qt_len)
82             {
83                 uch = qch->unicode();
84 
85                 if (uch > 0x00ff)
86                 {
87                     if (maxchar == 0x00ff)
88                         maxchar = 0x00ffff;
89 
90                     // See if this is a surrogate pair.  Note that we cannot
91                     // trust that the QString is terminated by a null QChar.
92                     if (qch->isHighSurrogate() && qt_i + 1 < qt_len && (qch + 1)->isLowSurrogate())
93                     {
94                         maxchar = 0x10ffff;
95                         --py_len;
96                         ++qch;
97                         ++qt_i;
98                     }
99                 }
100 
101                 ++qch;
102                 ++qt_i;
103             }
104 
105             // Create the correctly sized object.
106             if ((obj = sipUnicodeNew(py_len, maxchar, &kind, &data)) == NULL)
107                 return NULL;
108 
109             qch = qstr.constData();
110 
111             int qt_i2 = 0;
112 
113             for (int py_i = 0; py_i < py_len; ++py_i)
114             {
115                 uint py_ch;
116 
117                 if (qch->isHighSurrogate() && qt_i2 + 1 < qt_len && (qch + 1)->isLowSurrogate())
118                 {
119                     py_ch = QChar::surrogateToUcs4(*qch, *(qch + 1));
120                     ++qt_i2;
121                     ++qch;
122                 }
123                 else
124                 {
125                     py_ch = qch->unicode();
126                 }
127 
128                 ++qt_i2;
129                 ++qch;
130 
131                 sipUnicodeWrite(kind, data, py_i, py_ch);
132             }
133 
134             break;
135         }
136 
137         ++qch;
138 
139         sipUnicodeWrite(kind, data, qt_i, uch);
140     }
141 #elif defined(Py_UNICODE_WIDE)
142     QVector<uint> ucs4 = qstr.toUcs4();
143 
144     if ((obj = PyUnicode_FromUnicode(NULL, ucs4.size())) == NULL)
145         return NULL;
146 
147     memcpy(PyUnicode_AS_UNICODE(obj), ucs4.constData(),
148             ucs4.size() * sizeof (Py_UNICODE));
149 #else
150     if ((obj = PyUnicode_FromUnicode(NULL, qstr.length())) == NULL)
151         return NULL;
152 
153     memcpy(PyUnicode_AS_UNICODE(obj), qstr.utf16(),
154             qstr.length() * sizeof (Py_UNICODE));
155 #endif
156 
157     return obj;
158 }
159 
160 
161 // Convert a Python string object to a QString.
qpycore_PyObject_AsQString(PyObject * obj)162 QString qpycore_PyObject_AsQString(PyObject *obj)
163 {
164 #if PY_MAJOR_VERSION < 3
165     if (PyString_Check(obj))
166     {
167         const char *obj_s = PyString_AsString(obj);
168 
169         if (!obj_s)
170             return QString();
171 
172         return QString::fromUtf8(obj_s);
173     }
174 #endif
175 
176 #if defined(PYQT_PEP_393)
177     int char_size;
178     Py_ssize_t len;
179     void *data = sipUnicodeData(obj, &char_size, &len);
180 
181     if (char_size == 1)
182         return QString::fromLatin1(reinterpret_cast<char *>(data), len);
183 
184     if (char_size == 2)
185         // The (QChar *) cast should be safe.
186         return QString(reinterpret_cast<QChar *>(data), len);
187 
188     if (char_size == 4)
189         return QString::fromUcs4(reinterpret_cast<uint *>(data), len);
190 
191     return QString();
192 #elif defined(Py_UNICODE_WIDE)
193     return QString::fromUcs4((const uint *)PyUnicode_AS_UNICODE(obj),
194             PyUnicode_GET_SIZE(obj));
195 #else
196     return QString::fromUtf16((const ushort *)PyUnicode_AS_UNICODE(obj),
197             PyUnicode_GET_SIZE(obj));
198 #endif
199 }
200