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