textEncoder_ext.cxx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file textEncoder_ext.cxx
  10. * @author rdb
  11. * @date 2018-09-29
  12. */
  13. #include "textEncoder_ext.h"
  14. #ifdef HAVE_PYTHON
  15. /**
  16. * Sets the text as a Unicode string. In Python 2, if a regular str is given,
  17. * it is assumed to be in the TextEncoder's specified encoding.
  18. */
  19. void Extension<TextEncoder>::
  20. set_text(PyObject *text) {
  21. if (PyUnicode_Check(text)) {
  22. #if PY_VERSION_HEX >= 0x03030000
  23. Py_ssize_t len;
  24. const char *str = PyUnicode_AsUTF8AndSize(text, &len);
  25. _this->set_text(std::string(str, len), TextEncoder::E_utf8);
  26. #else
  27. Py_ssize_t len = PyUnicode_GET_SIZE(text);
  28. wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1));
  29. PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len);
  30. _this->set_wtext(std::wstring(str, len));
  31. #endif
  32. } else {
  33. #if PY_MAJOR_VERSION >= 3
  34. Dtool_Raise_TypeError("expected string");
  35. #else
  36. char *str;
  37. Py_ssize_t len;
  38. if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) {
  39. _this->set_text(std::string(str, len));
  40. }
  41. #endif
  42. }
  43. }
  44. /**
  45. * Sets the text as an encoded byte string of the given encoding.
  46. */
  47. void Extension<TextEncoder>::
  48. set_text(PyObject *text, TextEncoder::Encoding encoding) {
  49. char *str;
  50. Py_ssize_t len;
  51. if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) {
  52. _this->set_text(std::string(str, len), encoding);
  53. }
  54. }
  55. /**
  56. * Returns the text as a string. In Python 2, the returned string is in the
  57. * TextEncoder's specified encoding. In Python 3, it is returned as unicode.
  58. */
  59. PyObject *Extension<TextEncoder>::
  60. get_text() const {
  61. #if PY_MAJOR_VERSION >= 3
  62. std::wstring text = _this->get_wtext();
  63. return PyUnicode_FromWideChar(text.data(), (Py_ssize_t)text.size());
  64. #else
  65. std::string text = _this->get_text();
  66. return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
  67. #endif
  68. }
  69. /**
  70. * Returns the text as a bytes object in the given encoding.
  71. */
  72. PyObject *Extension<TextEncoder>::
  73. get_text(TextEncoder::Encoding encoding) const {
  74. std::string text = _this->get_text(encoding);
  75. #if PY_MAJOR_VERSION >= 3
  76. return PyBytes_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
  77. #else
  78. return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
  79. #endif
  80. }
  81. /**
  82. * Appends the text as a string (or Unicode object in Python 2).
  83. */
  84. void Extension<TextEncoder>::
  85. append_text(PyObject *text) {
  86. if (PyUnicode_Check(text)) {
  87. #if PY_VERSION_HEX >= 0x03030000
  88. Py_ssize_t len;
  89. const char *str = PyUnicode_AsUTF8AndSize(text, &len);
  90. std::string text_str(str, len);
  91. if (_this->get_encoding() == TextEncoder::E_utf8) {
  92. _this->append_text(text_str);
  93. } else {
  94. _this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8));
  95. }
  96. #else
  97. Py_ssize_t len = PyUnicode_GET_SIZE(text);
  98. wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1));
  99. PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len);
  100. _this->append_wtext(std::wstring(str, len));
  101. #endif
  102. } else {
  103. #if PY_MAJOR_VERSION >= 3
  104. Dtool_Raise_TypeError("expected string");
  105. #else
  106. char *str;
  107. Py_ssize_t len;
  108. if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) {
  109. _this->append_text(std::string(str, len));
  110. }
  111. #endif
  112. }
  113. }
  114. /**
  115. * Encodes the given wide character as byte string in the given encoding.
  116. */
  117. PyObject *Extension<TextEncoder>::
  118. encode_wchar(char32_t ch, TextEncoder::Encoding encoding) {
  119. std::string value = TextEncoder::encode_wchar(ch, encoding);
  120. #if PY_MAJOR_VERSION >= 3
  121. return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
  122. #else
  123. return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
  124. #endif
  125. }
  126. /**
  127. * Encodes a wide-text string into a single-char string, according to the
  128. * given encoding.
  129. */
  130. PyObject *Extension<TextEncoder>::
  131. encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) {
  132. std::string value = TextEncoder::encode_wtext(wtext, encoding);
  133. #if PY_MAJOR_VERSION >= 3
  134. return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
  135. #else
  136. return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
  137. #endif
  138. }
  139. /**
  140. * Returns the given wstring decoded to a single-byte string, via the given
  141. * encoding system.
  142. */
  143. PyObject *Extension<TextEncoder>::
  144. decode_text(PyObject *text, TextEncoder::Encoding encoding) {
  145. char *str;
  146. Py_ssize_t len;
  147. if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) {
  148. return Dtool_WrapValue(TextEncoder::decode_text(std::string(str, len), encoding));
  149. } else {
  150. return nullptr;
  151. }
  152. }
  153. #endif // HAVE_PYTHON