FreeCAD

Форк
0
/
Stream.cpp 
896 строк · 22.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2007 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#ifndef _PreComp_
27
#include <QBuffer>
28
#include <QByteArray>
29
#include <QIODevice>
30
#include <cstring>
31
#ifdef __GNUC__
32
#include <cstdint>
33
#endif
34
#endif
35

36
#include "Stream.h"
37
#include "Swap.h"
38
#include <CXX/Objects.hxx>
39

40

41
using namespace Base;
42

43
Stream::Stream() = default;
44

45
Stream::~Stream() = default;
46

47
Stream::ByteOrder Stream::byteOrder() const
48
{
49
    return _swap ? BigEndian : LittleEndian;
50
}
51

52
void Stream::setByteOrder(ByteOrder bo)
53
{
54
    _swap = (bo == BigEndian);
55
}
56

57
OutputStream::OutputStream(std::ostream& rout)
58
    : _out(rout)
59
{}
60

61
OutputStream::~OutputStream() = default;
62

63
OutputStream& OutputStream::operator<<(bool b)
64
{
65
    _out.write((const char*)&b, sizeof(bool));
66
    return *this;
67
}
68

69
OutputStream& OutputStream::operator<<(int8_t ch)
70
{
71
    _out.write((const char*)&ch, sizeof(int8_t));
72
    return *this;
73
}
74

75
OutputStream& OutputStream::operator<<(uint8_t uch)
76
{
77
    _out.write((const char*)&uch, sizeof(uint8_t));
78
    return *this;
79
}
80

81
OutputStream& OutputStream::operator<<(int16_t s)
82
{
83
    if (isSwapped()) {
84
        SwapEndian<int16_t>(s);
85
    }
86
    _out.write((const char*)&s, sizeof(int16_t));
87
    return *this;
88
}
89

90
OutputStream& OutputStream::operator<<(uint16_t us)
91
{
92
    if (isSwapped()) {
93
        SwapEndian<uint16_t>(us);
94
    }
95
    _out.write((const char*)&us, sizeof(uint16_t));
96
    return *this;
97
}
98

99
OutputStream& OutputStream::operator<<(int32_t i)
100
{
101
    if (isSwapped()) {
102
        SwapEndian<int32_t>(i);
103
    }
104
    _out.write((const char*)&i, sizeof(int32_t));
105
    return *this;
106
}
107

108
OutputStream& OutputStream::operator<<(uint32_t ui)
109
{
110
    if (isSwapped()) {
111
        SwapEndian<uint32_t>(ui);
112
    }
113
    _out.write((const char*)&ui, sizeof(uint32_t));
114
    return *this;
115
}
116

117
OutputStream& OutputStream::operator<<(int64_t l)
118
{
119
    if (isSwapped()) {
120
        SwapEndian<int64_t>(l);
121
    }
122
    _out.write((const char*)&l, sizeof(int64_t));
123
    return *this;
124
}
125

126
OutputStream& OutputStream::operator<<(uint64_t ul)
127
{
128
    if (isSwapped()) {
129
        SwapEndian<uint64_t>(ul);
130
    }
131
    _out.write((const char*)&ul, sizeof(uint64_t));
132
    return *this;
133
}
134

135
OutputStream& OutputStream::operator<<(float f)
136
{
137
    if (isSwapped()) {
138
        SwapEndian<float>(f);
139
    }
140
    _out.write((const char*)&f, sizeof(float));
141
    return *this;
142
}
143

144
OutputStream& OutputStream::operator<<(double d)
145
{
146
    if (isSwapped()) {
147
        SwapEndian<double>(d);
148
    }
149
    _out.write((const char*)&d, sizeof(double));
150
    return *this;
151
}
152

153
InputStream::InputStream(std::istream& rin)
154
    : _in(rin)
155
{}
156

157
InputStream::~InputStream() = default;
158

159
InputStream& InputStream::operator>>(bool& b)
160
{
161
    _in.read((char*)&b, sizeof(bool));
162
    return *this;
163
}
164

165
InputStream& InputStream::operator>>(int8_t& ch)
166
{
167
    _in.read((char*)&ch, sizeof(int8_t));
168
    return *this;
169
}
170

