Files
create/src/Base/Stream.h
Benjamin Bræstrup Sayoc dda05369c4 Base: remove unneeded includes
2025-02-18 11:07:57 -06:00

634 lines
19 KiB
C++

/***************************************************************************
* 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 *
* *
***************************************************************************/
#ifndef BASE_STREAM_H
#define BASE_STREAM_H
#ifdef __GNUC__
#include <cstdint>
#endif
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include "FileInfo.h"
class QByteArray;
class QIODevice;
class QBuffer;
using PyObject = struct _object;
namespace Base
{
class BaseExport Stream
{
public:
enum ByteOrder
{
BigEndian,
LittleEndian
};
ByteOrder byteOrder() const;
void setByteOrder(ByteOrder);
virtual ~Stream();
protected:
Stream();
Stream(const Stream&) = default;
Stream(Stream&&) = default;
Stream& operator=(const Stream&) = default;
Stream& operator=(Stream&&) = default;
bool isSwapped() const
{
return _swap;
};
private:
bool _swap {false};
};
/**
* The OutputStream class provides writing of binary data to an ostream.
* @author Werner Mayer
*/
class BaseExport OutputStream: public Stream
{
public:
explicit OutputStream(std::ostream& rout);
~OutputStream() override;
OutputStream& operator<<(bool b);
OutputStream& operator<<(int8_t ch);
OutputStream& operator<<(uint8_t uch);
OutputStream& operator<<(int16_t s);
OutputStream& operator<<(uint16_t us);
OutputStream& operator<<(int32_t i);
OutputStream& operator<<(uint32_t ui);
OutputStream& operator<<(int64_t l);
OutputStream& operator<<(uint64_t ul);
OutputStream& operator<<(float f);
OutputStream& operator<<(double d);
OutputStream& write(const char* s, int n);
OutputStream(const OutputStream&) = delete;
OutputStream(OutputStream&&) = delete;
void operator=(const OutputStream&) = delete;
void operator=(OutputStream&&) = delete;
private:
std::ostream& _out;
};
/**
* The InputStream class provides reading of binary data from an istream.
* @author Werner Mayer
*/
class BaseExport InputStream: public Stream
{
public:
explicit InputStream(std::istream& rin);
~InputStream() override;
InputStream& operator>>(bool& b);
InputStream& operator>>(int8_t& ch);
InputStream& operator>>(uint8_t& uch);
InputStream& operator>>(int16_t& s);
InputStream& operator>>(uint16_t& us);
InputStream& operator>>(int32_t& i);
InputStream& operator>>(uint32_t& ui);
InputStream& operator>>(int64_t& l);
InputStream& operator>>(uint64_t& ul);
InputStream& operator>>(float& f);
InputStream& operator>>(double& d);
InputStream& read(char* s, int n);
explicit operator bool() const
{
// test if _Ipfx succeeded
return !_in.eof();
}
InputStream(const InputStream&) = delete;
InputStream(InputStream&&) = delete;
void operator=(const InputStream&) = delete;
void operator=(InputStream&&) = delete;
private:
std::istream& _in;
};
/**
* The TextInputStream class provides reading of ASCII data from an istream, with custom handling
* for std::string to make it easier to read a single multi-line (or multi-word) string. This is
* designed for easy compatibility with the LinkStage3 implementation of the InputStream class, used
* to store StringHashers for the toponaming mitigation technique.
*/
class BaseExport TextInputStream: public Stream
{
public:
/** Constructor
* @param rin: upstream input
*/
explicit TextInputStream(std::istream& rin)
: _in(rin)
{}
TextInputStream(const TextInputStream&) = delete;
TextInputStream(const TextInputStream&&) noexcept = delete;
void operator=(const TextInputStream&) = delete;
void operator=(const TextInputStream&&) = delete;
~TextInputStream() override = default;
TextInputStream& operator>>(bool& input)
{
_in >> input;
return *this;
}
TextInputStream& operator>>(int8_t& ch)
{
int index {};
_in >> index;
ch = (int8_t)index;
return *this;
}
TextInputStream& operator>>(uint8_t& uch)
{
unsigned uns {};
_in >> uns;
uch = (uint8_t)uns;
return *this;
}
TextInputStream& operator>>(int16_t& int16)
{
_in >> int16;
return *this;
}
TextInputStream& operator>>(uint16_t& us)
{
_in >> us;
return *this;
}
TextInputStream& operator>>(int32_t& int32)
{
_in >> int32;
return *this;
}
TextInputStream& operator>>(uint32_t& ui)
{
_in >> ui;
return *this;
}
TextInputStream& operator>>(int64_t& int64)
{
_in >> int64;
return *this;
}
TextInputStream& operator>>(uint64_t& ul)
{
_in >> ul;
return *this;
}
TextInputStream& operator>>(float& flt)
{
_in >> flt;
return *this;
}
TextInputStream& operator>>(double& dbl)
{
_in >> dbl;
return *this;
}
TextInputStream& operator>>(std::string& str);
TextInputStream& operator>>(char& chr)
{
chr = (char)_in.get();
return *this;
}
explicit operator bool() const
{
// test if _Ipfx succeeded
return !_in.eof();
}
private:
std::istream& _in;
std::ostringstream _ss;
};
/**
* The TextOutputStream class provides writing of ASCII data to an ostream, with custom handling
* for std::string to make it easier to write a single multi-line (or multi-word) string. This is
* designed for easy compatibility with the LinkStage3 implementation of the OutputStream class,
* used to store StringHashers for the toponaming mitigation technique.
*/
class BaseExport TextOutputStream: public Stream
{
public:
/** Constructor
* @param rout: upstream output
*/
explicit TextOutputStream(std::ostream& rout)
: _out(rout)
{}
TextOutputStream(const TextOutputStream&) = delete;
TextOutputStream(const TextOutputStream&&) noexcept = delete;
void operator=(const TextOutputStream&) = delete;
void operator=(const TextOutputStream&&) = delete;
~TextOutputStream() override = default;
template<typename T>
TextOutputStream& operator<<(T object)
{
_out << object << '\n';
return *this;
}
TextOutputStream& operator<<(const char* object)
{
std::string_view str(object);
// Count the lines so that we can deal with potential EOL conversions by external software
uint32_t lineCount = 0;
for (const auto character : str) {
if (character == '\n') {
++lineCount;
}
}
// Stores the line count followed by a colon as the delimiter. We don't use
// whitespace because the input stream may also start with whitespace.
_out << lineCount << ':';
// Store the text, and normalize the end of line to a single '\n'.
bool foundSlashR = false;
for (const auto character : str) {
if (character == '\r') {
foundSlashR = true;
continue;
}
if (foundSlashR) {
if (character != '\n') {
// We allow '\r' if it is not at the end of a line
_out.put('\r');
}
foundSlashR = false; // Reset for next time
}
_out.put(character);
}
// Add an extra newline as the delimiter for the following data.
_out.put('\n');
return *this;
}
TextOutputStream& operator<<(const std::string& object)
{
return (*this) << object.c_str();
}
TextOutputStream& operator<<(char object)
{
_out.put(object);
return *this;
}
explicit operator bool() const
{
// test if _Ipfx succeeded
return !_out.eof();
}
private:
std::ostream& _out;
};
// ----------------------------------------------------------------------------
/**
* This class implements the streambuf interface to write data to a QByteArray.
* This class can only be used for writing but not for reading purposes.
* @author Werner Mayer
*/
class BaseExport ByteArrayOStreambuf: public std::streambuf
{
public:
explicit ByteArrayOStreambuf(QByteArray& ba);
~ByteArrayOStreambuf() override;
protected:
int_type overflow(std::streambuf::int_type c) override;
std::streamsize xsputn(const char* s, std::streamsize num) override;
pos_type seekoff(std::streambuf::off_type off,
std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
pos_type seekpos(std::streambuf::pos_type pos,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
public:
ByteArrayOStreambuf(const ByteArrayOStreambuf&) = delete;
ByteArrayOStreambuf(ByteArrayOStreambuf&&) = delete;
ByteArrayOStreambuf& operator=(const ByteArrayOStreambuf&) = delete;
ByteArrayOStreambuf& operator=(ByteArrayOStreambuf&&) = delete;
private:
QBuffer* _buffer;
};
/**
* This class implements the streambuf interface to read data from a QByteArray.
* This class can only be used for reading but not for writing purposes.
* @author Werner Mayer
*/
class BaseExport ByteArrayIStreambuf: public std::streambuf
{
public:
explicit ByteArrayIStreambuf(const QByteArray& data);
~ByteArrayIStreambuf() override;
protected:
int_type uflow() override;
int_type underflow() override;
int_type pbackfail(int_type ch) override;
std::streamsize showmanyc() override;
pos_type seekoff(std::streambuf::off_type off,
std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
pos_type seekpos(std::streambuf::pos_type pos,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
public:
ByteArrayIStreambuf(const ByteArrayIStreambuf&) = delete;
ByteArrayIStreambuf(ByteArrayIStreambuf&&) = delete;
ByteArrayIStreambuf& operator=(const ByteArrayIStreambuf&) = delete;
ByteArrayIStreambuf& operator=(ByteArrayIStreambuf&&) = delete;
private:
const QByteArray& _buffer;
int _beg, _end, _cur;
};
/**
* Simple class to write data directly into Qt's QIODevice.
* This class can only be used for writing but not reading purposes.
* @author Werner Mayer
*/
class BaseExport IODeviceOStreambuf: public std::streambuf
{
public:
explicit IODeviceOStreambuf(QIODevice* dev);
~IODeviceOStreambuf() override;
protected:
int_type overflow(std::streambuf::int_type c) override;
std::streamsize xsputn(const char* s, std::streamsize num) override;
pos_type seekoff(std::streambuf::off_type off,
std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
pos_type seekpos(std::streambuf::pos_type pos,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
public:
IODeviceOStreambuf(const IODeviceOStreambuf&) = delete;
IODeviceOStreambuf(IODeviceOStreambuf&&) = delete;
IODeviceOStreambuf& operator=(const IODeviceOStreambuf&) = delete;
IODeviceOStreambuf& operator=(IODeviceOStreambuf&&) = delete;
private:
QIODevice* device;
};
/**
* Simple class to read data directly from Qt's QIODevice.
* This class can only be used for readihg but not writing purposes.
* @author Werner Mayer
*/
class BaseExport IODeviceIStreambuf: public std::streambuf
{
public:
explicit IODeviceIStreambuf(QIODevice* dev);
~IODeviceIStreambuf() override;
protected:
int_type underflow() override;
pos_type seekoff(std::streambuf::off_type off,
std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
pos_type seekpos(std::streambuf::pos_type pos,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
public:
IODeviceIStreambuf(const IODeviceIStreambuf&) = delete;
IODeviceIStreambuf(IODeviceIStreambuf&&) = delete;
IODeviceIStreambuf& operator=(const IODeviceIStreambuf&) = delete;
IODeviceIStreambuf& operator=(IODeviceIStreambuf&&) = delete;
private:
QIODevice* device;
/* data buffer:
* - at most, pbSize characters in putback area plus
* - at most, bufSize characters in ordinary read buffer
*/
static const int pbSize = 4; // size of putback area
static const int bufSize = 1024; // size of the data buffer
char buffer[bufSize + pbSize] {}; // data buffer
};
class BaseExport PyStreambuf: public std::streambuf
{
using int_type = std::streambuf::int_type;
using pos_type = std::streambuf::pos_type;
using off_type = std::streambuf::off_type;
using seekdir = std::ios::seekdir;
using openmode = std::ios::openmode;
public:
enum Type
{
StringIO,
BytesIO,
Unknown
};
explicit PyStreambuf(PyObject* o, std::size_t buf_size = 256, std::size_t put_back = 8);
~PyStreambuf() override;
void setType(Type t)
{
type = t;
}
protected:
int_type underflow() override;
int_type overflow(int_type c = EOF) override;
std::streamsize xsputn(const char* s, std::streamsize num) override;
int sync() override;
pos_type seekoff(off_type offset, seekdir dir, openmode mode) override;
pos_type seekpos(pos_type offset, openmode mode) override;
private:
bool flushBuffer();
bool writeStr(const char* s, std::streamsize num);
public:
PyStreambuf(const PyStreambuf&) = delete;
PyStreambuf(PyStreambuf&&) = delete;
PyStreambuf& operator=(const PyStreambuf&) = delete;
PyStreambuf& operator=(PyStreambuf&&) = delete;
private:
PyObject* inp;
Type type {Unknown};
const std::size_t put_back;
std::vector<char> buffer;
};
class BaseExport Streambuf: public std::streambuf
{
public:
explicit Streambuf(const std::string& data);
~Streambuf() override;
protected:
int_type uflow() override;
int_type underflow() override;
int_type pbackfail(int_type ch) override;
std::streamsize showmanyc() override;
pos_type seekoff(std::streambuf::off_type off,
std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
pos_type seekpos(std::streambuf::pos_type pos,
std::ios_base::openmode which = std::ios::in | std::ios::out) override;
public:
Streambuf(const Streambuf&) = delete;
Streambuf(Streambuf&&) = delete;
Streambuf& operator=(const Streambuf&) = delete;
Streambuf& operator=(Streambuf&&) = delete;
private:
std::string::const_iterator _beg;
std::string::const_iterator _end;
std::string::const_iterator _cur;
};
// ----------------------------------------------------------------------------
class FileInfo;
/**
* The ofstream class is provided for convenience. On Windows
* platforms it opens a stream with UCS-2 encoded file name
* while on Linux platforms the file name is UTF-8 encoded.
* @author Werner Mayer
*/
class ofstream: public std::ofstream
{
public:
ofstream() = default;
ofstream(const ofstream&) = delete;
ofstream(ofstream&&) = delete;
explicit ofstream(const FileInfo& fi, ios_base::openmode mode = std::ios::out | std::ios::trunc)
#ifdef _MSC_VER
: std::ofstream(fi.toStdWString().c_str(), mode) {}
#else
: std::ofstream(fi.filePath().c_str(), mode)
{}
#endif
~ofstream() override = default;
void open(const FileInfo& fi, ios_base::openmode mode = std::ios::out | std::ios::trunc)
{
#ifdef _MSC_VER
std::ofstream::open(fi.toStdWString().c_str(), mode);
#else
std::ofstream::open(fi.filePath().c_str(), mode);
#endif
}
ofstream& operator=(const ofstream&) = delete;
ofstream& operator=(ofstream&&) = delete;
};
/**
* The ofstream class is provided for convenience. On Windows
* platforms it opens a stream with UCS-2 encoded file name
* while on Linux platforms the file name is UTF-8 encoded.
* @author Werner Mayer
*/
class ifstream: public std::ifstream
{
public:
ifstream() = default;
ifstream(const ifstream&) = delete;
ifstream(ifstream&&) = delete;
explicit ifstream(const FileInfo& fi, ios_base::openmode mode = std::ios::in)
#ifdef _MSC_VER
: std::ifstream(fi.toStdWString().c_str(), mode) {}
#else
: std::ifstream(fi.filePath().c_str(), mode)
{}
#endif
~ifstream() override = default;
void open(const FileInfo& fi, ios_base::openmode mode = std::ios::in)
{
#ifdef _MSC_VER
std::ifstream::open(fi.toStdWString().c_str(), mode);
#else
std::ifstream::open(fi.filePath().c_str(), mode);
#endif
}
ifstream& operator=(const ifstream&) = delete;
ifstream& operator=(ifstream&&) = delete;
};
} // namespace Base
#endif // BASE_STREAM_H