open_toontown_panda3d/dtool/src/prc/streamReader_ext.cxx

149 lines
3.6 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file streamReader_ext.cxx
* @author rdb
* @date 2013-12-09
*/
#include "streamReader_ext.h"
#ifdef HAVE_PYTHON
#include "vector_string.h"
/**
* Extracts the indicated number of bytes in the stream and returns them as a
* string (or bytes, in Python 3). Returns empty string at end-of-file.
*/
PyObject *Extension<StreamReader>::
extract_bytes(size_t size) {
std::istream *in = _this->get_istream();
if (in->eof() || in->fail() || size == 0) {
// Note that this is only safe to call with size 0 while the GIL is held.
return PyBytes_FromStringAndSize(nullptr, 0);
}
PyObject *bytes = PyBytes_FromStringAndSize(nullptr, size);
char *buffer = (char *)PyBytes_AS_STRING(bytes);
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyThreadState *_save;
Py_UNBLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
in->read(buffer, size);
size_t read_bytes = in->gcount();
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
Py_BLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
if (read_bytes == size || _PyBytes_Resize(&bytes, read_bytes) == 0) {
return bytes;
} else {
return nullptr;
}
}
/**
* Assumes the stream represents a text file, and extracts one line up to and
* including the trailing newline character. Returns empty string when the
* end of file is reached.
*
* The interface here is intentionally designed to be similar to that for
* Python's File.readline() function.
*/
PyObject *Extension<StreamReader>::
readline() {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyThreadState *_save;
Py_UNBLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
std::istream *in = _this->get_istream();
std::string line;
int ch = in->get();
while (ch != EOF && !in->fail()) {
line += ch;
if (ch == '\n' || in->eof()) {
// Here's the newline character.
break;
}
ch = in->get();
}
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
Py_BLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
#if PY_MAJOR_VERSION >= 3
return PyBytes_FromStringAndSize(line.data(), line.size());
#else
return PyString_FromStringAndSize(line.data(), line.size());
#endif
}
/**
* Reads all the lines at once and returns a list. Also see the documentation
* for readline().
*/
PyObject *Extension<StreamReader>::
readlines() {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyThreadState *_save;
Py_UNBLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
std::istream *in = _this->get_istream();
vector_string lines;
while (true) {
std::string line;
int ch = in->get();
while (ch != EOF && !in->fail()) {
line += ch;
if (ch == '\n' || in->eof()) {
// Here's the newline character.
break;
}
ch = in->get();
}
if (line.empty()) {
break;
}
lines.push_back(std::move(line));
}
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
Py_BLOCK_THREADS
#endif // HAVE_THREADS && !SIMPLE_THREADS
PyObject *lst = PyList_New(lines.size());
if (lst == nullptr) {
return nullptr;
}
Py_ssize_t i = 0;
for (const std::string &line : lines) {
#if PY_MAJOR_VERSION >= 3
PyObject *py_line = PyBytes_FromStringAndSize(line.data(), line.size());
#else
PyObject *py_line = PyString_FromStringAndSize(line.data(), line.size());
#endif
PyList_SET_ITEM(lst, i++, py_line);
}
return lst;
}
#endif