171
InputStream& InputStream::operator>>(uint8_t& uch)
172
{
173
    _in.read((char*)&uch, sizeof(uint8_t));
174
    return *this;
175
}
176

177
InputStream& InputStream::operator>>(int16_t& s)
178
{
179
    _in.read((char*)&s, sizeof(int16_t));
180
    if (isSwapped()) {
181
        SwapEndian<int16_t>(s);
182
    }
183
    return *this;
184
}
185

186
InputStream& InputStream::operator>>(uint16_t& us)
187
{
188
    _in.read((char*)&us, sizeof(uint16_t));
189
    if (isSwapped()) {
190
        SwapEndian<uint16_t>(us);
191
    }
192
    return *this;
193
}
194

195
InputStream& InputStream::operator>>(int32_t& i)
196
{
197
    _in.read((char*)&i, sizeof(int32_t));
198
    if (isSwapped()) {
199
        SwapEndian<int32_t>(i);
200
    }
201
    return *this;
202
}
203

204
InputStream& InputStream::operator>>(uint32_t& ui)
205
{
206
    _in.read((char*)&ui, sizeof(uint32_t));
207
    if (isSwapped()) {
208
        SwapEndian<uint32_t>(ui);
209
    }
210
    return *this;
211
}
212

213
InputStream& InputStream::operator>>(int64_t& l)
214
{
215
    _in.read((char*)&l, sizeof(int64_t));
216
    if (isSwapped()) {
217
        SwapEndian<int64_t>(l);
218
    }
219
    return *this;
220
}
221

222
InputStream& InputStream::operator>>(uint64_t& ul)
223
{
224
    _in.read((char*)&ul, sizeof(uint64_t));
225
    if (isSwapped()) {
226
        SwapEndian<uint64_t>(ul);
227
    }
228
    return *this;
229
}
230

231
InputStream& InputStream::operator>>(float& f)
232
{
233
    _in.read((char*)&f, sizeof(float));
234
    if (isSwapped()) {
235
        SwapEndian<float>(f);
236
    }
237
    return *this;
238
}
239

240
InputStream& InputStream::operator>>(double& d)
241
{
242
    _in.read((char*)&d, sizeof(double));
243
    if (isSwapped()) {
244
        SwapEndian<double>(d);
245
    }
246
    return *this;
247
}
248

249
// ----------------------------------------------------------------------
250

251
ByteArrayOStreambuf::ByteArrayOStreambuf(QByteArray& ba)
252
    : _buffer(new QBuffer(&ba))
253
{
254
    _buffer->open(QIODevice::WriteOnly);
255
}
256

257
ByteArrayOStreambuf::~ByteArrayOStreambuf()
258
{
259
    _buffer->close();
260
    delete _buffer;
261
}
262

263
std::streambuf::int_type ByteArrayOStreambuf::overflow(std::streambuf::int_type c)
264
{
265
    if (c != EOF) {
266
        char z = static_cast<char>(c);
267
        if (_buffer->write(&z, 1) != 1) {
268
            return EOF;
269
        }
270
    }
271
    return c;
272
}
273

274
std::streamsize ByteArrayOStreambuf::xsputn(const char* s, std::streamsize num)
275
{
276
    return _buffer->write(s, num);
277
}
278

279
std::streambuf::pos_type ByteArrayOStreambuf::seekoff(std::streambuf::off_type off,
280
                                                      std::ios_base::seekdir way,
281
                                                      std::ios_base::openmode /*mode*/)
282
{
283
    off_type endpos = 0;
284
    off_type curpos = _buffer->pos();
285
    switch (way) {
286
        case std::ios_base::beg:
287
            endpos = off;
288
            break;
289
        case std::ios_base::cur:
290
            endpos = curpos + off;
291
            break;
292
        case std::ios_base::end:
293
            endpos = _buffer->size();
294
            break;
295
        default:
296
            return {off_type(-1)};
297
    }
298

299
    if (endpos != curpos) {
300
        if (!_buffer->seek(endpos)) {
301
            endpos = -1;
302
        }
303
    }
304

305
    return {endpos};
306
}
307

