/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Robin J. Maxwell 11-22-96 * Fredrik Roubert 2010-07-23 * Matt Austern 2010-07-23 */ #include "prstrms.h" #include #include #include #include using std::ios_base; using std::iostream; using std::istream; using std::nothrow; using std::ostream; using std::streambuf; using std::streamsize; PRfilebuf::PRfilebuf(): _fd(NULL), _opened(false), _allocated(false), _unbuffered(false), _user_buf(false), _buf_base(NULL), _buf_end(NULL) { } PRfilebuf::PRfilebuf(PRFileDesc *fd): _fd(fd), _opened(false), _allocated(false), _unbuffered(false), _user_buf(false), _buf_base(NULL), _buf_end(NULL) { } PRfilebuf::PRfilebuf(PRFileDesc *fd, char_type *ptr, streamsize len): _fd(fd), _opened(false), _allocated(false), _unbuffered(false), _user_buf(false), _buf_base(NULL), _buf_end(NULL) { setbuf(ptr, len); } PRfilebuf::~PRfilebuf() { if (_opened) { close(); } else { sync(); } if (_allocated) { delete _buf_base; } } PRfilebuf *PRfilebuf::open( const char *name, ios_base::openmode flags, PRIntn mode) { if (_fd != NULL) { return NULL; // Error if already open. } // Translate flags argument. PRIntn prflags = 0; bool ate = (flags & ios_base::ate) != 0; flags &= ~(ios_base::ate | ios_base::binary); // TODO: The flag PR_CREATE_FILE should probably be used for the cases // (out), (out|app), (out|trunc) and (in|out|trunc) as the C++ standard // specifies that these cases should open files 'as if by using fopen with // "w"'. But adding that flag here will cause the unit test to leave files // behind after running (which might or might not be an error in the unit // test) so the matter needs further investigation before any changes are // made. The old prstreams implementation used the non-standard flag // ios::nocreate to control the use of PR_CREATE_FILE. if (flags == (ios_base::out)) { prflags = PR_WRONLY | PR_TRUNCATE; } else if (flags == (ios_base::out | ios_base::app)) { prflags = PR_RDWR | PR_APPEND; } else if (flags == (ios_base::out | ios_base::trunc)) { prflags = PR_WRONLY | PR_TRUNCATE; } else if (flags == (ios_base::in)) { prflags = PR_RDONLY; } else if (flags == (ios_base::in | ios_base::out)) { prflags = PR_RDWR; } else if (flags == (ios_base::in | ios_base::out | ios_base::trunc)) { prflags = PR_RDWR | PR_TRUNCATE; } else { return NULL; // Unrecognized flag combination. } if ((_fd = PR_Open(name, prflags, mode)) == NULL) { return NULL; } _opened = true; if (ate && seekoff(0, ios_base::end, flags) == pos_type(traits_type::eof())) { close(); return NULL; } return this; } PRfilebuf *PRfilebuf::attach(PRFileDesc *fd) { if (_fd != NULL) { return NULL; // Error if already open. } _opened = false; _fd = fd; return this; } PRfilebuf *PRfilebuf::close() { if (_fd == NULL) { return NULL; } int status = sync(); if (PR_Close(_fd) == PR_FAILURE || traits_type::eq_int_type(status, traits_type::eof())) { return NULL; } _fd = NULL; return this; } streambuf *PRfilebuf::setbuf(char_type *ptr, streamsize len) { if (is_open() && _buf_end) { return NULL; } if (!ptr || len <= 0) { _unbuffered = true; } else { setb(ptr, ptr + len, false); } return this; } streambuf::pos_type PRfilebuf::seekoff( off_type offset, ios_base::seekdir dir, ios_base::openmode /*flags*/) { if (PR_GetDescType(_fd) != PR_DESC_FILE) { return traits_type::eof(); } PRSeekWhence whence; PRInt64 pos; switch (dir) { case ios_base::beg: whence = PR_SEEK_SET; break; case ios_base::cur: whence = PR_SEEK_CUR; break; case ios_base::end: whence = PR_SEEK_END; break; default: return traits_type::eof(); // This should never happen. } if (traits_type::eq_int_type(sync(), traits_type::eof())) { return traits_type::eof(); } if ((pos = PR_Seek64(_fd, offset, whence)) == -1) { return traits_type::eof(); } return pos; } int PRfilebuf::sync() { if (_fd == NULL) { return traits_type::eof(); } if (!_unbuffered) { // Sync write area. PRInt32 waiting; if ((waiting = pptr() - pbase()) != 0) { PRInt32 nout; if ((nout = PR_Write(_fd, pbase(), waiting)) != waiting) { if (nout > 0) { // Should set _pptr -= nout. pbump(-nout); memmove(pbase(), pbase() + nout, waiting - nout); } return traits_type::eof(); } } setp(NULL, NULL); // Empty put area. if (PR_GetDescType(_fd) == PR_DESC_FILE) { // Sockets can't seek; don't need this. PROffset64 avail; if ((avail = in_avail()) > 0) { if (PR_Seek64(_fd, -avail, PR_SEEK_CUR) != -1) { return traits_type::eof(); } } } setg(NULL, NULL, NULL); // Empty get area. } return 0; } streambuf::int_type PRfilebuf::underflow() { PRInt32 count; char_type byte; if (gptr() != NULL && gptr() < egptr()) { return traits_type::to_int_type(*gptr()); } // Make sure there is a reserve area. if (!_unbuffered && _buf_base == NULL && !allocate()) { return traits_type::eof(); } // Sync before new buffer created below. if (traits_type::eq_int_type(sync(), traits_type::eof())) { return traits_type::eof(); } if (_unbuffered) { if (PR_Read(_fd, &byte, 1) <= 0) { return traits_type::eof(); } return traits_type::to_int_type(byte); } if ((count = PR_Read(_fd, _buf_base, _buf_end - _buf_base)) <= 0) { return traits_type::eof(); // Reached EOF. } setg(_buf_base, _buf_base, _buf_base + count); return traits_type::to_int_type(*gptr()); } streambuf::int_type PRfilebuf::overflow(int_type c) { // Make sure there is a reserve area. if (!_unbuffered && _buf_base == NULL && !allocate()) { return traits_type::eof(); } // Sync before new buffer created below. if (traits_type::eq_int_type(sync(), traits_type::eof())) { return traits_type::eof(); } if (!_unbuffered) { setp(_buf_base, _buf_end); } if (!traits_type::eq_int_type(c, traits_type::eof())) { // Extract the byte to be written. // (Required on big-endian architectures.) char_type byte = traits_type::to_char_type(c); if (!_unbuffered && pptr() < epptr()) { // Guard against recursion. return sputc(byte); } else { if (PR_Write(_fd, &byte, 1) != 1) { return traits_type::eof(); } } } return traits_type::not_eof(c); } bool PRfilebuf::allocate() { char_type *buf = new(nothrow) char_type[BUFSIZ]; if (buf == NULL) { return false; } setb(buf, buf + BUFSIZ, true); return true; } void PRfilebuf::setb(char_type *buf_base, char_type *buf_end, bool user_buf) { if (_buf_base && !_user_buf) { delete[] _buf_base; } _buf_base = buf_base; _buf_end = buf_end; _user_buf = user_buf; } PRifstream::PRifstream(): istream(NULL), _filebuf() { init(&_filebuf); } PRifstream::PRifstream(PRFileDesc *fd): istream(NULL), _filebuf(fd) { init(&_filebuf); } PRifstream::PRifstream(PRFileDesc *fd, char_type *ptr, streamsize len): istream(NULL), _filebuf(fd, ptr, len) { init(&_filebuf); } PRifstream::PRifstream(const char *name, openmode flags, PRIntn mode): istream(NULL), _filebuf() { init(&_filebuf); if (!_filebuf.open(name, flags | in, mode)) { setstate(failbit); } } PRifstream::~PRifstream() { } void PRifstream::open(const char *name, openmode flags, PRIntn mode) { if (is_open() || !_filebuf.open(name, flags | in, mode)) { setstate(failbit); } } void PRifstream::attach(PRFileDesc *fd) { if (!_filebuf.attach(fd)) { setstate(failbit); } } void PRifstream::close() { if (_filebuf.close() == NULL) { setstate(failbit); } } PRofstream::PRofstream(): ostream(NULL), _filebuf() { init(&_filebuf); } PRofstream::PRofstream(PRFileDesc *fd): ostream(NULL), _filebuf(fd) { init(&_filebuf); } PRofstream::PRofstream(PRFileDesc *fd, char_type *ptr, streamsize len): ostream(NULL), _filebuf(fd, ptr, len) { init(&_filebuf); } PRofstream::PRofstream(const char *name, openmode flags, PRIntn mode): ostream(NULL), _filebuf() { init(&_filebuf); if (!_filebuf.open(name, flags | out, mode)) { setstate(failbit); } } PRofstream::~PRofstream() { } void PRofstream::open(const char *name, openmode flags, PRIntn mode) { if (is_open() || !_filebuf.open(name, flags | out, mode)) { setstate(failbit); } } void PRofstream::attach(PRFileDesc *fd) { if (!_filebuf.attach(fd)) { setstate(failbit); } } void PRofstream::close() { if (_filebuf.close() == NULL) { setstate(failbit); } } PRfstream::PRfstream(): iostream(NULL), _filebuf() { init(&_filebuf); } PRfstream::PRfstream(PRFileDesc *fd): iostream(NULL), _filebuf(fd) { init(&_filebuf); } PRfstream::PRfstream(PRFileDesc *fd, char_type *ptr, streamsize len): iostream(NULL), _filebuf(fd, ptr, len) { init(&_filebuf); } PRfstream::PRfstream(const char *name, openmode flags, PRIntn mode): iostream(NULL), _filebuf() { init(&_filebuf); if (!_filebuf.open(name, flags | in | out, mode)) { setstate(failbit); } } PRfstream::~PRfstream() { } void PRfstream::open(const char *name, openmode flags, PRIntn mode) { if (is_open() || !_filebuf.open(name, flags | in | out, mode)) { setstate(failbit); } } void PRfstream::attach(PRFileDesc *fd) { if (!_filebuf.attach(fd)) { setstate(failbit); } } void PRfstream::close() { if (_filebuf.close() == NULL) { setstate(failbit); } }