scl.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. // Standard Conversion Library (Currently for Python only)
  18. #ifndef SCL_H
  19. #define SCL_H
  20. #if PY_MAJOR_VERSION >= 3
  21. #define PyString_AsString(val) \
  22. PyBytes_AsString(val)
  23. #define PyString_AsStringAndSize(val, lpstr, size) \
  24. PyBytes_AsStringAndSize(val, lpstr, size)
  25. #define PyString_FromStringAndSize(val, size) \
  26. PyBytes_FromStringAndSize(val, size)
  27. #define PyString_FromString(val) \
  28. PyBytes_FromString(val)
  29. #define PyInt_AsLong(id) \
  30. PyLong_AsLong(id)
  31. #endif
  32. #include <kopano/platform.h>
  33. // Get Py_ssize_t for older versions of python
  34. #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
  35. typedef int Py_ssize_t;
  36. # define PY_SSIZE_T_MAX INT_MAX
  37. # define PY_SSIZE_T_MIN INT_MIN
  38. #endif
  39. namespace priv {
  40. /**
  41. * Default version of conv_out, which is intended to convert one script value
  42. * to a native value.
  43. * This version will always generate a compile error as the actual conversions
  44. * should be performed by specializations for the specific native types.
  45. *
  46. * @tparam _Type The type of the resulting value.
  47. * @param[in] Value The scripted value to convert.
  48. * @param[in] flags Allowed values:
  49. * @remark @c MAPI_UNICODE If the data is a string, it's a wide character string
  50. * @param[out] result The native value.
  51. */
  52. template <typename _Type>
  53. void conv_out(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, _Type* result) {
  54. // Just generate an error here
  55. value = result;
  56. }
  57. /**
  58. * Specialization for extracting a string (TCHAR*) from a script value.
  59. *
  60. * @tparam _Type The type of the resulting value.
  61. * @param[in] Value The scripted value to convert.
  62. * @param[out] result The native value.
  63. */
  64. template <>
  65. void conv_out<LPTSTR>(PyObject* value, LPVOID lpBase, ULONG ulFlags, LPTSTR *lppResult) {
  66. if(value == Py_None) {
  67. *lppResult = NULL;
  68. return;
  69. }
  70. // FIXME: General helper function as improvement
  71. if ((ulFlags & MAPI_UNICODE) == 0) {
  72. *(LPSTR*)lppResult = PyString_AsString(value);
  73. return;
  74. }
  75. int len = PyUnicode_GetSize(value);
  76. if (MAPIAllocateMore((len + 1) * sizeof(wchar_t), lpBase, reinterpret_cast<void **>(lppResult)) != hrSuccess)
  77. throw std::bad_alloc();
  78. // FIXME: Required for the PyUnicodeObject cast
  79. #if PY_MAJOR_VERSION >= 3
  80. len = PyUnicode_AsWideChar(value, *(LPWSTR*)lppResult, len);
  81. #else
  82. len = PyUnicode_AsWideChar((PyUnicodeObject*)value, *(LPWSTR*)lppResult, len);
  83. #endif
  84. (*(LPWSTR*)lppResult)[len] = L'\0';
  85. }
  86. /**
  87. * Specialization for extracting an unsigned int from a script value.
  88. *
  89. * @tparam _Type The type of the resulting value.
  90. * @param[in] Value The scripted value to convert.
  91. * @param[out] result The native value.
  92. */
  93. template <>
  94. void conv_out<unsigned int>(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, unsigned int *lpResult) {
  95. *lpResult = (unsigned int)PyLong_AsUnsignedLong(value);
  96. }
  97. /**
  98. * Specialization for extracting an unsigned short from a script value.
  99. *
  100. * @tparam _Type The type of the resulting value.
  101. * @param[in] Value The scripted value to convert.
  102. * @param[out] result The native value.
  103. */
  104. template <>
  105. void conv_out<unsigned short>(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, unsigned short *lpResult) {
  106. *lpResult = (unsigned short)PyLong_AsUnsignedLong(value);
  107. }
  108. /**
  109. * Specialization for extracting a boolean from a script value.
  110. *
  111. * @tparam _Type The type of the resulting value.
  112. * @param[in] Value The scripted value to convert.
  113. * @param[out] result The native value.
  114. */
  115. template <>
  116. void conv_out<bool>(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, bool *lpResult) {
  117. *lpResult = (bool)PyLong_AsUnsignedLong(value);
  118. }
  119. /**
  120. * Specialization for extracting a int64_t from a script value.
  121. *
  122. * @tparam _Type The type of the resulting value.
  123. * @param[in] Value The scripted value to convert.
  124. * @param[out] result The native value.
  125. */
  126. template <>
  127. void conv_out<int64_t>(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, int64_t *lpResult) {
  128. *lpResult = (int64_t)PyLong_AsUnsignedLong(value);
  129. }
  130. /**
  131. * Specialization for extracting an ECENTRYID from a script value.
  132. *
  133. * @tparam _Type The type of the resulting value.
  134. * @param[in] Value The scripted value to convert.
  135. * @param[out] result The native value.
  136. */
  137. template <>
  138. void conv_out<ECENTRYID>(PyObject* value, LPVOID lpBase, ULONG /*ulFlags*/, ECENTRYID *lpResult) {
  139. char *data;
  140. Py_ssize_t size;
  141. if(value == Py_None) {
  142. lpResult->cb = 0;
  143. lpResult->lpb = NULL;
  144. return;
  145. }
  146. PyString_AsStringAndSize(value, &data, &size);
  147. lpResult->cb = size;
  148. if (MAPIAllocateMore(size, lpBase, reinterpret_cast<void **>(&lpResult->lpb)) != hrSuccess)
  149. throw std::bad_alloc();
  150. memcpy(lpResult->lpb, data, size);
  151. }
  152. /**
  153. * Specialization for extracting an objectclass_t from a script value.
  154. * @note In the script language an objectclass_t will be an unsigned int value.
  155. *
  156. * @tparam _Type The type of the resulting value.
  157. * @param[in] Value The scripted value to convert.
  158. * @param[out] result The native value.
  159. */
  160. template <>
  161. void conv_out<objectclass_t>(PyObject* value, LPVOID /*lpBase*/, ULONG /*ulFlags*/, objectclass_t *lpResult) {
  162. *lpResult = (objectclass_t)PyLong_AsUnsignedLong(value);
  163. }
  164. } // namspace priv
  165. /**
  166. * This is the default convert function for converting a script value to
  167. * a native value that's part of a struct (on both sides). The actual conversion
  168. * is delegated to a specialization of the private::conv_out template.
  169. *
  170. * @tparam _ObjType The type of the structure containing the values that
  171. * are to be converted.
  172. * @tparam _MemType The type of the member for which this particular instantiation
  173. * is intended.
  174. * @tparam _Member The data member pointer that points to the actual field
  175. * for which this particula instantiation is intended.
  176. * @param[in,out] lpObj The native object whos members will be populated with
  177. * values converted from the scripted object.
  178. * @param[in] elem The scipted object, whose values will be converted to
  179. * a native representation.
  180. * @param[in] lpszMember The name of the member in the scripted object.
  181. * @param[in] flags Allowed values:
  182. * @remark @c MAPI_UNICODE If the data is a string, it's a wide character string
  183. */
  184. template <typename _ObjType, typename _MemType, _MemType(_ObjType::*_Member)>
  185. void conv_out_default(_ObjType *lpObj, PyObject *elem, const char *lpszMember, LPVOID lpBase, ULONG ulFlags) {
  186. PyObject *value = PyObject_GetAttrString(elem, const_cast<char*>(lpszMember)); // Older versions of python might expect a non-const char pointer.
  187. if (PyErr_Occurred())
  188. return;
  189. priv::conv_out(value, lpBase, ulFlags, &(lpObj->*_Member));
  190. Py_DECREF(value);
  191. }
  192. /**
  193. * This structure is used to create a list of items that need to be converted from
  194. * their scripted representation to their native representation.
  195. */
  196. template <typename _ObjType>
  197. struct conv_out_info {
  198. typedef void(*conv_out_func_t)(_ObjType*, PyObject*, const char*, LPVOID lpBase, ULONG ulFlags);
  199. conv_out_func_t conv_out_func;
  200. const char* membername;
  201. };
  202. /**
  203. * This function processes an array of conv_out_info structures, effectively
  204. * performing the complete conversion.
  205. *
  206. * @tparam _ ObjType The type of the structure containing the values that
  207. * are to be converted. This is determined automatically.
  208. * @tparam N The size of the array. This is determined automatically.
  209. * @param[in] array The array containing the conv_out_info structures that
  210. * define the conversion operations.
  211. * @param[in] flags Allowed values:
  212. * @remark @c MAPI_UNICODE If the data is a string, it's a wide character string
  213. */
  214. template <typename _ObjType, size_t N>
  215. void process_conv_out_array(_ObjType *lpObj, PyObject *elem, const conv_out_info<_ObjType> (&array)[N], LPVOID lpBase, ULONG ulFlags) {
  216. for (size_t n = 0; !PyErr_Occurred() && n < N; ++n)
  217. array[n].conv_out_func(lpObj, elem, array[n].membername, lpBase, ulFlags);
  218. }
  219. #endif // ndef SCL_H