308
std::streambuf::pos_type ByteArrayOStreambuf::seekpos(std::streambuf::pos_type pos,
309
                                                      std::ios_base::openmode /*mode*/)
310
{
311
    return seekoff(pos, std::ios_base::beg);
312
}
313

314
// ----------------------------------------------------------------------
315

316
ByteArrayIStreambuf::ByteArrayIStreambuf(const QByteArray& data)
317
    : _buffer(data)
318
    , _beg(0)
319
    , _end(data.size())
320
    , _cur(0)
321
{}
322

323
ByteArrayIStreambuf::~ByteArrayIStreambuf() = default;
324

325
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::underflow()
326
{
327
    if (_cur == _end) {
328
        return traits_type::eof();
329
    }
330

331
    return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur]) & 0x000000ff;
332
}
333

334
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::uflow()
335
{
336
    if (_cur == _end) {
337
        return traits_type::eof();
338
    }
339

340
    return static_cast<ByteArrayIStreambuf::int_type>(_buffer[_cur++]) & 0x000000ff;
341
}
342

343
ByteArrayIStreambuf::int_type ByteArrayIStreambuf::pbackfail(int_type ch)
344
{
345
    if (_cur == _beg || (ch != traits_type::eof() && ch != _buffer[_cur - 1])) {
346
        return traits_type::eof();
347
    }
348

349
    return static_cast<ByteArrayIStreambuf::int_type>(_buffer[--_cur]) & 0x000000ff;
350
}
351

352
std::streamsize ByteArrayIStreambuf::showmanyc()
353
{
354
    return _end - _cur;
355
}
356

357
std::streambuf::pos_type ByteArrayIStreambuf::seekoff(std::streambuf::off_type off,
358
                                                      std::ios_base::seekdir way,
359
                                                      std::ios_base::openmode /*mode*/)
360
{
361
    int p_pos = -1;
362
    if (way == std::ios_base::beg) {
363
        p_pos = _beg;
364
    }
365
    else if (way == std::ios_base::end) {
366
        p_pos = _end;
367
    }
368
    else if (way == std::ios_base::cur) {
369
        p_pos = _cur;
370
    }
371

372
    if (p_pos > _end) {
373
        return traits_type::eof();
374
    }
375

376
    if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
377
        return traits_type::eof();
378
    }
379

380
    _cur = p_pos + off;
381

382
    return ((p_pos + off) - _beg);
383
}
384

385
std::streambuf::pos_type ByteArrayIStreambuf::seekpos(std::streambuf::pos_type pos,
386
                                                      std::ios_base::openmode /*mode*/)
387
{
388
    return seekoff(pos, std::ios_base::beg);
389
}
390

391
// ----------------------------------------------------------------------
392

393
IODeviceOStreambuf::IODeviceOStreambuf(QIODevice* dev)
394
    : device(dev)
395
{}
396

397
IODeviceOStreambuf::~IODeviceOStreambuf() = default;
398

399
std::streambuf::int_type IODeviceOStreambuf::overflow(std::streambuf::int_type c)
400
{
401
    if (c != EOF) {
402
        char z = static_cast<char>(c);
403
        if (device->write(&z, 1) != 1) {
404
            return EOF;
405
        }
406
    }
407
    return c;
408
}
409

410
std::streamsize IODeviceOStreambuf::xsputn(const char* s, std::streamsize num)
411
{
412
    return device->write(s, num);
413
}
414

415
std::streambuf::pos_type IODeviceOStreambuf::seekoff(std::streambuf::off_type off,
416
                                                     std::ios_base::seekdir way,
417
                                                     std::ios_base::openmode /*mode*/)
418
{
419
    off_type endpos = 0;
420
    off_type curpos = device->pos();
421
    switch (way) {
422
        case std::ios_base::beg:
423
            endpos = off;
424
            break;
425
        case std::ios_base::cur:
426
            endpos = curpos + off;
427
            break;
428
        case std::ios_base::end:
429
            endpos = device->size();
430
            break;
431
        default:
432
            return {off_type(-1)};
433
    }
434

435
    if (endpos != curpos) {
436
        if (!device->seek(endpos)) {
437
            endpos = -1;
438
        }
439
    }
440

441
    return {endpos};
442
}
443

