897 lines
22 KiB
C++
897 lines
22 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
/***************************************************************************
|
|
* Copyright (c) 2007 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <QBuffer>
|
|
#include <QIODevice>
|
|
#ifdef __GNUC__
|
|
# include <cstdint>
|
|
#endif
|
|
|
|
#include "Stream.h"
|
|
#include "Swap.h"
|
|
#include <CXX/Objects.hxx>
|
|
|
|
|
|
using namespace Base;
|
|
|
|
Stream::Stream() = default;
|
|
|
|
Stream::~Stream() = default;
|
|
|
|
Stream::ByteOrder Stream::byteOrder() const
|
|
{
|
|
return _swap ? BigEndian : LittleEndian;
|
|
}
|
|
|
|
void Stream::setByteOrder(ByteOrder bo)
|
|
{
|
|
_swap = (bo == BigEndian);
|
|
}
|
|
|
|
OutputStream::OutputStream(std::ostream& rout)
|
|
: _out(rout)
|
|
{}
|
|
|
|
OutputStream::~OutputStream() = default;
|
|
|
|
OutputStream& OutputStream::operator<<(bool b)
|
|
{
|
|
_out.write((const char*)&b, sizeof(bool));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(int8_t ch)
|
|
{
|
|
_out.write((const char*)&ch, sizeof(int8_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(uint8_t uch)
|
|
{
|
|
_out.write((const char*)&uch, sizeof(uint8_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(int16_t s)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<int16_t>(s);
|
|
}
|
|
_out.write((const char*)&s, sizeof(int16_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(uint16_t us)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<uint16_t>(us);
|
|
}
|
|
_out.write((const char*)&us, sizeof(uint16_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(int32_t i)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<int32_t>(i);
|
|
}
|
|
_out.write((const char*)&i, sizeof(int32_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(uint32_t ui)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<uint32_t>(ui);
|
|
}
|
|
_out.write((const char*)&ui, sizeof(uint32_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(int64_t l)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<int64_t>(l);
|
|
}
|
|
_out.write((const char*)&l, sizeof(int64_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(uint64_t ul)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<uint64_t>(ul);
|
|
}
|
|
_out.write((const char*)&ul, sizeof(uint64_t));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(float f)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<float>(f);
|
|
}
|
|
_out.write((const char*)&f, sizeof(float));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::operator<<(double d)
|
|
{
|
|
if (isSwapped()) {
|
|
SwapEndian<double>(d);
|
|
}
|
|
_out.write((const char*)&d, sizeof(double));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream& OutputStream::write(const char* s, int n)
|
|
{
|
|
_out.write(s, n);
|
|
return *this;
|
|
}
|
|
|
|
InputStream::InputStream(std::istream& rin)
|
|
: _in(rin)
|
|
{}
|
|
|
|
InputStream::~InputStream() = default;
|
|
|
|
InputStream& InputStream::operator>>(bool& b)
|
|
{
|
|
_in.read((char*)&b, sizeof(bool));
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(int8_t& ch)
|
|
{
|
|
_in.read((char*)&ch, sizeof(int8_t));
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(uint8_t& uch)
|
|
{
|
|
_in.read((char*)&uch, sizeof(uint8_t));
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(int16_t& s)
|
|
{
|
|
_in.read((char*)&s, sizeof(int16_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<int16_t>(s);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(uint16_t& us)
|
|
{
|
|
_in.read((char*)&us, sizeof(uint16_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<uint16_t>(us);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(int32_t& i)
|
|
{
|
|
_in.read((char*)&i, sizeof(int32_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<int32_t>(i);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(uint32_t& ui)
|
|
{
|
|
_in.read((char*)&ui, sizeof(uint32_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<uint32_t>(ui);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(int64_t& l)
|
|
{
|
|
_in.read((char*)&l, sizeof(int64_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<int64_t>(l);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(uint64_t& ul)
|
|
{
|
|
_in.read((char*)&ul, sizeof(uint64_t));
|
|
if (isSwapped()) {
|
|
SwapEndian<uint64_t>(ul);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(float& f)
|
|
{
|
|
_in.read((char*)&f, sizeof(float));
|
|
if (isSwapped()) {
|
|
SwapEndian<float>(f);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::operator>>(double& d)
|
|
{
|
|
_in.read((char*)&d, sizeof(double));
|
|
if (isSwapped()) {
|
|
SwapEndian<double>(d);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
InputStream& InputStream::read(char* s, int n)
|
|
{
|
|
_in.read(s, n);
|
|
return *this;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
ByteArrayOStreambuf::ByteArrayOStreambuf(QByteArray& ba)
|
|
: _buffer(new QBuffer(&ba))
|
|
{
|
|
_buffer->open(QIODevice::WriteOnly);
|
|
}
|
|
|
|
ByteArrayOStreambuf::~ByteArrayOStreambuf()
|
|
{
|
|
_buffer->close();
|
|
delete _buffer;
|
|
}
|
|
|
|
std::streambuf::int_type ByteArrayOStreambuf::overflow(std::streambuf::int_type c)
|
|
{
|
|
if (c != EOF) {
|
|
char z = static_cast<char>(c);
|
|
if (_buffer->write(&z, 1) != 1) {
|
|
return EOF;
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
std::streamsize ByteArrayOStreambuf::xsputn(const char* s, std::streamsize num)
|
|
{
|
|
return _buffer->write(s, num);
|
|
}
|
|
|
|
std::streambuf::pos_type ByteArrayOStreambuf::
|
|
seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*mode*/)
|
|
{
|
|
off_type endpos = 0;
|
|
off_type curpos = _buffer->pos();
|
|
switch (way) {
|
|
case std::ios_base::beg:
|
|
endpos = off;
|
|
break;
|
|
case std::ios_base::cur:
|
|
endpos = curpos + off;
|
|
break;
|
|
case std::ios_base::end:
|
|
endpos = _buffer->size();
|
|
break;
|
|
default:
|
|
return {off_type(-1)};
|
|
}
|
|
|
|
if (endpos != curpos) {
|
|
if (!_buffer->seek(endpos)) {
|
|
endpos = -1;
|
|
}
|
|
}
|
|
|
|
return {endpos};
|
|
}
|
|
|
|
std::streambuf::pos_type ByteArrayOStreambuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode /*mode*/)
|
|
{
|
|
return seekoff(pos, std::ios_base::beg);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
ByteArrayIStreambuf::ByteArrayIStreambuf(const QByteArray& data)
|
|
: _buffer(data)
|
|
, _beg(0)
|
|
, _end(data.size())
|
|
, _cur(0)
|
|
{}
|
|
|
|
ByteArrayIStreambuf::~ByteArrayIStreambuf() = default;
|
|
|
|
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::underflow()
|
|
{
|
|
if (_cur == _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur]) & 0x000000ff;
|
|
}
|
|
|
|
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::uflow()
|
|
{
|
|
if (_cur == _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur++]) & 0x000000ff;
|
|
}
|
|
|
|
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::pbackfail(int_type ch)
|
|
{
|
|
if (_cur == _beg || (ch != traits_type::eof() && ch != _buffer[_cur - 1])) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[--_cur]) & 0x000000ff;
|
|
}
|
|
|
|
std::streamsize ByteArrayIStreambuf::showmanyc()
|
|
{
|
|
return _end - _cur;
|
|
}
|
|
|
|
std::streambuf::pos_type ByteArrayIStreambuf::
|
|
seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*mode*/)
|
|
{
|
|
int p_pos = -1;
|
|
if (way == std::ios_base::beg) {
|
|
p_pos = _beg;
|
|
}
|
|
else if (way == std::ios_base::end) {
|
|
p_pos = _end;
|
|
}
|
|
else if (way == std::ios_base::cur) {
|
|
p_pos = _cur;
|
|
}
|
|
|
|
if (p_pos > _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
_cur = p_pos + off;
|
|
|
|
return ((p_pos + off) - _beg);
|
|
}
|
|
|
|
std::streambuf::pos_type ByteArrayIStreambuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode /*mode*/)
|
|
{
|
|
return seekoff(pos, std::ios_base::beg);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
IODeviceOStreambuf::IODeviceOStreambuf(QIODevice* dev)
|
|
: device(dev)
|
|
{}
|
|
|
|
IODeviceOStreambuf::~IODeviceOStreambuf() = default;
|
|
|
|
std::streambuf::int_type IODeviceOStreambuf::overflow(std::streambuf::int_type c)
|
|
{
|
|
if (c != EOF) {
|
|
char z = static_cast<char>(c);
|
|
if (device->write(&z, 1) != 1) {
|
|
return EOF;
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
std::streamsize IODeviceOStreambuf::xsputn(const char* s, std::streamsize num)
|
|
{
|
|
return device->write(s, num);
|
|
}
|
|
|
|
std::streambuf::pos_type IODeviceOStreambuf::
|
|
seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*mode*/)
|
|
{
|
|
off_type endpos = 0;
|
|
off_type curpos = device->pos();
|
|
switch (way) {
|
|
case std::ios_base::beg:
|
|
endpos = off;
|
|
break;
|
|
case std::ios_base::cur:
|
|
endpos = curpos + off;
|
|
break;
|
|
case std::ios_base::end:
|
|
endpos = device->size();
|
|
break;
|
|
default:
|
|
return {off_type(-1)};
|
|
}
|
|
|
|
if (endpos != curpos) {
|
|
if (!device->seek(endpos)) {
|
|
endpos = -1;
|
|
}
|
|
}
|
|
|
|
return {endpos};
|
|
}
|
|
|
|
std::streambuf::pos_type IODeviceOStreambuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode /*mode*/)
|
|
{
|
|
return seekoff(pos, std::ios_base::beg);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
IODeviceIStreambuf::IODeviceIStreambuf(QIODevice* dev)
|
|
: device(dev)
|
|
{
|
|
setg(
|
|
buffer + pbSize, // beginning of putback area
|
|
buffer + pbSize, // read position
|
|
buffer + pbSize
|
|
); // end position
|
|
}
|
|
|
|
IODeviceIStreambuf::~IODeviceIStreambuf() = default;
|
|
|
|
std::streambuf::int_type IODeviceIStreambuf::underflow()
|
|
{
|
|
#ifndef _MSC_VER
|
|
using std::memcpy;
|
|
#endif
|
|
|
|
// is read position before end of buffer?
|
|
if (gptr() < egptr()) {
|
|
return *gptr();
|
|
}
|
|
|
|
/* process size of putback area
|
|
* - use number of characters read
|
|
* - but at most size of putback area
|
|
*/
|
|
int numPutback {};
|
|
numPutback = gptr() - eback();
|
|
if (numPutback > pbSize) {
|
|
numPutback = pbSize;
|
|
}
|
|
|
|
/* copy up to pbSize characters previously read into
|
|
* the putback area
|
|
*/
|
|
memcpy(buffer + (pbSize - numPutback), gptr() - numPutback, numPutback);
|
|
|
|
// read at most bufSize new characters
|
|
int num {};
|
|
num = device->read(buffer + pbSize, bufSize);
|
|
if (num <= 0) {
|
|
// ERROR or EOF
|
|
return EOF;
|
|
}
|
|
|
|
// reset buffer pointers
|
|
setg(
|
|
buffer + (pbSize - numPutback), // beginning of putback area
|
|
buffer + pbSize, // read position
|
|
buffer + pbSize + num
|
|
); // end of buffer
|
|
|
|
// return next character
|
|
return *gptr();
|
|
}
|
|
|
|
std::streambuf::pos_type IODeviceIStreambuf::
|
|
seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*mode*/)
|
|
{
|
|
off_type endpos = 0;
|
|
off_type curpos = device->pos();
|
|
switch (way) {
|
|
case std::ios_base::beg:
|
|
endpos = off;
|
|
break;
|
|
case std::ios_base::cur:
|
|
endpos = curpos + off;
|
|
break;
|
|
case std::ios_base::end:
|
|
endpos = device->size();
|
|
break;
|
|
default:
|
|
return {off_type(-1)};
|
|
}
|
|
|
|
if (endpos != curpos) {
|
|
if (!device->seek(endpos)) {
|
|
endpos = -1;
|
|
}
|
|
}
|
|
|
|
return {endpos};
|
|
}
|
|
|
|
std::streambuf::pos_type IODeviceIStreambuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode /*mode*/)
|
|
{
|
|
return seekoff(pos, std::ios_base::beg);
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
#define PYSTREAM_BUFFERED
|
|
|
|
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
|
|
// 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)
|
|
, put_back(std::max(put_back, std::size_t(1)))
|
|
, buffer(std::max(buf_size, put_back) + put_back)
|
|
{
|
|
Py_INCREF(inp);
|
|
char* end = &buffer.front() + buffer.size();
|
|
setg(end, end, end);
|
|
#ifdef PYSTREAM_BUFFERED
|
|
char* base = &buffer.front();
|
|
setp(base, base + buffer.size());
|
|
#endif
|
|
}
|
|
|
|
PyStreambuf::~PyStreambuf()
|
|
{
|
|
PyStreambuf::sync();
|
|
Py_DECREF(inp);
|
|
}
|
|
|
|
PyStreambuf::int_type PyStreambuf::underflow()
|
|
{
|
|
if (gptr() < egptr()) {
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
char* base = &buffer.front();
|
|
char* start = base;
|
|
|
|
if (eback() == base) { // true when this isn't the first fill
|
|
std::memmove(base, egptr() - put_back, put_back);
|
|
start += put_back;
|
|
}
|
|
|
|
std::size_t n {};
|
|
Py::Tuple arg(1);
|
|
long len = static_cast<long>(buffer.size() - (start - base));
|
|
arg.setItem(0, Py::Long(len));
|
|
Py::Callable meth(Py::Object(inp).getAttr("read"));
|
|
|
|
try {
|
|
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();
|
|
}
|
|
|
|
// Check: bugprone-not-null-terminated-result
|
|
std::memcpy(start, c.data(), c.size());
|
|
}
|
|
catch (Py::Exception& e) {
|
|
e.clear();
|
|
return traits_type::eof();
|
|
}
|
|
|
|
setg(base, start, start + n);
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
PyStreambuf::int_type PyStreambuf::overflow(PyStreambuf::int_type ch)
|
|
{
|
|
#ifdef PYSTREAM_BUFFERED
|
|
sync();
|
|
if (ch != traits_type::eof()) {
|
|
*pptr() = static_cast<char>(ch);
|
|
pbump(1);
|
|
return ch;
|
|
}
|
|
|
|
return traits_type::eof();
|
|
#else
|
|
if (ch != EOF) {
|
|
char z = ch;
|
|
if (!writeStr(&z, 1)) {
|
|
return traits_type::eof();
|
|
}
|
|
}
|
|
|
|
return ch;
|
|
#endif
|
|
}
|
|
|
|
int PyStreambuf::sync()
|
|
{
|
|
#ifdef PYSTREAM_BUFFERED
|
|
if (pptr() > pbase()) {
|
|
flushBuffer();
|
|
}
|
|
return 0;
|
|
#else
|
|
return std::streambuf::sync();
|
|
#endif
|
|
}
|
|
|
|
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);
|
|
Py::Callable meth(Py::Object(inp).getAttr("write"));
|
|
|
|
if (type == StringIO) {
|
|
arg.setItem(0, Py::String(str, num));
|
|
meth.apply(arg);
|
|
return true;
|
|
}
|
|
if (type == BytesIO) {
|
|
arg.setItem(0, Py::Bytes(str, num));
|
|
meth.apply(arg);
|
|
return true;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
throw; // re-throw
|
|
}
|
|
}
|
|
catch (Py::Exception& e) {
|
|
e.clear();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::streamsize PyStreambuf::xsputn(const char* s, std::streamsize num)
|
|
{
|
|
#ifdef PYSTREAM_BUFFERED
|
|
return std::streambuf::xsputn(s, num);
|
|
#else
|
|
if (!writeStr(s, num)) {
|
|
return 0;
|
|
}
|
|
return num;
|
|
#endif
|
|
}
|
|
|
|
PyStreambuf::pos_type PyStreambuf::
|
|
seekoff(PyStreambuf::off_type offset, PyStreambuf::seekdir dir, PyStreambuf::openmode /*mode*/)
|
|
{
|
|
int whence = 0;
|
|
switch (dir) {
|
|
case std::ios_base::beg:
|
|
whence = 0;
|
|
break;
|
|
case std::ios_base::cur:
|
|
whence = 1;
|
|
break;
|
|
case std::ios_base::end:
|
|
whence = 2;
|
|
break;
|
|
default:
|
|
return {off_type(-1)};
|
|
}
|
|
|
|
try {
|
|
Py::Tuple arg(2);
|
|
arg.setItem(0, Py::Long(static_cast<long>(offset)));
|
|
arg.setItem(1, Py::Long(whence));
|
|
Py::Callable seek(Py::Object(inp).getAttr("seek"));
|
|
seek.apply(arg);
|
|
|
|
// get current position
|
|
Py::Tuple arg2;
|
|
Py::Callable tell(Py::Object(inp).getAttr("tell"));
|
|
Py::Long pos(tell.apply(arg2));
|
|
long cur_pos = static_cast<long>(pos);
|
|
return static_cast<pos_type>(cur_pos);
|
|
}
|
|
catch (Py::Exception& e) {
|
|
e.clear();
|
|
return {off_type(-1)};
|
|
}
|
|
}
|
|
|
|
PyStreambuf::pos_type PyStreambuf::seekpos(PyStreambuf::pos_type offset, PyStreambuf::openmode mode)
|
|
{
|
|
return seekoff(offset, std::ios::beg, mode);
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
Streambuf::Streambuf(const std::string& data)
|
|
{
|
|
_beg = data.begin();
|
|
_end = data.end();
|
|
_cur = _beg; // NOLINT
|
|
}
|
|
|
|
Streambuf::~Streambuf() = default;
|
|
|
|
Streambuf::int_type Streambuf::underflow()
|
|
{
|
|
if (_cur == _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<Streambuf::int_type>(*_cur) & 0x000000ff;
|
|
}
|
|
|
|
Streambuf::int_type Streambuf::uflow()
|
|
{
|
|
if (_cur == _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<Streambuf::int_type>(*_cur++) & 0x000000ff;
|
|
}
|
|
|
|
Streambuf::int_type Streambuf::pbackfail(int_type ch)
|
|
{
|
|
/* coverity[negative_returns] _cur is an iterator */
|
|
if (_cur == _beg || (ch != traits_type::eof() && ch != _cur[-1])) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
return static_cast<Streambuf::int_type>(*--_cur) & 0x000000ff;
|
|
}
|
|
|
|
std::streamsize Streambuf::showmanyc()
|
|
{
|
|
return _end - _cur;
|
|
}
|
|
|
|
std::streambuf::pos_type Streambuf::
|
|
seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*mode*/)
|
|
{
|
|
std::string::const_iterator p_pos;
|
|
if (way == std::ios_base::beg) {
|
|
p_pos = _beg;
|
|
}
|
|
else if (way == std::ios_base::end) {
|
|
p_pos = _end;
|
|
}
|
|
else if (way == std::ios_base::cur) {
|
|
p_pos = _cur;
|
|
}
|
|
|
|
if (p_pos > _end) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
|
|
return traits_type::eof();
|
|
}
|
|
|
|
_cur = p_pos + off;
|
|
|
|
return ((p_pos + off) - _beg);
|
|
}
|
|
|
|
std::streambuf::pos_type Streambuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode /*mode*/)
|
|
{
|
|
return seekoff(pos, std::ios_base::beg);
|
|
}
|
|
|
|
// The custom string handler written by realthunder for the LinkStage3 toponaming code, to handle
|
|
// reading multi-line strings directly into a std::string. Imported from LinkStage3 and refactored
|
|
// during the TNP mitigation project in February 2024.
|
|
TextInputStream& TextInputStream::operator>>(std::string& outputString)
|
|
{
|
|
uint32_t numberOfLines;
|
|
char inputChar;
|
|
// The number of lines is followed by a colon as the delimiter. The string itself is then
|
|
// allowed to start with any character.
|
|
_in >> numberOfLines >> inputChar;
|
|
|
|
_ss.str("");
|
|
for (uint32_t lineNumber = 0; lineNumber < numberOfLines && _in; ++lineNumber) {
|
|
while (true) {
|
|
if (!_in.get(inputChar)) {
|
|
break;
|
|
}
|
|
// Normalize \r\n to \n
|
|
if (inputChar == '\r') {
|
|
if (!_in.get(inputChar)) {
|
|
break;
|
|
}
|
|
if (inputChar == '\n') {
|
|
break;
|
|
}
|
|
_ss.put('\r');
|
|
_ss.put(inputChar);
|
|
}
|
|
else {
|
|
_ss.put(inputChar);
|
|
if (inputChar == '\n') {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reading the last line
|
|
while (_in.get(inputChar)) {
|
|
// Normalize \r\n to \n, but DO NOT insert '\n' into the extracted
|
|
// line, because the last '\n' is inserted by us (See OutputStream
|
|
// operator>>(const char*) above)
|
|
if (inputChar == '\r') {
|
|
if (!_in.get(inputChar)) {
|
|
break;
|
|
}
|
|
if (inputChar == '\n') {
|
|
break;
|
|
}
|
|
_ss.put('\r');
|
|
}
|
|
else if (inputChar == '\n') {
|
|
break;
|
|
}
|
|
|
|
_ss.put(inputChar);
|
|
}
|
|
|
|
outputString = _ss.str();
|
|
return *this;
|
|
}
|