Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- Converts a Python value to a PHP value.
- *pyobj* (``PyObject *``) is the python value.
- .. NOTE:: If this is a ``PyUnicodeObject``, the resulting PHP value will
- contain a UTF-8 encoded string.
- *pymemo* (``PyObject *``) is a memo dictionary of objects already copied. This
- is used internally by this method so it should be set to ``NULL``.
- Returns the new PHP value (``zval *``).
- .. NOTE:: If the return value is ``NULL``, a Python exception has been raised.
- */
- static zval * PyObject_to_zval(PyObject * pyobj, PyObject * pymemo) {
- // Other python object type checks...
- else if (PyDict_Check(pyobj)) {
- bool pymemo_is_tmp = false;
- Py_ssize_t pylen = 0;
- Py_ssize_t pypos = 0;
- Py_ssize_t keylen = 0;
- const char * key = NULL; // borrowed
- zval * zdict = NULL; // owned
- zval * zv = NULL; // owned
- PyObject * pyptr = NULL; // borrowed
- PyObject * pykey = NULL; // borrowed
- PyObject * pyval = NULL; // borrowed
- PyObject * pyptr_tmp = NULL; // owned
- PyObject * pykey_tmp = NULL; // owned
- PyObject * pyval_tmp = NULL; // owned
- // Make sure the dict is small enough.
- pylen = PyDict_Size(pyobj);
- if (pylen < 0 || INT_MAX < pylen) {
- PyErr_Format(PyExc_ValueError, "Python object:%s length:%" PY_Z "i must be between 0 and %i inclusive.", Py_TYPE(pyobj)->tp_name, pylen, INT_MAX);
- return NULL;
- }
- // Initialize PHP array.
- MAKE_STD_ZVAL(zdict);
- if (zdict == NULL) {
- PyErr_Format(InternalErrorType, "Failed to create zval.");
- return NULL;
- }
- if (array_init(zdict) != SUCCESS) {
- PyErr_Format(InternalErrorType, "Failed to initialize zval array.");
- goto dict_error;
- }
- // Create memo dict if we don't have one.
- if (pymemo == NULL) {
- pymemo = PyDict_New();
- if (pymemo == NULL) {
- goto dict_error;
- }
- pymemo_is_tmp = true;
- }
- // Iterate over python dict, convert python key-value pairs into PHP key
- // value pairs and append them to the PHP array.
- while (PyDict_Next(pyobj, &pypos, &pykey, &pyval)) {
- // Get python key string.
- if (pykey == Py_None || pykey == Py_False) {
- // In PHP both `null` and `false` become empty strings when casted.
- key = "";
- keylen = 0;
- } else {
- if (PyString_Check(pykey)) {
- key = PyString_AS_STRING(pykey);
- keylen = PyString_GET_SIZE(pykey);
- } else {
- if (PyUnicode_Check(pykey)) {
- pykey_tmp = PyUnicode_AsUTF8String(pykey);
- } else {
- pykey_tmp = PyObject_Str(pykey);
- }
- if (pykey_tmp == NULL) {
- goto dict_error; // Clean up.
- }
- key = PyString_AS_STRING(pykey_tmp);
- keylen = PyString_GET_SIZE(pykey_tmp);
- }
- if (keylen < 0 || INT_MAX < keylen) {
- PyErr_Format(InternalErrorType, "Python key:%s length:%" PY_Z "i must be between 0 and %i inclusive.", Py_TYPE(pykey)->tp_name, keylen, INT_MAX);
- goto dict_error; // Clean up.
- }
- }
- // Convert python value to php value.
- // - The memo dict maps python value pointer to php value pointer.
- pyval_tmp = PyLong_FromVoidPtr(pyval);
- if (pyval_tmp == NULL) {
- goto dict_error; // Clean up.
- }
- pyptr = PyDict_GetItem(pymemo, pyval_tmp);
- if (pyptr != NULL) {
- // Get mapped php value pointer from python value pointer.
- zv = PyLong_AsVoidPtr(pyptr);
- if (zv == NULL) {
- goto dict_error; // Clean up.
- }
- } else {
- zv = PyObject_to_zval(pyval, pymemo);
- if (zv == NULL) {
- goto dict_error; // Clean up.
- }
- // Map python value pointer to php value pointer to support recursion.
- pyptr_tmp = PyLong_FromVoidPtr(zv);
- if (pyptr_tmp == NULL) {
- goto dict_error; // Clean up.
- }
- if (PyDict_SetItem(pymemo, pyval_tmp, pyptr_tmp) != 0) {
- goto dict_error; // Clean up.
- }
- }
- // Set new php value in array.
- // - NOTE: Hash key length MUST include NULL byte.
- if (zend_symtable_update(Z_ARRVAL_P(zdict), key, (unsigned int)keylen + 1, &zv, sizeof(zv), NULL) != SUCCESS) {
- PyErr_Format(InternalErrorType, "Failed to set key in php array.");
- goto dict_error;
- }
- zv = NULL; // PHP dict steals reference to php value.
- // Destroy temporary python values.
- Py_CLEAR(pyptr_tmp);
- Py_CLEAR(pyval_tmp);
- Py_CLEAR(pykey_tmp);
- }
- // Clean up remaining python temporary values.
- if (pymemo_is_tmp) {
- Py_DECREF(pymemo);
- }
- // Return new PHP array.
- return zdict;
- // Failed to convert python dict to php array.
- dict_error: {
- // Clean up temporary python values.
- Py_XDECREF(pyptr_tmp);
- Py_XDECREF(pyval_tmp);
- Py_XDECREF(pykey_tmp);
- if (pymemo_is_tmp) {
- Py_DECREF(pymemo);
- }
- // Destory orphaned php value.
- if (zv != NULL) {
- zval_del(&zv);
- }
- // Destory php array.
- zval_del(&zdict);
- }
- return NULL;
- }
- // Other python object type checks...
- // Python object not supported.
- PyErr_Format(PyExc_TypeError, "Python type:%s cannot be converted to a PHP value.", Py_TYPE(pyobj)->tp_name);
- return NULL;
- }
Advertisement
Add Comment
Please, Sign In to add comment