444
std::streambuf::pos_type IODeviceOStreambuf::seekpos(std::streambuf::pos_type pos,
445
                                                     std::ios_base::openmode /*mode*/)
446
{
447
    return seekoff(pos, std::ios_base::beg);
448
}
449

450
// ----------------------------------------------------------------------
451

452
IODeviceIStreambuf::IODeviceIStreambuf(QIODevice* dev)
453
    : device(dev)
454
{
455
    setg(buffer + pbSize,   // beginning of putback area
456
         buffer + pbSize,   // read position
457
         buffer + pbSize);  // end position
458
}
459

460
IODeviceIStreambuf::~IODeviceIStreambuf() = default;
461

462
std::streambuf::int_type IODeviceIStreambuf::underflow()
463
{
464
#ifndef _MSC_VER
465
    using std::memcpy;
466
#endif
467

468
    // is read position before end of buffer?
469
    if (gptr() < egptr()) {
470
        return *gptr();
471
    }
472

473
    /* process size of putback area
474
     * - use number of characters read
475
     * - but at most size of putback area
476
     */
477
    int numPutback {};
478
    numPutback = gptr() - eback();
479
    if (numPutback > pbSize) {
480
        numPutback = pbSize;
481
    }
482

483
    /* copy up to pbSize characters previously read into
484
     * the putback area
485
     */
486
    memcpy(buffer + (pbSize - numPutback), gptr() - numPutback, numPutback);
487

488
    // read at most bufSize new characters
489
    int num {};
490
    num = device->read(buffer + pbSize, bufSize);
491
    if (num <= 0) {
492
        // ERROR or EOF
493
        return EOF;
494
    }
495

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
500

501
    // return next character
502
    return *gptr();
503
}
504

505
std::streambuf::pos_type IODeviceIStreambuf::seekoff(std::streambuf::off_type off,
506
                                                     std::ios_base::seekdir way,
507
                                                     std::ios_base::openmode /*mode*/)
508
{
509
    off_type endpos = 0;
510
    off_type curpos = device->pos();
511
    switch (way) {
512
        case std::ios_base::beg:
513
            endpos = off;
514
            break;
515
        case std::ios_base::cur:
516
            endpos = curpos + off;
517
            break;
518
        case std::ios_base::end:
519
            endpos = device->size();
520
            break;
521
        default:
522
            return {off_type(-1)};
523
    }
524

525
    if (endpos != curpos) {
526
        if (!device->seek(endpos)) {
527
            endpos = -1;
528
        }
529
    }
530

531
    return {endpos};
532
}
533

534
std::streambuf::pos_type IODeviceIStreambuf::seekpos(std::streambuf::pos_type pos,
535
                                                     std::ios_base::openmode /*mode*/)
536
{
537
    return seekoff(pos, std::ios_base::beg);
538
}
539

540
// ---------------------------------------------------------
541

542
#define PYSTREAM_BUFFERED
543

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)
547
    : inp(o)
548
    , put_back(std::max(put_back, std::size_t(1)))
549
    , buffer(std::max(buf_size, put_back) + put_back)
550
{
551
    Py_INCREF(inp);
552
    char* end = &buffer.front() + buffer.size();
553
    setg(end, end, end);
554
#ifdef PYSTREAM_BUFFERED
555
    char* base = &buffer.front();
556
    setp(base, base + buffer.size());
557
#endif
558
}
559

560
PyStreambuf::~PyStreambuf()
561
{
562
    PyStreambuf::sync();
563
    Py_DECREF(inp);
564
}
565

