1/* 2 * This file is part of libSavitar. 3 * 4 * Parts of this code have been copied from libArcus 5 * Copyright (C) 2016 Ultimaker b.v. <a.hiemstra@ultimaker.com> 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as published 9 * by the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Lesser General Public License for more details. 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 21/** 22 * Convert a python str object to a std::string. 23 */ 24%MappedType std::string 25{ 26 %TypeHeaderCode 27 #include <string> 28 %End 29 30 %ConvertFromTypeCode // From C++ to python 31 PyObject* newstring; 32 newstring = PyUnicode_DecodeUTF8(sipCpp->c_str(), sipCpp->length(), NULL); 33 if(newstring == NULL) 34 { 35 PyErr_Clear(); 36 newstring = PyBytes_FromString(sipCpp->c_str()); 37 } 38 return newstring; 39 %End 40 41 %ConvertToTypeCode // From python to C++ 42 // Allow a Python string (or a unicode string) whenever a string is 43 // expected. 44 // If argument is a Unicode string, just decode it to UTF-8 45 // If argument is a Python string, assume it's UTF-8 46 if (sipIsErr == NULL) 47 { 48 return (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)); 49 } 50 51 if (sipPy == Py_None) 52 { 53 *sipCppPtr = new std::string; 54 return 1; 55 } 56 57 if (PyUnicode_Check(sipPy)) 58 { 59 PyObject* s = PyUnicode_AsEncodedString(sipPy, "UTF-8", ""); 60 *sipCppPtr = new std::string(PyBytes_AS_STRING(s)); 61 Py_DECREF(s); 62 return 1; 63 } 64 65 if (PyBytes_Check(sipPy)) 66 { 67 *sipCppPtr = new std::string(PyBytes_AS_STRING(sipPy)); 68 return 1; 69 } 70 return 0; 71 %End 72}; 73 74/** 75 * Convert a list filled with SceneNodes to a vector with SceneNodes. 76 */ 77%MappedType std::vector<SceneNode*> 78{ 79 %TypeHeaderCode 80 #include <vector> 81 %End 82 83 %ConvertFromTypeCode // From C++ to python 84 PyObject *result_list = PyList_New(sipCpp -> size()); 85 86 // Create the Python list of the correct length. 87 if (!result_list) 88 { 89 return NULL; 90 } 91 92 // Go through each element in the C++ instance and convert it to a 93 // wrapped P2d. 94 for (int i = 0; i < (int)sipCpp->size(); ++i) 95 { 96 SceneNode *cpp = new SceneNode(*sipCpp->at(i)); 97 PyObject *pobj = sipConvertFromType(cpp, sipType_SceneNode, sipTransferObj); 98 99 // Get the Python wrapper for the Type instance, creating a new 100 // one if necessary, and handle any ownership transfer. 101 if (!pobj) 102 { 103 // There was an error so garbage collect the Python list. 104 Py_DECREF(result_list); 105 return NULL; 106 } 107 108 // Add the wrapper to the list. 109 PyList_SET_ITEM(result_list, i, pobj); 110 } 111 112 // Return the Python list. 113 return result_list; 114 %End 115 116 %ConvertToTypeCode // From python to C++ 117 // Check if type is compatible 118 if (!sipIsErr) 119 { 120 // Must be any iterable 121 PyObject *i = PyObject_GetIter(sipPy); 122 bool iterable = (i != NULL); 123 Py_XDECREF(i); 124 return iterable; 125 } 126 127 // Iterate over the object 128 PyObject *iterator = PyObject_GetIter(sipPy); 129 PyObject *item; 130 131 std::vector<SceneNode*> *result_vector = new std::vector<SceneNode*>(); 132 133 while ((item = PyIter_Next(iterator))) 134 { 135 if (!sipCanConvertToType(item, sipType_SceneNode, SIP_NOT_NONE)) 136 { 137 PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to SceneNode"); 138 *sipIsErr = 1; 139 break; 140 } 141 142 int state; 143 SceneNode* p = reinterpret_cast<SceneNode*>(sipConvertToType(item, sipType_SceneNode, 0, SIP_NOT_NONE, &state, sipIsErr)); 144 145 if (!*sipIsErr) 146 { 147 result_vector->push_back(p); 148 } 149 150 sipReleaseType(p, sipType_SceneNode, state); 151 Py_DECREF(item); 152 } 153 154 Py_DECREF(iterator); 155 156 if (*sipIsErr) 157 { 158 delete result_vector; 159 return 0; 160 } 161 162 *sipCppPtr = result_vector; 163 return sipGetState(sipTransferObj); 164 %End 165}; 166 167/** 168 * Convert to and from byte arrays. 169 * Uses the internal data vector directly to create/extract a PyBytes* instance. 170 */ 171%MappedType bytearray 172{ 173 %TypeHeaderCode 174 #include <vector> 175 #include <cstdint> 176 #include "Types.h" 177 %End 178 179 %ConvertFromTypeCode // From C++ to python 180 return PyBytes_FromStringAndSize(reinterpret_cast<const char *>(sipCpp->data()), sipCpp->size()); 181 %End 182 183 %ConvertToTypeCode // From python to C++ 184 if (sipIsErr == NULL) 185 { 186 return (PyBytes_Check(sipPy)); 187 } 188 189 if (sipPy == Py_None) 190 { 191 *sipCppPtr = new bytearray; 192 return 1; 193 } 194 195 if (PyBytes_Check(sipPy)) 196 { 197 uint8_t *buffer = reinterpret_cast<uint8_t *>(PyBytes_AS_STRING(sipPy)); 198 *sipCppPtr = new bytearray(buffer, buffer + PyBytes_GET_SIZE(sipPy)); 199 return 1; 200 } 201 return 0; 202 %End 203}; 204 205/** 206 * SIP generic implementation for std::vector<TYPE> 207 */ 208template<TYPE> 209%MappedType std::vector<TYPE> 210{ 211 %TypeHeaderCode 212 #include <vector> 213 %End 214 215 %ConvertFromTypeCode // From C++ to python 216 PyObject *result_list = PyList_New(sipCpp -> size()); 217 218 // Create the Python list of the correct length. 219 if (!result_list) 220 { 221 return NULL; 222 } 223 224 // Go through each element in the C++ instance and convert it to a 225 // wrapped P2d. 226 for (int i = 0; i < (int)sipCpp->size(); ++i) 227 { 228 TYPE *cpp = new TYPE(sipCpp->at(i)); 229 PyObject *pobj = sipConvertFromType(cpp, sipClass_TYPE, sipTransferObj); 230 231 // Get the Python wrapper for the Type instance, creating a new 232 // one if necessary, and handle any ownership transfer. 233 if (!pobj) 234 { 235 // There was an error so garbage collect the Python list. 236 Py_DECREF(result_list); 237 return NULL; 238 } 239 240 // Add the wrapper to the list. 241 PyList_SET_ITEM(result_list, i, pobj); 242 } 243 244 // Return the Python list. 245 return result_list; 246 %End 247 248 %ConvertToTypeCode // From python to C++ 249 // Check if type is compatible 250 if (!sipIsErr) 251 { 252 // Must be any iterable 253 PyObject *i = PyObject_GetIter(sipPy); 254 bool iterable = (i != NULL); 255 Py_XDECREF(i); 256 return iterable; 257 } 258 259 // Iterate over the object 260 PyObject *iterator = PyObject_GetIter(sipPy); 261 PyObject *item; 262 263 std::vector<TYPE> *result_vector = new std::vector<TYPE>(); 264 265 while ((item = PyIter_Next(iterator))) 266 { 267 if (!sipCanConvertToType(item, sipClass_TYPE, SIP_NOT_NONE)) 268 { 269 PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE"); 270 *sipIsErr = 1; 271 break; 272 } 273 274 int state; 275 TYPE* p = reinterpret_cast<TYPE*>(sipConvertToType(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr)); 276 277 if (!*sipIsErr) 278 { 279 result_vector->push_back(*p); 280 } 281 282 sipReleaseType(p, sipClass_TYPE, state); 283 Py_DECREF(item); 284 } 285 286 Py_DECREF(iterator); 287 288 if (*sipIsErr) 289 { 290 delete result_vector; 291 return 0; 292 } 293 294 *sipCppPtr = result_vector; 295 return sipGetState(sipTransferObj); 296 %End 297}; 298 299 300/** 301 * Convert a (python) dict with strings as keys and values to a map<string, string>. 302 */ 303%MappedType std::map<std::string, std::string> 304{ 305 %TypeHeaderCode 306 #include <map> 307 %End 308 309 %ConvertFromTypeCode // From C++ to python 310 // Create the dictionary. 311 PyObject *result_dict = PyDict_New(); 312 313 if (!result_dict) 314 { 315 return NULL; 316 } 317 318 // Set the dictionary elements. 319 std::map<std::string, std::string>::const_iterator i = sipCpp->begin(); 320 321 while (i != sipCpp->end()) 322 { 323 std::string *key = new std::string((*i).first); 324 std::string *value = new std::string((*i).second); 325 326 PyObject *key_object = sipConvertFromNewType(key, sipType_std_string, sipTransferObj); 327 PyObject *value_object = sipConvertFromNewType(value, sipType_std_string, sipTransferObj); 328 329 if (key_object == NULL || value_object == NULL || PyDict_SetItem(result_dict, key_object, value_object) < 0) 330 { 331 Py_DECREF(result_dict); 332 333 if (key_object) 334 { 335 Py_DECREF(key_object); 336 } 337 else 338 { 339 delete key; 340 } 341 342 if (value_object) 343 { 344 Py_DECREF(value_object); 345 } 346 else 347 { 348 delete value; 349 } 350 351 return nullptr; 352 } 353 354 Py_DECREF(key_object); 355 Py_DECREF(value_object); 356 357 ++i; 358 } 359 360 return result_dict; 361 %End 362 363 %ConvertToTypeCode // From python to C++ 364 PyObject *key_object, *value_object; 365 SIP_SSIZE_T i = 0; 366 367 // Check the type if that is all that is required. 368 if (sipIsErr == nullptr) 369 { 370 if (!PyDict_Check(sipPy)) 371 { 372 return 0; 373 } 374 375 while (PyDict_Next(sipPy, &i, &key_object, &value_object)) 376 { 377 if (!sipCanConvertToType(key_object, sipType_std_string, SIP_NOT_NONE)) 378 { 379 return 0; 380 } 381 382 if (!sipCanConvertToType(value_object, sipType_std_string, SIP_NOT_NONE)) 383 { 384 return 0; 385 } 386 } 387 388 return 1; 389 } 390 391 std::map<std::string, std::string> *std_map = new std::map<std::string, std::string>; 392 393 while (PyDict_Next(sipPy, &i, &key_object, &value_object)) 394 { 395 int key_state, value_state; 396 397 std::string *key = reinterpret_cast<std::string *>(sipConvertToType(key_object, sipType_std_string, sipTransferObj, SIP_NOT_NONE, &key_state, sipIsErr)); 398 std::string *value = reinterpret_cast<std::string *>(sipConvertToType(value_object, sipType_std_string, sipTransferObj, SIP_NOT_NONE, &value_state, sipIsErr)); 399 400 if (*sipIsErr) 401 { 402 sipReleaseType(key, sipType_std_string, key_state); 403 sipReleaseType(value, sipType_std_string, value_state); 404 405 delete std_map; 406 return 0; 407 } 408 409 (*std_map)[*key] = *value; 410 411 sipReleaseType(key, sipType_std_string, key_state); 412 sipReleaseType(value, sipType_std_string, value_state); 413 } 414 415 *sipCppPtr = std_map; 416 417 return sipGetState(sipTransferObj); 418 %End 419}; 420