1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/lib/prstreams/prstrms.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,516 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Robin J. Maxwell 11-22-96 1.11 + * Fredrik Roubert <roubert@google.com> 2010-07-23 1.12 + * Matt Austern <austern@google.com> 2010-07-23 1.13 + */ 1.14 + 1.15 +#include "prstrms.h" 1.16 + 1.17 +#include <cstdio> 1.18 +#include <cstring> 1.19 +#include <ios> 1.20 +#include <new> 1.21 + 1.22 +using std::ios_base; 1.23 +using std::iostream; 1.24 +using std::istream; 1.25 +using std::nothrow; 1.26 +using std::ostream; 1.27 +using std::streambuf; 1.28 +using std::streamsize; 1.29 + 1.30 + 1.31 +PRfilebuf::PRfilebuf(): 1.32 + _fd(NULL), 1.33 + _opened(false), 1.34 + _allocated(false), 1.35 + _unbuffered(false), 1.36 + _user_buf(false), 1.37 + _buf_base(NULL), 1.38 + _buf_end(NULL) { } 1.39 + 1.40 + 1.41 +PRfilebuf::PRfilebuf(PRFileDesc *fd): 1.42 + _fd(fd), 1.43 + _opened(false), 1.44 + _allocated(false), 1.45 + _unbuffered(false), 1.46 + _user_buf(false), 1.47 + _buf_base(NULL), 1.48 + _buf_end(NULL) { } 1.49 + 1.50 + 1.51 +PRfilebuf::PRfilebuf(PRFileDesc *fd, char_type *ptr, streamsize len): 1.52 + _fd(fd), 1.53 + _opened(false), 1.54 + _allocated(false), 1.55 + _unbuffered(false), 1.56 + _user_buf(false), 1.57 + _buf_base(NULL), 1.58 + _buf_end(NULL) 1.59 +{ 1.60 + setbuf(ptr, len); 1.61 +} 1.62 + 1.63 + 1.64 +PRfilebuf::~PRfilebuf() 1.65 +{ 1.66 + if (_opened) { 1.67 + close(); 1.68 + } else { 1.69 + sync(); 1.70 + } 1.71 + if (_allocated) { 1.72 + delete _buf_base; 1.73 + } 1.74 +} 1.75 + 1.76 + 1.77 +PRfilebuf *PRfilebuf::open( 1.78 + const char *name, ios_base::openmode flags, PRIntn mode) 1.79 +{ 1.80 + if (_fd != NULL) { 1.81 + return NULL; // Error if already open. 1.82 + } 1.83 + 1.84 + // Translate flags argument. 1.85 + PRIntn prflags = 0; 1.86 + bool ate = (flags & ios_base::ate) != 0; 1.87 + flags &= ~(ios_base::ate | ios_base::binary); 1.88 + 1.89 + // TODO: The flag PR_CREATE_FILE should probably be used for the cases 1.90 + // (out), (out|app), (out|trunc) and (in|out|trunc) as the C++ standard 1.91 + // specifies that these cases should open files 'as if by using fopen with 1.92 + // "w"'. But adding that flag here will cause the unit test to leave files 1.93 + // behind after running (which might or might not be an error in the unit 1.94 + // test) so the matter needs further investigation before any changes are 1.95 + // made. The old prstreams implementation used the non-standard flag 1.96 + // ios::nocreate to control the use of PR_CREATE_FILE. 1.97 + 1.98 + if (flags == (ios_base::out)) { 1.99 + prflags = PR_WRONLY | PR_TRUNCATE; 1.100 + } else if (flags == (ios_base::out | ios_base::app)) { 1.101 + prflags = PR_RDWR | PR_APPEND; 1.102 + } else if (flags == (ios_base::out | ios_base::trunc)) { 1.103 + prflags = PR_WRONLY | PR_TRUNCATE; 1.104 + } else if (flags == (ios_base::in)) { 1.105 + prflags = PR_RDONLY; 1.106 + } else if (flags == (ios_base::in | ios_base::out)) { 1.107 + prflags = PR_RDWR; 1.108 + } else if (flags == (ios_base::in | ios_base::out | ios_base::trunc)) { 1.109 + prflags = PR_RDWR | PR_TRUNCATE; 1.110 + } else { 1.111 + return NULL; // Unrecognized flag combination. 1.112 + } 1.113 + 1.114 + if ((_fd = PR_Open(name, prflags, mode)) == NULL) { 1.115 + return NULL; 1.116 + } 1.117 + 1.118 + _opened = true; 1.119 + 1.120 + if (ate && 1.121 + seekoff(0, ios_base::end, flags) == pos_type(traits_type::eof())) { 1.122 + close(); 1.123 + return NULL; 1.124 + } 1.125 + 1.126 + return this; 1.127 +} 1.128 + 1.129 + 1.130 +PRfilebuf *PRfilebuf::attach(PRFileDesc *fd) 1.131 +{ 1.132 + if (_fd != NULL) { 1.133 + return NULL; // Error if already open. 1.134 + } 1.135 + 1.136 + _opened = false; 1.137 + _fd = fd; 1.138 + return this; 1.139 +} 1.140 + 1.141 + 1.142 +PRfilebuf *PRfilebuf::close() 1.143 +{ 1.144 + if (_fd == NULL) 1.145 + return NULL; 1.146 + 1.147 + int status = sync(); 1.148 + 1.149 + if (PR_Close(_fd) == PR_FAILURE || 1.150 + traits_type::eq_int_type(status, traits_type::eof())) { 1.151 + return NULL; 1.152 + } 1.153 + 1.154 + _fd = NULL; 1.155 + return this; 1.156 +} 1.157 + 1.158 + 1.159 +streambuf *PRfilebuf::setbuf(char_type *ptr, streamsize len) 1.160 +{ 1.161 + if (is_open() && _buf_end) { 1.162 + return NULL; 1.163 + } 1.164 + 1.165 + if (!ptr || len <= 0) { 1.166 + _unbuffered = true; 1.167 + } else { 1.168 + setb(ptr, ptr + len, false); 1.169 + } 1.170 + 1.171 + return this; 1.172 +} 1.173 + 1.174 + 1.175 +streambuf::pos_type PRfilebuf::seekoff( 1.176 + off_type offset, ios_base::seekdir dir, ios_base::openmode /*flags*/) 1.177 +{ 1.178 + if (PR_GetDescType(_fd) != PR_DESC_FILE) { 1.179 + return traits_type::eof(); 1.180 + } 1.181 + 1.182 + PRSeekWhence whence; 1.183 + PRInt64 pos; 1.184 + 1.185 + switch (dir) { 1.186 + case ios_base::beg: whence = PR_SEEK_SET; break; 1.187 + case ios_base::cur: whence = PR_SEEK_CUR; break; 1.188 + case ios_base::end: whence = PR_SEEK_END; break; 1.189 + default: 1.190 + return traits_type::eof(); // This should never happen. 1.191 + } 1.192 + 1.193 + if (traits_type::eq_int_type(sync(), traits_type::eof())) { 1.194 + return traits_type::eof(); 1.195 + } 1.196 + 1.197 + if ((pos = PR_Seek64(_fd, offset, whence)) == -1) { 1.198 + return traits_type::eof(); 1.199 + } 1.200 + 1.201 + return pos; 1.202 +} 1.203 + 1.204 + 1.205 +int PRfilebuf::sync() 1.206 +{ 1.207 + if (_fd == NULL) { 1.208 + return traits_type::eof(); 1.209 + } 1.210 + 1.211 + if (!_unbuffered) { 1.212 + // Sync write area. 1.213 + PRInt32 waiting; 1.214 + if ((waiting = pptr() - pbase()) != 0) { 1.215 + PRInt32 nout; 1.216 + if ((nout = PR_Write(_fd, pbase(), waiting)) != waiting) { 1.217 + if (nout > 0) { 1.218 + // Should set _pptr -= nout. 1.219 + pbump(-nout); 1.220 + memmove(pbase(), pbase() + nout, waiting - nout); 1.221 + } 1.222 + return traits_type::eof(); 1.223 + } 1.224 + } 1.225 + setp(NULL, NULL); // Empty put area. 1.226 + 1.227 + if (PR_GetDescType(_fd) == PR_DESC_FILE) { 1.228 + // Sockets can't seek; don't need this. 1.229 + PROffset64 avail; 1.230 + if ((avail = in_avail()) > 0) { 1.231 + if (PR_Seek64(_fd, -avail, PR_SEEK_CUR) != -1) { 1.232 + return traits_type::eof(); 1.233 + } 1.234 + } 1.235 + } 1.236 + setg(NULL, NULL, NULL); // Empty get area. 1.237 + } 1.238 + 1.239 + return 0; 1.240 +} 1.241 + 1.242 + 1.243 +streambuf::int_type PRfilebuf::underflow() 1.244 +{ 1.245 + PRInt32 count; 1.246 + char_type byte; 1.247 + 1.248 + if (gptr() != NULL && gptr() < egptr()) { 1.249 + return traits_type::to_int_type(*gptr()); 1.250 + } 1.251 + 1.252 + // Make sure there is a reserve area. 1.253 + if (!_unbuffered && _buf_base == NULL && !allocate()) { 1.254 + return traits_type::eof(); 1.255 + } 1.256 + 1.257 + // Sync before new buffer created below. 1.258 + if (traits_type::eq_int_type(sync(), traits_type::eof())) { 1.259 + return traits_type::eof(); 1.260 + } 1.261 + 1.262 + if (_unbuffered) { 1.263 + if (PR_Read(_fd, &byte, 1) <= 0) { 1.264 + return traits_type::eof(); 1.265 + } 1.266 + 1.267 + return traits_type::to_int_type(byte); 1.268 + } 1.269 + 1.270 + if ((count = PR_Read(_fd, _buf_base, _buf_end - _buf_base)) <= 0) { 1.271 + return traits_type::eof(); // Reached EOF. 1.272 + } 1.273 + 1.274 + setg(_buf_base, _buf_base, _buf_base + count); 1.275 + return traits_type::to_int_type(*gptr()); 1.276 +} 1.277 + 1.278 + 1.279 +streambuf::int_type PRfilebuf::overflow(int_type c) 1.280 +{ 1.281 + // Make sure there is a reserve area. 1.282 + if (!_unbuffered && _buf_base == NULL && !allocate()) { 1.283 + return traits_type::eof(); 1.284 + } 1.285 + 1.286 + // Sync before new buffer created below. 1.287 + if (traits_type::eq_int_type(sync(), traits_type::eof())) { 1.288 + return traits_type::eof(); 1.289 + } 1.290 + 1.291 + if (!_unbuffered) { 1.292 + setp(_buf_base, _buf_end); 1.293 + } 1.294 + 1.295 + if (!traits_type::eq_int_type(c, traits_type::eof())) { 1.296 + // Extract the byte to be written. 1.297 + // (Required on big-endian architectures.) 1.298 + char_type byte = traits_type::to_char_type(c); 1.299 + if (!_unbuffered && pptr() < epptr()) { // Guard against recursion. 1.300 + return sputc(byte); 1.301 + } else { 1.302 + if (PR_Write(_fd, &byte, 1) != 1) { 1.303 + return traits_type::eof(); 1.304 + } 1.305 + } 1.306 + } 1.307 + 1.308 + return traits_type::not_eof(c); 1.309 +} 1.310 + 1.311 + 1.312 +bool PRfilebuf::allocate() 1.313 +{ 1.314 + char_type *buf = new(nothrow) char_type[BUFSIZ]; 1.315 + if (buf == NULL) { 1.316 + return false; 1.317 + } 1.318 + 1.319 + setb(buf, buf + BUFSIZ, true); 1.320 + return true; 1.321 +} 1.322 + 1.323 + 1.324 +void PRfilebuf::setb(char_type *buf_base, char_type *buf_end, bool user_buf) 1.325 +{ 1.326 + if (_buf_base && !_user_buf) { 1.327 + delete[] _buf_base; 1.328 + } 1.329 + 1.330 + _buf_base = buf_base; 1.331 + _buf_end = buf_end; 1.332 + _user_buf = user_buf; 1.333 +} 1.334 + 1.335 + 1.336 +PRifstream::PRifstream(): 1.337 + istream(NULL), 1.338 + _filebuf() 1.339 +{ 1.340 + init(&_filebuf); 1.341 +} 1.342 + 1.343 + 1.344 +PRifstream::PRifstream(PRFileDesc *fd): 1.345 + istream(NULL), 1.346 + _filebuf(fd) 1.347 +{ 1.348 + init(&_filebuf); 1.349 +} 1.350 + 1.351 + 1.352 +PRifstream::PRifstream(PRFileDesc *fd, char_type *ptr, streamsize len): 1.353 + istream(NULL), 1.354 + _filebuf(fd, ptr, len) 1.355 +{ 1.356 + init(&_filebuf); 1.357 +} 1.358 + 1.359 + 1.360 +PRifstream::PRifstream(const char *name, openmode flags, PRIntn mode): 1.361 + istream(NULL), 1.362 + _filebuf() 1.363 +{ 1.364 + init(&_filebuf); 1.365 + if (!_filebuf.open(name, flags | in, mode)) { 1.366 + setstate(failbit); 1.367 + } 1.368 +} 1.369 + 1.370 + 1.371 +PRifstream::~PRifstream() { } 1.372 + 1.373 + 1.374 +void PRifstream::open(const char *name, openmode flags, PRIntn mode) 1.375 +{ 1.376 + if (is_open() || !_filebuf.open(name, flags | in, mode)) { 1.377 + setstate(failbit); 1.378 + } 1.379 +} 1.380 + 1.381 + 1.382 +void PRifstream::attach(PRFileDesc *fd) 1.383 +{ 1.384 + if (!_filebuf.attach(fd)) { 1.385 + setstate(failbit); 1.386 + } 1.387 +} 1.388 + 1.389 + 1.390 +void PRifstream::close() 1.391 +{ 1.392 + if (_filebuf.close() == NULL) { 1.393 + setstate(failbit); 1.394 + } 1.395 +} 1.396 + 1.397 + 1.398 +PRofstream::PRofstream(): 1.399 + ostream(NULL), 1.400 + _filebuf() 1.401 +{ 1.402 + init(&_filebuf); 1.403 +} 1.404 + 1.405 + 1.406 +PRofstream::PRofstream(PRFileDesc *fd): 1.407 + ostream(NULL), 1.408 + _filebuf(fd) 1.409 +{ 1.410 + init(&_filebuf); 1.411 +} 1.412 + 1.413 + 1.414 +PRofstream::PRofstream(PRFileDesc *fd, char_type *ptr, streamsize len): 1.415 + ostream(NULL), 1.416 + _filebuf(fd, ptr, len) 1.417 +{ 1.418 + init(&_filebuf); 1.419 +} 1.420 + 1.421 + 1.422 +PRofstream::PRofstream(const char *name, openmode flags, PRIntn mode): 1.423 + ostream(NULL), 1.424 + _filebuf() 1.425 +{ 1.426 + init(&_filebuf); 1.427 + if (!_filebuf.open(name, flags | out, mode)) { 1.428 + setstate(failbit); 1.429 + } 1.430 +} 1.431 + 1.432 + 1.433 +PRofstream::~PRofstream() { } 1.434 + 1.435 + 1.436 +void PRofstream::open(const char *name, openmode flags, PRIntn mode) 1.437 +{ 1.438 + if (is_open() || !_filebuf.open(name, flags | out, mode)) { 1.439 + setstate(failbit); 1.440 + } 1.441 +} 1.442 + 1.443 + 1.444 +void PRofstream::attach(PRFileDesc *fd) 1.445 +{ 1.446 + if (!_filebuf.attach(fd)) { 1.447 + setstate(failbit); 1.448 + } 1.449 +} 1.450 + 1.451 + 1.452 +void PRofstream::close() 1.453 +{ 1.454 + if (_filebuf.close() == NULL) { 1.455 + setstate(failbit); 1.456 + } 1.457 +} 1.458 + 1.459 + 1.460 +PRfstream::PRfstream(): 1.461 + iostream(NULL), 1.462 + _filebuf() 1.463 +{ 1.464 + init(&_filebuf); 1.465 +} 1.466 + 1.467 + 1.468 +PRfstream::PRfstream(PRFileDesc *fd): 1.469 + iostream(NULL), 1.470 + _filebuf(fd) 1.471 +{ 1.472 + init(&_filebuf); 1.473 +} 1.474 + 1.475 + 1.476 +PRfstream::PRfstream(PRFileDesc *fd, char_type *ptr, streamsize len): 1.477 + iostream(NULL), 1.478 + _filebuf(fd, ptr, len) 1.479 +{ 1.480 + init(&_filebuf); 1.481 +} 1.482 + 1.483 + 1.484 +PRfstream::PRfstream(const char *name, openmode flags, PRIntn mode): 1.485 + iostream(NULL), 1.486 + _filebuf() 1.487 +{ 1.488 + init(&_filebuf); 1.489 + if (!_filebuf.open(name, flags | in | out, mode)) { 1.490 + setstate(failbit); 1.491 + } 1.492 +} 1.493 + 1.494 + 1.495 +PRfstream::~PRfstream() { } 1.496 + 1.497 + 1.498 +void PRfstream::open(const char *name, openmode flags, PRIntn mode) 1.499 +{ 1.500 + if (is_open() || !_filebuf.open(name, flags | in | out, mode)) { 1.501 + setstate(failbit); 1.502 + } 1.503 +} 1.504 + 1.505 + 1.506 +void PRfstream::attach(PRFileDesc *fd) 1.507 +{ 1.508 + if (!_filebuf.attach(fd)) { 1.509 + setstate(failbit); 1.510 + } 1.511 +} 1.512 + 1.513 + 1.514 +void PRfstream::close() 1.515 +{ 1.516 + if (_filebuf.close() == NULL) { 1.517 + setstate(failbit); 1.518 + } 1.519 +}