566
PyStreambuf::int_type PyStreambuf::underflow()
567
{
568
    if (gptr() < egptr()) {
569
        return traits_type::to_int_type(*gptr());
570
    }
571

572
    char* base = &buffer.front();
573
    char* start = base;
574

575
    if (eback() == base) {  // true when this isn't the first fill
576
        std::memmove(base, egptr() - put_back, put_back);
577
        start += put_back;
578
    }
579

580
    std::size_t n {};
581
    Py::Tuple arg(1);
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"));
585

586
    try {
587
        std::string c;
588
        Py::Object res(meth.apply(arg));
589
        if (res.isBytes()) {
590
            c = static_cast<std::string>(Py::Bytes(res));
591
        }
592
        else if (res.isString()) {
593
            c = static_cast<std::string>(Py::String(res));
594
        }
595
        else {
596
            // wrong type
597
            return traits_type::eof();
598
        }
599

600
        n = c.size();
601
        if (n == 0) {
602
            return traits_type::eof();
603
        }
604

605
        // Check: bugprone-not-null-terminated-result
606
        std::memcpy(start, c.data(), c.size());
607
    }
608
    catch (Py::Exception& e) {
609
        e.clear();
610
        return traits_type::eof();
611
    }
612

613
    setg(base, start, start + n);
614
    return traits_type::to_int_type(*gptr());
615
}
616

617
PyStreambuf::int_type PyStreambuf::overflow(PyStreambuf::int_type ch)
618
{
619
#ifdef PYSTREAM_BUFFERED
620
    sync();
621
    if (ch != traits_type::eof()) {
622
        *pptr() = static_cast<char>(ch);
623
        pbump(1);
624
        return ch;
625
    }
626

627
    return traits_type::eof();
628
#else
629
    if (ch != EOF) {
630
        char z = ch;
631
        if (!writeStr(&z, 1)) {
632
            return traits_type::eof();
633
        }
634
    }
635

636
    return ch;
637
#endif
638
}
639

640
int PyStreambuf::sync()
641
{
642
#ifdef PYSTREAM_BUFFERED
643
    if (pptr() > pbase()) {
644
        flushBuffer();
645
    }
646
    return 0;
647
#else
648
    return std::streambuf::sync();
649
#endif
650
}
651

652
bool PyStreambuf::flushBuffer()
653
{
654
    std::ptrdiff_t n = pptr() - pbase();
655
    pbump(-n);
656
    return writeStr(pbase(), n);
657
}
658

659
bool PyStreambuf::writeStr(const char* str, std::streamsize num)
660
{
661
    try {
662
        Py::Tuple arg(1);
663
        Py::Callable meth(Py::Object(inp).getAttr("write"));
664

665
        if (type == StringIO) {
666
            arg.setItem(0, Py::String(str, num));
667
            meth.apply(arg);
668
            return true;
669
        }
670
        if (type == BytesIO) {
671
            arg.setItem(0, Py::Bytes(str, num));
672
            meth.apply(arg);
673
            return true;
674
        }
675

676
        // try out what works
677
        try {
678
            arg.setItem(0, Py::String(str, num));
679
            meth.apply(arg);
680
            type = StringIO;
681
            return true;
682
        }
683
        catch (Py::Exception& e) {
684
            if (PyErr_ExceptionMatches(PyExc_TypeError)) {
685
                e.clear();
686
                arg.setItem(0, Py::Bytes(str, num));
687
                meth.apply(arg);
688
                type = BytesIO;
689
                return true;
690
            }
691

692
            throw;  // re-throw
693
        }
694
    }
695
    catch (Py::Exception& e) {
696
        e.clear();
697
    }
698

699
    return false;
700
}
701

702
std::streamsize PyStreambuf::xsputn(const char* s, std::streamsize num)
703
{
704
#ifdef PYSTREAM_BUFFERED
705
    return std::streambuf::xsputn(s, num);
706
#else
707
    if (!writeStr(s, num)) {
708
        return 0;
709
    }
710
    return num;
711
#endif
712
}
713

714
PyStreambuf::pos_type PyStreambuf::seekoff(PyStreambuf::off_type offset,
715
                                           PyStreambuf::seekdir dir,
716
                                           PyStreambuf::openmode /*mode*/)
717
{
718
    int whence = 0;
719
    switch (dir) {
720
        case std::ios_base::beg:
721
            whence = 0;
722
            break;
723
        case std::ios_base::cur:
724
            whence = 1;
725
            break;
726
        case std::ios_base::end:
727
            whence = 2;
728
            break;
729
        default:
730
            return {off_type(-1)};
731
    }
732

733
    try {
734
        Py::Tuple arg(2);
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"));
738
        seek.apply(arg);
739

740
        // get current position
741
        Py::Tuple arg2;
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);
746
    }
