tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

prstrms.cpp (10847B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 * Robin J. Maxwell 11-22-96
      8 * Fredrik Roubert <roubert@google.com> 2010-07-23
      9 * Matt Austern <austern@google.com> 2010-07-23
     10 */
     11 
     12 #include "prstrms.h"
     13 
     14 #include <cstdio>
     15 #include <cstring>
     16 #include <ios>
     17 #include <new>
     18 
     19 using std::ios_base;
     20 using std::iostream;
     21 using std::istream;
     22 using std::nothrow;
     23 using std::ostream;
     24 using std::streambuf;
     25 using std::streamsize;
     26 
     27 
     28 PRfilebuf::PRfilebuf():
     29    _fd(NULL),
     30    _opened(false),
     31    _allocated(false),
     32    _unbuffered(false),
     33    _user_buf(false),
     34    _buf_base(NULL),
     35    _buf_end(NULL) { }
     36 
     37 
     38 PRfilebuf::PRfilebuf(PRFileDesc *fd):
     39    _fd(fd),
     40    _opened(false),
     41    _allocated(false),
     42    _unbuffered(false),
     43    _user_buf(false),
     44    _buf_base(NULL),
     45    _buf_end(NULL) { }
     46 
     47 
     48 PRfilebuf::PRfilebuf(PRFileDesc *fd, char_type *ptr, streamsize len):
     49    _fd(fd),
     50    _opened(false),
     51    _allocated(false),
     52    _unbuffered(false),
     53    _user_buf(false),
     54    _buf_base(NULL),
     55    _buf_end(NULL)
     56 {
     57    setbuf(ptr, len);
     58 }
     59 
     60 
     61 PRfilebuf::~PRfilebuf()
     62 {
     63    if (_opened) {
     64        close();
     65    } else {
     66        sync();
     67    }
     68    if (_allocated) {
     69        delete _buf_base;
     70    }
     71 }
     72 
     73 
     74 PRfilebuf *PRfilebuf::open(
     75    const char *name, ios_base::openmode flags, PRIntn mode)
     76 {
     77    if (_fd != NULL) {
     78        return NULL;  // Error if already open.
     79    }
     80 
     81    // Translate flags argument.
     82    PRIntn prflags = 0;
     83    bool ate = (flags & ios_base::ate) != 0;
     84    flags &= ~(ios_base::ate | ios_base::binary);
     85 
     86    // TODO: The flag PR_CREATE_FILE should probably be used for the cases
     87    // (out), (out|app), (out|trunc) and (in|out|trunc) as the C++ standard
     88    // specifies that these cases should open files 'as if by using fopen with
     89    // "w"'. But adding that flag here will cause the unit test to leave files
     90    // behind after running (which might or might not be an error in the unit
     91    // test) so the matter needs further investigation before any changes are
     92    // made. The old prstreams implementation used the non-standard flag
     93    // ios::nocreate to control the use of PR_CREATE_FILE.
     94 
     95    if (flags == (ios_base::out)) {
     96        prflags = PR_WRONLY | PR_TRUNCATE;
     97    } else if (flags == (ios_base::out | ios_base::app)) {
     98        prflags = PR_RDWR | PR_APPEND;
     99    } else if (flags == (ios_base::out | ios_base::trunc)) {
    100        prflags = PR_WRONLY | PR_TRUNCATE;
    101    } else if (flags == (ios_base::in)) {
    102        prflags = PR_RDONLY;
    103    } else if (flags == (ios_base::in | ios_base::out)) {
    104        prflags = PR_RDWR;
    105    } else if (flags == (ios_base::in | ios_base::out | ios_base::trunc)) {
    106        prflags = PR_RDWR | PR_TRUNCATE;
    107    } else {
    108        return NULL;  // Unrecognized flag combination.
    109    }
    110 
    111    if ((_fd = PR_Open(name, prflags, mode)) == NULL) {
    112        return NULL;
    113    }
    114 
    115    _opened = true;
    116 
    117    if (ate &&
    118        seekoff(0, ios_base::end, flags) == pos_type(traits_type::eof())) {
    119        close();
    120        return NULL;
    121    }
    122 
    123    return this;
    124 }
    125 
    126 
    127 PRfilebuf *PRfilebuf::attach(PRFileDesc *fd)
    128 {
    129    if (_fd != NULL) {
    130        return NULL;  // Error if already open.
    131    }
    132 
    133    _opened = false;
    134    _fd = fd;
    135    return this;
    136 }
    137 
    138 
    139 PRfilebuf *PRfilebuf::close()
    140 {
    141    if (_fd == NULL) {
    142        return NULL;
    143    }
    144 
    145    int status = sync();
    146 
    147    if (PR_Close(_fd) == PR_FAILURE ||
    148        traits_type::eq_int_type(status, traits_type::eof())) {
    149        return NULL;
    150    }
    151 
    152    _fd = NULL;
    153    return this;
    154 }
    155 
    156 
    157 streambuf *PRfilebuf::setbuf(char_type *ptr, streamsize len)
    158 {
    159    if (is_open() && _buf_end) {
    160        return NULL;
    161    }
    162 
    163    if (!ptr || len <= 0) {
    164        _unbuffered = true;
    165    } else {
    166        setb(ptr, ptr + len, false);
    167    }
    168 
    169    return this;
    170 }
    171 
    172 
    173 streambuf::pos_type PRfilebuf::seekoff(
    174    off_type offset, ios_base::seekdir dir, ios_base::openmode /*flags*/)
    175 {
    176    if (PR_GetDescType(_fd) != PR_DESC_FILE) {
    177        return traits_type::eof();
    178    }
    179 
    180    PRSeekWhence whence;
    181    PRInt64 pos;
    182 
    183    switch (dir) {
    184        case ios_base::beg: whence = PR_SEEK_SET; break;
    185        case ios_base::cur: whence = PR_SEEK_CUR; break;
    186        case ios_base::end: whence = PR_SEEK_END; break;
    187        default:
    188            return traits_type::eof();  // This should never happen.
    189    }
    190 
    191    if (traits_type::eq_int_type(sync(), traits_type::eof())) {
    192        return traits_type::eof();
    193    }
    194 
    195    if ((pos = PR_Seek64(_fd, offset, whence)) == -1) {
    196        return traits_type::eof();
    197    }
    198 
    199    return pos;
    200 }
    201 
    202 
    203 int PRfilebuf::sync()
    204 {
    205    if (_fd == NULL) {
    206        return traits_type::eof();
    207    }
    208 
    209    if (!_unbuffered) {
    210        // Sync write area.
    211        PRInt32 waiting;
    212        if ((waiting = pptr() - pbase()) != 0) {
    213            PRInt32 nout;
    214            if ((nout = PR_Write(_fd, pbase(), waiting)) != waiting) {
    215                if (nout > 0) {
    216                    // Should set _pptr -= nout.
    217                    pbump(-nout);
    218                    memmove(pbase(), pbase() + nout, waiting - nout);
    219                }
    220                return traits_type::eof();
    221            }
    222        }
    223        setp(NULL, NULL);  // Empty put area.
    224 
    225        if (PR_GetDescType(_fd) == PR_DESC_FILE) {
    226            // Sockets can't seek; don't need this.
    227            PROffset64 avail;
    228            if ((avail = in_avail()) > 0) {
    229                if (PR_Seek64(_fd, -avail, PR_SEEK_CUR) != -1) {
    230                    return traits_type::eof();
    231                }
    232            }
    233        }
    234        setg(NULL, NULL, NULL);  // Empty get area.
    235    }
    236 
    237    return 0;
    238 }
    239 
    240 
    241 streambuf::int_type PRfilebuf::underflow()
    242 {
    243    PRInt32 count;
    244    char_type byte;
    245 
    246    if (gptr() != NULL && gptr() < egptr()) {
    247        return traits_type::to_int_type(*gptr());
    248    }
    249 
    250    // Make sure there is a reserve area.
    251    if (!_unbuffered && _buf_base == NULL && !allocate()) {
    252        return traits_type::eof();
    253    }
    254 
    255    // Sync before new buffer created below.
    256    if (traits_type::eq_int_type(sync(), traits_type::eof())) {
    257        return traits_type::eof();
    258    }
    259 
    260    if (_unbuffered) {
    261        if (PR_Read(_fd, &byte, 1) <= 0) {
    262            return traits_type::eof();
    263        }
    264 
    265        return traits_type::to_int_type(byte);
    266    }
    267 
    268    if ((count = PR_Read(_fd, _buf_base, _buf_end - _buf_base)) <= 0) {
    269        return traits_type::eof();  // Reached EOF.
    270    }
    271 
    272    setg(_buf_base, _buf_base, _buf_base + count);
    273    return traits_type::to_int_type(*gptr());
    274 }
    275 
    276 
    277 streambuf::int_type PRfilebuf::overflow(int_type c)
    278 {
    279    // Make sure there is a reserve area.
    280    if (!_unbuffered && _buf_base == NULL && !allocate()) {
    281        return traits_type::eof();
    282    }
    283 
    284    // Sync before new buffer created below.
    285    if (traits_type::eq_int_type(sync(), traits_type::eof())) {
    286        return traits_type::eof();
    287    }
    288 
    289    if (!_unbuffered) {
    290        setp(_buf_base, _buf_end);
    291    }
    292 
    293    if (!traits_type::eq_int_type(c, traits_type::eof())) {
    294        // Extract the byte to be written.
    295        // (Required on big-endian architectures.)
    296        char_type byte = traits_type::to_char_type(c);
    297        if (!_unbuffered && pptr() < epptr()) {  // Guard against recursion.
    298            return sputc(byte);
    299        } else {
    300            if (PR_Write(_fd, &byte, 1) != 1) {
    301                return traits_type::eof();
    302            }
    303        }
    304    }
    305 
    306    return traits_type::not_eof(c);
    307 }
    308 
    309 
    310 bool PRfilebuf::allocate()
    311 {
    312    char_type *buf = new(nothrow) char_type[BUFSIZ];
    313    if (buf == NULL) {
    314        return false;
    315    }
    316 
    317    setb(buf, buf + BUFSIZ, true);
    318    return true;
    319 }
    320 
    321 
    322 void PRfilebuf::setb(char_type *buf_base, char_type *buf_end, bool user_buf)
    323 {
    324    if (_buf_base && !_user_buf) {
    325        delete[] _buf_base;
    326    }
    327 
    328    _buf_base = buf_base;
    329    _buf_end = buf_end;
    330    _user_buf = user_buf;
    331 }
    332 
    333 
    334 PRifstream::PRifstream():
    335    istream(NULL),
    336    _filebuf()
    337 {
    338    init(&_filebuf);
    339 }
    340 
    341 
    342 PRifstream::PRifstream(PRFileDesc *fd):
    343    istream(NULL),
    344    _filebuf(fd)
    345 {
    346    init(&_filebuf);
    347 }
    348 
    349 
    350 PRifstream::PRifstream(PRFileDesc *fd, char_type *ptr, streamsize len):
    351    istream(NULL),
    352    _filebuf(fd, ptr, len)
    353 {
    354    init(&_filebuf);
    355 }
    356 
    357 
    358 PRifstream::PRifstream(const char *name, openmode flags, PRIntn mode):
    359    istream(NULL),
    360    _filebuf()
    361 {
    362    init(&_filebuf);
    363    if (!_filebuf.open(name, flags | in, mode)) {
    364        setstate(failbit);
    365    }
    366 }
    367 
    368 
    369 PRifstream::~PRifstream() { }
    370 
    371 
    372 void PRifstream::open(const char *name, openmode flags, PRIntn mode)
    373 {
    374    if (is_open() || !_filebuf.open(name, flags | in, mode)) {
    375        setstate(failbit);
    376    }
    377 }
    378 
    379 
    380 void PRifstream::attach(PRFileDesc *fd)
    381 {
    382    if (!_filebuf.attach(fd)) {
    383        setstate(failbit);
    384    }
    385 }
    386 
    387 
    388 void PRifstream::close()
    389 {
    390    if (_filebuf.close() == NULL) {
    391        setstate(failbit);
    392    }
    393 }
    394 
    395 
    396 PRofstream::PRofstream():
    397    ostream(NULL),
    398    _filebuf()
    399 {
    400    init(&_filebuf);
    401 }
    402 
    403 
    404 PRofstream::PRofstream(PRFileDesc *fd):
    405    ostream(NULL),
    406    _filebuf(fd)
    407 {
    408    init(&_filebuf);
    409 }
    410 
    411 
    412 PRofstream::PRofstream(PRFileDesc *fd, char_type *ptr, streamsize len):
    413    ostream(NULL),
    414    _filebuf(fd, ptr, len)
    415 {
    416    init(&_filebuf);
    417 }
    418 
    419 
    420 PRofstream::PRofstream(const char *name, openmode flags, PRIntn mode):
    421    ostream(NULL),
    422    _filebuf()
    423 {
    424    init(&_filebuf);
    425    if (!_filebuf.open(name, flags | out, mode)) {
    426        setstate(failbit);
    427    }
    428 }
    429 
    430 
    431 PRofstream::~PRofstream() { }
    432 
    433 
    434 void PRofstream::open(const char *name, openmode flags, PRIntn mode)
    435 {
    436    if (is_open() || !_filebuf.open(name, flags | out, mode)) {
    437        setstate(failbit);
    438    }
    439 }
    440 
    441 
    442 void PRofstream::attach(PRFileDesc *fd)
    443 {
    444    if (!_filebuf.attach(fd)) {
    445        setstate(failbit);
    446    }
    447 }
    448 
    449 
    450 void PRofstream::close()
    451 {
    452    if (_filebuf.close() == NULL) {
    453        setstate(failbit);
    454    }
    455 }
    456 
    457 
    458 PRfstream::PRfstream():
    459    iostream(NULL),
    460    _filebuf()
    461 {
    462    init(&_filebuf);
    463 }
    464 
    465 
    466 PRfstream::PRfstream(PRFileDesc *fd):
    467    iostream(NULL),
    468    _filebuf(fd)
    469 {
    470    init(&_filebuf);
    471 }
    472 
    473 
    474 PRfstream::PRfstream(PRFileDesc *fd, char_type *ptr, streamsize len):
    475    iostream(NULL),
    476    _filebuf(fd, ptr, len)
    477 {
    478    init(&_filebuf);
    479 }
    480 
    481 
    482 PRfstream::PRfstream(const char *name, openmode flags, PRIntn mode):
    483    iostream(NULL),
    484    _filebuf()
    485 {
    486    init(&_filebuf);
    487    if (!_filebuf.open(name, flags | in | out, mode)) {
    488        setstate(failbit);
    489    }
    490 }
    491 
    492 
    493 PRfstream::~PRfstream() { }
    494 
    495 
    496 void PRfstream::open(const char *name, openmode flags, PRIntn mode)
    497 {
    498    if (is_open() || !_filebuf.open(name, flags | in | out, mode)) {
    499        setstate(failbit);
    500    }
    501 }
    502 
    503 
    504 void PRfstream::attach(PRFileDesc *fd)
    505 {
    506    if (!_filebuf.attach(fd)) {
    507        setstate(failbit);
    508    }
    509 }
    510 
    511 
    512 void PRfstream::close()
    513 {
    514    if (_filebuf.close() == NULL) {
    515        setstate(failbit);
    516    }
    517 }