Base: let PyStreambuf figure out if String or Bytes object must be written to file

This commit is contained in:
wmayer
2020-06-29 18:04:32 +02:00
parent d3b43aa5bf
commit 864555bc93
2 changed files with 67 additions and 27 deletions

View File

@@ -40,6 +40,7 @@
#include "Stream.h"
#include "Swap.h"
#include <CXX/Objects.hxx>
#include <Python.h>
using namespace Base;
@@ -529,6 +530,7 @@ IODeviceIStreambuf::seekpos(std::streambuf::pos_type pos,
// http://www.icce.rug.nl/documents/cplusplus/cplusplus24.html
PyStreambuf::PyStreambuf(PyObject* o, std::size_t buf_size, std::size_t put_back)
: inp(o)
, type(Unknown)
, put_back(std::max(put_back, std::size_t(1)))
, buffer(std::max(buf_size, put_back) + put_back)
{
@@ -568,8 +570,19 @@ PyStreambuf::int_type PyStreambuf::underflow()
Py::Callable meth(Py::Object(inp).getAttr("read"));
try {
Py::String res(meth.apply(arg));
std::string c = static_cast<std::string>(res);
std::string c;
Py::Object res(meth.apply(arg));
if (res.isBytes()) {
c = static_cast<std::string>(Py::Bytes(res));
}
else if (res.isString()) {
c = static_cast<std::string>(Py::String(res));
}
else {
// wrong type
return traits_type::eof();
}
n = c.size();
if (n == 0) {
return traits_type::eof();
@@ -601,17 +614,8 @@ PyStreambuf::overflow(PyStreambuf::int_type ch)
#else
if (ch != EOF) {
char z = ch;
try {
Py::Tuple arg(1);
arg.setItem(0, Py::Char(z));
Py::Callable meth(Py::Object(inp).getAttr("write"));
meth.apply(arg);
}
catch(Py::Exception& e) {
e.clear();
return EOF;
}
if (!writeStr(&z, 1))
return traits_type::eof();
}
return ch;
@@ -634,18 +638,52 @@ bool PyStreambuf::flushBuffer()
{
std::ptrdiff_t n = pptr() - pbase();
pbump(-n);
return writeStr(pbase(), n);
}
bool PyStreambuf::writeStr(const char* str, std::streamsize num)
{
try {
Py::Tuple arg(1);
arg.setItem(0, Py::String(pbase(), n));
Py::Callable meth(Py::Object(inp).getAttr("write"));
meth.apply(arg);
return true;
if (type == StringIO) {
arg.setItem(0, Py::String(str, num));
meth.apply(arg);
return true;
}
else if (type == BytesIO) {
arg.setItem(0, Py::Bytes(str, num));
meth.apply(arg);
return true;
}
else {
// try out what works
try {
arg.setItem(0, Py::String(str, num));
meth.apply(arg);
type = StringIO;
return true;
}
catch (Py::Exception& e) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
e.clear();
arg.setItem(0, Py::Bytes(str, num));
meth.apply(arg);
type = BytesIO;
return true;
}
else {
throw; // re-throw
}
}
}
}
catch(Py::Exception& e) {
e.clear();
return false;
}
return false;
}
std::streamsize PyStreambuf::xsputn (const char* s, std::streamsize num)
@@ -653,17 +691,8 @@ std::streamsize PyStreambuf::xsputn (const char* s, std::streamsize num)
#ifdef PYSTREAM_BUFFERED
return std::streambuf::xsputn(s, num);
#else
try {
Py::Tuple arg(1);
arg.setItem(0, Py::String(s, num));
Py::Callable meth(Py::Object(inp).getAttr("write"));
meth.apply(arg);
}
catch(Py::Exception& e) {
e.clear();
if (!writeStr(s, num))
return 0;
}
return num;
#endif
}