Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid losing null-chars when casting to/from std::string. #48

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 56 additions & 18 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ NAMESPACE_BEGIN(detail)
#define PYBIND11_AS_STRING PyString_AsString
#endif

#if PY_MAJOR_VERSION >= 3
#define PYBIND11_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
#else
#define PYBIND11_AS_STRING_AND_SIZE PyString_AsStringAndSize
#endif

#if PY_MAJOR_VERSION >= 3
#define PYBIND11_FROM_STRING PyBytes_FromString
#else
#define PYBIND11_FROM_STRING PyString_FromString
#endif

#if PY_MAJOR_VERSION >= 3
#define PYBIND11_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
#else
#define PYBIND11_FROM_STRING_AND_SIZE PyString_FromStringAndSize
#endif

/** Linked list descriptor type for function signatures (produces smaller binaries
compared to a previous solution using std::string and operator +=) */
class descr {
Expand Down Expand Up @@ -336,35 +354,55 @@ template <> class type_caster<bool> {
template <> class type_caster<std::string> {
public:
bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION < 3
if (PyString_Check(src)) { value = PyString_AsString(src); return true; }
#endif
object temp(PyUnicode_AsUTF8String(src), false);
const char *ptr = nullptr;
if (temp)
ptr = PYBIND11_AS_STRING(temp.ptr());
if (!ptr) { PyErr_Clear(); return false; }
value = ptr;
object temp;
PyObject *load_src = src;
if (PyUnicode_Check(src)) {
temp = object(PyUnicode_AsUTF8String(src), false);
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
load_src = temp.ptr();
}
char *buffer;
Py_ssize_t length;
int err = PYBIND11_AS_STRING_AND_SIZE(load_src, &buffer, &length);
if (err == -1) { PyErr_Clear(); return false; } // TypeError
value = std::string(buffer, length);
return true;
}
static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
return PyUnicode_FromString(src.c_str());
}
#if PY_MAJOR_VERSION >= 3
PYBIND11_TYPE_CASTER(std::string, "str");
#else
PYBIND11_TYPE_CASTER(std::string, "unicode");
#endif
};

template <typename T> class type_caster<bytes<T>> : public type_caster<T> {
public:
static PyObject *cast(const bytes<T> &src, return_value_policy /* policy */, PyObject * /* parent */) {
return PYBIND11_FROM_STRING_AND_SIZE(src.data(), src.size());
}
#if PY_MAJOR_VERSION >= 3
PYBIND11_TYPE_CASTER(bytes<T>, "bytes");
#else
PYBIND11_TYPE_CASTER(bytes<T>, "str");
#endif
};

template <> class type_caster<char> {
public:
bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION < 3
if (PyString_Check(src)) { value = PyString_AsString(src); return true; }
#endif
object temp(PyUnicode_AsUTF8String(src), false);
const char *ptr = nullptr;
if (temp)
ptr = PYBIND11_AS_STRING(temp.ptr());
if (!ptr) { PyErr_Clear(); return false; }
value = ptr;
object temp;
PyObject *load_src = src;
if (PyUnicode_Check(src)) {
temp = object(PyUnicode_AsUTF8String(src), false);
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
load_src = temp.ptr();
}
const char *ptr = PYBIND11_AS_STRING(load_src);
if (!ptr) { PyErr_Clear(); return false; } // TypeError
value = std::string(ptr);
return true;
}

Expand Down
10 changes: 10 additions & 0 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ inline iterator handle::end() { return iterator(nullptr); }
PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() { }

template <typename T>
class bytes : public T {
public:
using T::T;

bytes(const T& src) : T(src) { }
bytes(T&& src) : T(std::move(src)) { }
bytes() : T() { }
};

class str : public object {
public:
PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)
Expand Down