1
/***************************************************************************
2
* Copyright (c) 2007 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
38
#include <CXX/Objects.hxx>
43
Stream::Stream() = default;
45
Stream::~Stream() = default;
47
Stream::ByteOrder Stream::byteOrder() const
49
return _swap ? BigEndian : LittleEndian;
52
void Stream::setByteOrder(ByteOrder bo)
54
_swap = (bo == BigEndian);
57
OutputStream::OutputStream(std::ostream& rout)
61
OutputStream::~OutputStream() = default;
63
OutputStream& OutputStream::operator<<(bool b)
65
_out.write((const char*)&b, sizeof(bool));
69
OutputStream& OutputStream::operator<<(int8_t ch)
71
_out.write((const char*)&ch, sizeof(int8_t));
75
OutputStream& OutputStream::operator<<(uint8_t uch)
77
_out.write((const char*)&uch, sizeof(uint8_t));
81
OutputStream& OutputStream::operator<<(int16_t s)
84
SwapEndian<int16_t>(s);
86
_out.write((const char*)&s, sizeof(int16_t));
90
OutputStream& OutputStream::operator<<(uint16_t us)
93
SwapEndian<uint16_t>(us);
95
_out.write((const char*)&us, sizeof(uint16_t));
99
OutputStream& OutputStream::operator<<(int32_t i)
102
SwapEndian<int32_t>(i);
104
_out.write((const char*)&i, sizeof(int32_t));
108
OutputStream& OutputStream::operator<<(uint32_t ui)
111
SwapEndian<uint32_t>(ui);
113
_out.write((const char*)&ui, sizeof(uint32_t));
117
OutputStream& OutputStream::operator<<(int64_t l)
120
SwapEndian<int64_t>(l);
122
_out.write((const char*)&l, sizeof(int64_t));
126
OutputStream& OutputStream::operator<<(uint64_t ul)
129
SwapEndian<uint64_t>(ul);
131
_out.write((const char*)&ul, sizeof(uint64_t));
135
OutputStream& OutputStream::operator<<(float f)
138
SwapEndian<float>(f);
140
_out.write((const char*)&f, sizeof(float));
144
OutputStream& OutputStream::operator<<(double d)
147
SwapEndian<double>(d);
149
_out.write((const char*)&d, sizeof(double));
153
InputStream::InputStream(std::istream& rin)
157
InputStream::~InputStream() = default;
159
InputStream& InputStream::operator>>(bool& b)
161
_in.read((char*)&b, sizeof(bool));
165
InputStream& InputStream::operator>>(int8_t& ch)
167
_in.read((char*)&ch, sizeof(int8_t));
171
InputStream& InputStream::operator>>(uint8_t& uch)
173
_in.read((char*)&uch, sizeof(uint8_t));
177
InputStream& InputStream::operator>>(int16_t& s)
179
_in.read((char*)&s, sizeof(int16_t));
181
SwapEndian<int16_t>(s);
186
InputStream& InputStream::operator>>(uint16_t& us)
188
_in.read((char*)&us, sizeof(uint16_t));
190
SwapEndian<uint16_t>(us);
195
InputStream& InputStream::operator>>(int32_t& i)
197
_in.read((char*)&i, sizeof(int32_t));
199
SwapEndian<int32_t>(i);
204
InputStream& InputStream::operator>>(uint32_t& ui)
206
_in.read((char*)&ui, sizeof(uint32_t));
208
SwapEndian<uint32_t>(ui);
213
InputStream& InputStream::operator>>(int64_t& l)
215
_in.read((char*)&l, sizeof(int64_t));
217
SwapEndian<int64_t>(l);
222
InputStream& InputStream::operator>>(uint64_t& ul)
224
_in.read((char*)&ul, sizeof(uint64_t));
226
SwapEndian<uint64_t>(ul);
231
InputStream& InputStream::operator>>(float& f)
233
_in.read((char*)&f, sizeof(float));
235
SwapEndian<float>(f);
240
InputStream& InputStream::operator>>(double& d)
242
_in.read((char*)&d, sizeof(double));
244
SwapEndian<double>(d);
249
// ----------------------------------------------------------------------
251
ByteArrayOStreambuf::ByteArrayOStreambuf(QByteArray& ba)
252
: _buffer(new QBuffer(&ba))
254
_buffer->open(QIODevice::WriteOnly);
257
ByteArrayOStreambuf::~ByteArrayOStreambuf()
263
std::streambuf::int_type ByteArrayOStreambuf::overflow(std::streambuf::int_type c)
266
char z = static_cast<char>(c);
267
if (_buffer->write(&z, 1) != 1) {
274
std::streamsize ByteArrayOStreambuf::xsputn(const char* s, std::streamsize num)
276
return _buffer->write(s, num);
279
std::streambuf::pos_type ByteArrayOStreambuf::seekoff(std::streambuf::off_type off,
280
std::ios_base::seekdir way,
281
std::ios_base::openmode /*mode*/)
284
off_type curpos = _buffer->pos();
286
case std::ios_base::beg:
289
case std::ios_base::cur:
290
endpos = curpos + off;
292
case std::ios_base::end:
293
endpos = _buffer->size();
296
return {off_type(-1)};
299
if (endpos != curpos) {
300
if (!_buffer->seek(endpos)) {
308
std::streambuf::pos_type ByteArrayOStreambuf::seekpos(std::streambuf::pos_type pos,
309
std::ios_base::openmode /*mode*/)
311
return seekoff(pos, std::ios_base::beg);
314
// ----------------------------------------------------------------------
316
ByteArrayIStreambuf::ByteArrayIStreambuf(const QByteArray& data)
323
ByteArrayIStreambuf::~ByteArrayIStreambuf() = default;
325
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::underflow()
328
return traits_type::eof();
331
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur]) & 0x000000ff;
334
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::uflow()
337
return traits_type::eof();
340
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur++]) & 0x000000ff;
343
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::pbackfail(int_type ch)
345
if (_cur == _beg || (ch != traits_type::eof() && ch != _buffer[_cur - 1])) {
346
return traits_type::eof();
349
return static_cast<ByteArrayIStreambuf::int_type>(_buffer[--_cur]) & 0x000000ff;
352
std::streamsize ByteArrayIStreambuf::showmanyc()
357
std::streambuf::pos_type ByteArrayIStreambuf::seekoff(std::streambuf::off_type off,
358
std::ios_base::seekdir way,
359
std::ios_base::openmode /*mode*/)
362
if (way == std::ios_base::beg) {
365
else if (way == std::ios_base::end) {
368
else if (way == std::ios_base::cur) {
373
return traits_type::eof();
376
if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
377
return traits_type::eof();
382
return ((p_pos + off) - _beg);
385
std::streambuf::pos_type ByteArrayIStreambuf::seekpos(std::streambuf::pos_type pos,
386
std::ios_base::openmode /*mode*/)
388
return seekoff(pos, std::ios_base::beg);
391
// ----------------------------------------------------------------------
393
IODeviceOStreambuf::IODeviceOStreambuf(QIODevice* dev)
397
IODeviceOStreambuf::~IODeviceOStreambuf() = default;
399
std::streambuf::int_type IODeviceOStreambuf::overflow(std::streambuf::int_type c)
402
char z = static_cast<char>(c);
403
if (device->write(&z, 1) != 1) {
410
std::streamsize IODeviceOStreambuf::xsputn(const char* s, std::streamsize num)
412
return device->write(s, num);
415
std::streambuf::pos_type IODeviceOStreambuf::seekoff(std::streambuf::off_type off,
416
std::ios_base::seekdir way,
417
std::ios_base::openmode /*mode*/)
420
off_type curpos = device->pos();
422
case std::ios_base::beg:
425
case std::ios_base::cur:
426
endpos = curpos + off;
428
case std::ios_base::end:
429
endpos = device->size();
432
return {off_type(-1)};
435
if (endpos != curpos) {
436
if (!device->seek(endpos)) {
444
std::streambuf::pos_type IODeviceOStreambuf::seekpos(std::streambuf::pos_type pos,
445
std::ios_base::openmode /*mode*/)
447
return seekoff(pos, std::ios_base::beg);
450
// ----------------------------------------------------------------------
452
IODeviceIStreambuf::IODeviceIStreambuf(QIODevice* dev)
455
setg(buffer + pbSize, // beginning of putback area
456
buffer + pbSize, // read position
457
buffer + pbSize); // end position
460
IODeviceIStreambuf::~IODeviceIStreambuf() = default;
462
std::streambuf::int_type IODeviceIStreambuf::underflow()
468
// is read position before end of buffer?
469
if (gptr() < egptr()) {
473
/* process size of putback area
474
* - use number of characters read
475
* - but at most size of putback area
478
numPutback = gptr() - eback();
479
if (numPutback > pbSize) {
483
/* copy up to pbSize characters previously read into
486
memcpy(buffer + (pbSize - numPutback), gptr() - numPutback, numPutback);
488
// read at most bufSize new characters
490
num = device->read(buffer + pbSize, bufSize);
496
// reset buffer pointers
497
setg(buffer + (pbSize - numPutback), // beginning of putback area
498
buffer + pbSize, // read position
499
buffer + pbSize + num); // end of buffer
501
// return next character
505
std::streambuf::pos_type IODeviceIStreambuf::seekoff(std::streambuf::off_type off,
506
std::ios_base::seekdir way,
507
std::ios_base::openmode /*mode*/)
510
off_type curpos = device->pos();
512
case std::ios_base::beg:
515
case std::ios_base::cur:
516
endpos = curpos + off;
518
case std::ios_base::end:
519
endpos = device->size();
522
return {off_type(-1)};
525
if (endpos != curpos) {
526
if (!device->seek(endpos)) {
534
std::streambuf::pos_type IODeviceIStreambuf::seekpos(std::streambuf::pos_type pos,
535
std::ios_base::openmode /*mode*/)
537
return seekoff(pos, std::ios_base::beg);
540
// ---------------------------------------------------------
542
#define PYSTREAM_BUFFERED
544
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
545
// http://www.icce.rug.nl/documents/cplusplus/cplusplus24.html
546
PyStreambuf::PyStreambuf(PyObject* o, std::size_t buf_size, std::size_t put_back)
548
, put_back(std::max(put_back, std::size_t(1)))
549
, buffer(std::max(buf_size, put_back) + put_back)
552
char* end = &buffer.front() + buffer.size();
554
#ifdef PYSTREAM_BUFFERED
555
char* base = &buffer.front();
556
setp(base, base + buffer.size());
560
PyStreambuf::~PyStreambuf()
566
PyStreambuf::int_type PyStreambuf::underflow()
568
if (gptr() < egptr()) {
569
return traits_type::to_int_type(*gptr());
572
char* base = &buffer.front();
575
if (eback() == base) { // true when this isn't the first fill
576
std::memmove(base, egptr() - put_back, put_back);
582
long len = static_cast<long>(buffer.size() - (start - base));
583
arg.setItem(0, Py::Long(len));
584
Py::Callable meth(Py::Object(inp).getAttr("read"));
588
Py::Object res(meth.apply(arg));
590
c = static_cast<std::string>(Py::Bytes(res));
592
else if (res.isString()) {
593
c = static_cast<std::string>(Py::String(res));
597
return traits_type::eof();
602
return traits_type::eof();
605
// Check: bugprone-not-null-terminated-result
606
std::memcpy(start, c.data(), c.size());
608
catch (Py::Exception& e) {
610
return traits_type::eof();
613
setg(base, start, start + n);
614
return traits_type::to_int_type(*gptr());
617
PyStreambuf::int_type PyStreambuf::overflow(PyStreambuf::int_type ch)
619
#ifdef PYSTREAM_BUFFERED
621
if (ch != traits_type::eof()) {
622
*pptr() = static_cast<char>(ch);
627
return traits_type::eof();
631
if (!writeStr(&z, 1)) {
632
return traits_type::eof();
640
int PyStreambuf::sync()
642
#ifdef PYSTREAM_BUFFERED
643
if (pptr() > pbase()) {
648
return std::streambuf::sync();
652
bool PyStreambuf::flushBuffer()
654
std::ptrdiff_t n = pptr() - pbase();
656
return writeStr(pbase(), n);
659
bool PyStreambuf::writeStr(const char* str, std::streamsize num)
663
Py::Callable meth(Py::Object(inp).getAttr("write"));
665
if (type == StringIO) {
666
arg.setItem(0, Py::String(str, num));
670
if (type == BytesIO) {
671
arg.setItem(0, Py::Bytes(str, num));
676
// try out what works
678
arg.setItem(0, Py::String(str, num));
683
catch (Py::Exception& e) {
684
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
686
arg.setItem(0, Py::Bytes(str, num));
695
catch (Py::Exception& e) {
702
std::streamsize PyStreambuf::xsputn(const char* s, std::streamsize num)
704
#ifdef PYSTREAM_BUFFERED
705
return std::streambuf::xsputn(s, num);
707
if (!writeStr(s, num)) {
714
PyStreambuf::pos_type PyStreambuf::seekoff(PyStreambuf::off_type offset,
715
PyStreambuf::seekdir dir,
716
PyStreambuf::openmode /*mode*/)
720
case std::ios_base::beg:
723
case std::ios_base::cur:
726
case std::ios_base::end:
730
return {off_type(-1)};
735
arg.setItem(0, Py::Long(static_cast<long>(offset)));
736
arg.setItem(1, Py::Long(whence));
737
Py::Callable seek(Py::Object(inp).getAttr("seek"));
740
// get current position
742
Py::Callable tell(Py::Object(inp).getAttr("tell"));
743
Py::Long pos(tell.apply(arg2));
744
long cur_pos = static_cast<long>(pos);
745
return static_cast<pos_type>(cur_pos);
747
catch (Py::Exception& e) {
749
return {off_type(-1)};
753
PyStreambuf::pos_type PyStreambuf::seekpos(PyStreambuf::pos_type offset, PyStreambuf::openmode mode)
755
return seekoff(offset, std::ios::beg, mode);
758
// ---------------------------------------------------------
760
Streambuf::Streambuf(const std::string& data)
764
_cur = _beg; // NOLINT
767
Streambuf::~Streambuf() = default;
769
Streambuf::int_type Streambuf::underflow()
772
return traits_type::eof();
775
return static_cast<Streambuf::int_type>(*_cur) & 0x000000ff;
778
Streambuf::int_type Streambuf::uflow()
781
return traits_type::eof();
784
return static_cast<Streambuf::int_type>(*_cur++) & 0x000000ff;
787
Streambuf::int_type Streambuf::pbackfail(int_type ch)
789
/* coverity[negative_returns] _cur is an iterator */
790
if (_cur == _beg || (ch != traits_type::eof() && ch != _cur[-1])) {
791
return traits_type::eof();
794
return static_cast<Streambuf::int_type>(*--_cur) & 0x000000ff;
797
std::streamsize Streambuf::showmanyc()
802
std::streambuf::pos_type Streambuf::seekoff(std::streambuf::off_type off,
803
std::ios_base::seekdir way,
804
std::ios_base::openmode /*mode*/)
806
std::string::const_iterator p_pos;
807
if (way == std::ios_base::beg) {
810
else if (way == std::ios_base::end) {
813
else if (way == std::ios_base::cur) {
818
return traits_type::eof();
821
if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
822
return traits_type::eof();
827
return ((p_pos + off) - _beg);
830
std::streambuf::pos_type Streambuf::seekpos(std::streambuf::pos_type pos,
831
std::ios_base::openmode /*mode*/)
833
return seekoff(pos, std::ios_base::beg);
836
// The custom string handler written by realthunder for the LinkStage3 toponaming code, to handle
837
// reading multi-line strings directly into a std::string. Imported from LinkStage3 and refactored
838
// during the TNP mitigation project in February 2024.
839
TextInputStream& TextInputStream::operator>>(std::string& outputString)
841
uint32_t numberOfLines;
843
// The number of lines is followed by a colon as the delimiter. The string itself is then
844
// allowed to start with any character.
845
_in >> numberOfLines >> inputChar;
848
for (uint32_t lineNumber = 0; lineNumber < numberOfLines && _in; ++lineNumber) {
850
if (!_in.get(inputChar)) {
853
// Normalize \r\n to \n
854
if (inputChar == '\r') {
855
if (!_in.get(inputChar)) {
858
if (inputChar == '\n') {
866
if (inputChar == '\n') {
873
// Reading the last line
874
while (_in.get(inputChar)) {
875
// Normalize \r\n to \n, but DO NOT insert '\n' into the extracted
876
// line, because the last '\n' is inserted by us (See OutputStream
877
// operator>>(const char*) above)
878
if (inputChar == '\r') {
879
if (!_in.get(inputChar)) {
882
if (inputChar == '\n') {
887
else if (inputChar == '\n') {
894
outputString = _ss.str();