747
    catch (Py::Exception& e) {
748
        e.clear();
749
        return {off_type(-1)};
750
    }
751
}
752

753
PyStreambuf::pos_type PyStreambuf::seekpos(PyStreambuf::pos_type offset, PyStreambuf::openmode mode)
754
{
755
    return seekoff(offset, std::ios::beg, mode);
756
}
757

758
// ---------------------------------------------------------
759

760
Streambuf::Streambuf(const std::string& data)
761
{
762
    _beg = data.begin();
763
    _end = data.end();
764
    _cur = _beg;  // NOLINT
765
}
766

767
Streambuf::~Streambuf() = default;
768

769
Streambuf::int_type Streambuf::underflow()
770
{
771
    if (_cur == _end) {
772
        return traits_type::eof();
773
    }
774

775
    return static_cast<Streambuf::int_type>(*_cur) & 0x000000ff;
776
}
777

778
Streambuf::int_type Streambuf::uflow()
779
{
780
    if (_cur == _end) {
781
        return traits_type::eof();
782
    }
783

784
    return static_cast<Streambuf::int_type>(*_cur++) & 0x000000ff;
785
}
786

787
Streambuf::int_type Streambuf::pbackfail(int_type ch)
788
{
789
    /* coverity[negative_returns] _cur is an iterator */
790
    if (_cur == _beg || (ch != traits_type::eof() && ch != _cur[-1])) {
791
        return traits_type::eof();
792
    }
793

794
    return static_cast<Streambuf::int_type>(*--_cur) & 0x000000ff;
795
}
796

797
std::streamsize Streambuf::showmanyc()
798
{
799
    return _end - _cur;
800
}
801

802
std::streambuf::pos_type Streambuf::seekoff(std::streambuf::off_type off,
803
                                            std::ios_base::seekdir way,
804
                                            std::ios_base::openmode /*mode*/)
805
{
806
    std::string::const_iterator p_pos;
807
    if (way == std::ios_base::beg) {
808
        p_pos = _beg;
809
    }
810
    else if (way == std::ios_base::end) {
811
        p_pos = _end;
812
    }
813
    else if (way == std::ios_base::cur) {
814
        p_pos = _cur;
815
    }
816

817
    if (p_pos > _end) {
818
        return traits_type::eof();
819
    }
820

821
    if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
822
        return traits_type::eof();
823
    }
824

825
    _cur = p_pos + off;
826

827
    return ((p_pos + off) - _beg);
828
}
829

830
std::streambuf::pos_type Streambuf::seekpos(std::streambuf::pos_type pos,
831
                                            std::ios_base::openmode /*mode*/)
832
{
833
    return seekoff(pos, std::ios_base::beg);
834
}
835

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)
840
{
841
    uint32_t numberOfLines;
842
    char inputChar;
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;
846

847
    _ss.str("");
848
    for (uint32_t lineNumber = 0; lineNumber < numberOfLines && _in; ++lineNumber) {
849
        while (true) {
850
            if (!_in.get(inputChar)) {
851
                break;
852
            }
853
            // Normalize \r\n to \n
854
            if (inputChar == '\r') {
855
                if (!_in.get(inputChar)) {
856
                    break;
857
                }
858
                if (inputChar == '\n') {
859
                    break;
860
                }
861
                _ss.put('\r');
862
                _ss.put(inputChar);
863
            }
864
            else {
865
                _ss.put(inputChar);
866
                if (inputChar == '\n') {
867
                    break;
868
                }
869
            }
870
        }
871
    }
872

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)) {
880
                break;
881
            }
882
            if (inputChar == '\n') {
883
                break;
884
            }
885
            _ss.put('\r');
886
        }
887
        else if (inputChar == '\n') {
888
            break;
889
        }
890

891
        _ss.put(inputChar);
892
    }
893

894
    outputString = _ss.str();
895
    return *this;
896
}
897

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.