1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt for Python.
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "sbkstring.h"
41 #include "sbkstaticstrings_p.h"
42 #include "autodecref.h"
43
44 #include <vector>
45 #include <unordered_set>
46
47 namespace Shiboken
48 {
49
50 namespace String
51 {
52
53 // PYSIDE-795: Redirecting PySequence to Iterable
checkIterable(PyObject * obj)54 bool checkIterable(PyObject *obj)
55 {
56 return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter());
57 }
58
checkType(PyTypeObject * type)59 bool checkType(PyTypeObject *type)
60 {
61 return type == &PyUnicode_Type
62 #if PY_MAJOR_VERSION < 3
63 || type == &PyString_Type
64 #endif
65 ;
66 }
67
check(PyObject * obj)68 bool check(PyObject *obj)
69 {
70 return obj == Py_None ||
71 #if PY_MAJOR_VERSION < 3
72 PyString_Check(obj) ||
73 #endif
74 PyUnicode_Check(obj);
75 }
76
checkChar(PyObject * pyobj)77 bool checkChar(PyObject *pyobj)
78 {
79 return check(pyobj) && (len(pyobj) == 1);
80 }
81
isConvertible(PyObject * obj)82 bool isConvertible(PyObject *obj)
83 {
84 return check(obj);
85 }
86
fromCString(const char * value)87 PyObject *fromCString(const char *value)
88 {
89 #ifdef IS_PY3K
90 return PyUnicode_FromString(value);
91 #else
92 return PyBytes_FromString(value);
93 #endif
94 }
95
fromCString(const char * value,int len)96 PyObject *fromCString(const char *value, int len)
97 {
98 #ifdef IS_PY3K
99 return PyUnicode_FromStringAndSize(value, len);
100 #else
101 return PyBytes_FromStringAndSize(value, len);
102 #endif
103 }
104
toCString(PyObject * str,Py_ssize_t * len)105 const char *toCString(PyObject *str, Py_ssize_t *len)
106 {
107 if (str == Py_None)
108 return nullptr;
109 if (PyUnicode_Check(str)) {
110 if (len) {
111 // We need to encode the unicode string into utf8 to know the size of returned char *.
112 Shiboken::AutoDecRef uniStr(PyUnicode_AsUTF8String(str));
113 *len = PyBytes_GET_SIZE(uniStr.object());
114 }
115 #ifdef IS_PY3K
116 // Return unicode from str instead of uniStr, because the lifetime of the returned pointer
117 // depends on the lifetime of str.
118 return _PepUnicode_AsString(str);
119 #else
120 str = PyUnicode_AsUTF8String(str);
121 if (str == NULL) {
122 return NULL;
123 }
124 return PyString_AsString(str);
125 #endif
126 }
127 if (PyBytes_Check(str)) {
128 if (len)
129 *len = PyBytes_GET_SIZE(str);
130 return PyBytes_AS_STRING(str);
131 }
132 return nullptr;
133 }
134
concat(PyObject ** val1,PyObject * val2)135 bool concat(PyObject **val1, PyObject *val2)
136 {
137 if (PyUnicode_Check(*val1) && PyUnicode_Check(val2)) {
138 PyObject *result = PyUnicode_Concat(*val1, val2);
139 Py_DECREF(*val1);
140 *val1 = result;
141 return true;
142 }
143
144 if (PyBytes_Check(*val1) && PyBytes_Check(val2)) {
145 PyBytes_Concat(val1, val2);
146 return true;
147 }
148
149 #if PY_MAJOR_VERSION < 3
150 if (PyString_Check(*val1) && PyString_Check(val2)) {
151 PyString_Concat(val1, val2);
152 return true;
153 }
154 #endif
155 return false;
156 }
157
fromFormat(const char * format,...)158 PyObject *fromFormat(const char *format, ...)
159 {
160 va_list argp;
161 va_start(argp, format);
162 PyObject *result = nullptr;
163 #ifdef IS_PY3K
164 result = PyUnicode_FromFormatV(format, argp);
165 #else
166 result = PyString_FromFormatV(format, argp);
167 #endif
168 va_end(argp);
169 return result;
170 }
171
fromStringAndSize(const char * str,Py_ssize_t size)172 PyObject *fromStringAndSize(const char *str, Py_ssize_t size)
173 {
174 #ifdef IS_PY3K
175 return PyUnicode_FromStringAndSize(str, size);
176 #else
177 return PyString_FromStringAndSize(str, size);
178 #endif
179 }
180
compare(PyObject * val1,const char * val2)181 int compare(PyObject *val1, const char *val2)
182 {
183 if (PyUnicode_Check(val1))
184 #ifdef IS_PY3K
185 return PyUnicode_CompareWithASCIIString(val1, val2);
186 #else
187 {
188 PyObject *uVal2 = PyUnicode_FromString(val2);
189 bool result = PyUnicode_Compare(val1, uVal2);
190 Py_XDECREF(uVal2);
191 return result;
192 }
193 if (PyString_Check(val1))
194 return strcmp(PyString_AS_STRING(val1), val2);
195 #endif
196 return 0;
197
198 }
199
len(PyObject * str)200 Py_ssize_t len(PyObject *str)
201 {
202 if (str == Py_None)
203 return 0;
204
205 if (PyUnicode_Check(str))
206 return PepUnicode_GetLength(str);
207
208 if (PyBytes_Check(str))
209 return PyBytes_GET_SIZE(str);
210 return 0;
211 }
212
213 ///////////////////////////////////////////////////////////////////////
214 //
215 // Implementation of efficient Python strings
216 // ------------------------------------------
217 //
218 // Instead of repetitively executing
219 //
220 // PyObject *attr = PyObject_GetAttrString(obj, "__name__");
221 //
222 // a helper of the form
223 //
224 // PyObject *name()
225 // {
226 // static PyObject *const s = Shiboken::String::createStaticString("__name__");
227 // return result;
228 // }
229 //
230 // can now be implemented, which registers the string into a static set avoiding
231 // repetitive string creation. The resulting code looks like:
232 //
233 // PyObject *attr = PyObject_GetAttr(obj, name());
234 //
235
236 using StaticStrings = std::unordered_set<PyObject *>;
237
238 static void finalizeStaticStrings(); // forward
239
staticStrings()240 static StaticStrings &staticStrings()
241 {
242 static StaticStrings result;
243 return result;
244 }
245
finalizeStaticStrings()246 static void finalizeStaticStrings()
247 {
248 auto &set = staticStrings();
249 for (PyObject *ob : set) {
250 Py_REFCNT(ob) = 1;
251 Py_DECREF(ob);
252 }
253 set.clear();
254 }
255
createStaticString(const char * str)256 PyObject *createStaticString(const char *str)
257 {
258 static bool initialized = false;
259 if (!initialized) {
260 Py_AtExit(finalizeStaticStrings);
261 initialized = true;
262 }
263 #if PY_VERSION_HEX >= 0x03000000
264 PyObject *result = PyUnicode_InternFromString(str);
265 #else
266 PyObject *result = PyString_InternFromString(str);
267 #endif
268 if (result == nullptr) {
269 // This error is never checked, but also very unlikely. Report and exit.
270 PyErr_Print();
271 Py_FatalError("unexpected error in createStaticString()");
272 }
273 auto it = staticStrings().find(result);
274 if (it == staticStrings().end())
275 staticStrings().insert(result);
276 /*
277 * Note: We always add one reference even if we have a new string.
278 * This makes the strings immortal, and we are safe if someone
279 * uses AutoDecRef, although the set cannot cope with deletions.
280 * The exit handler cleans that up, anyway.
281 */
282 Py_INCREF(result);
283 return result;
284 }
285
286 ///////////////////////////////////////////////////////////////////////
287 //
288 // PYSIDE-1019: Helper function for snake_case vs. camelCase names
289 // ---------------------------------------------------------------
290 //
291 // When renaming dict entries, `BindingManager::getOverride` must
292 // use adapted names.
293 //
294 // This might become more complex when we need to register
295 // exceptions from this rule.
296 //
297
getSnakeCaseName(const char * name,bool lower)298 PyObject *getSnakeCaseName(const char *name, bool lower)
299 {
300 /*
301 * Convert `camelCase` to `snake_case`.
302 * Gives up when there are two consecutive upper chars.
303 *
304 * Also functions beginning with `gl` followed by upper case stay
305 * unchanged since that are the special OpenGL functions.
306 */
307 if (!lower
308 || strlen(name) < 3
309 || (name[0] == 'g' && name[1] == 'l' && isupper(name[2])))
310 return createStaticString(name);
311
312 char new_name[200 + 1] = {};
313 const char *p = name;
314 char *q = new_name;
315 for (; *p && q - new_name < 200; ++p, ++q) {
316 if (isupper(*p)) {
317 if (p != name && isupper(*(p - 1)))
318 return createStaticString(name);
319 *q = '_';
320 ++q;
321 *q = tolower(*p);
322 }
323 else {
324 *q = *p;
325 }
326 }
327 return createStaticString(new_name);
328 }
329
getSnakeCaseName(PyObject * name,bool lower)330 PyObject *getSnakeCaseName(PyObject *name, bool lower)
331 {
332 // This is all static strings, not refcounted.
333 if (lower)
334 return getSnakeCaseName(toCString(name), lower);
335 return name;
336 }
337
338 } // namespace String
339 } // namespace Shiboken
340