Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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/. */
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 */
12 #include "prstrms.h"
14 #include <cstdio>
15 #include <cstring>
16 #include <ios>
17 #include <new>
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;
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) { }
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) { }
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 }
61 PRfilebuf::~PRfilebuf()
62 {
63 if (_opened) {
64 close();
65 } else {
66 sync();
67 }
68 if (_allocated) {
69 delete _buf_base;
70 }
71 }
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 }
81 // Translate flags argument.
82 PRIntn prflags = 0;
83 bool ate = (flags & ios_base::ate) != 0;
84 flags &= ~(ios_base::ate | ios_base::binary);
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.
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 }
111 if ((_fd = PR_Open(name, prflags, mode)) == NULL) {
112 return NULL;
113 }
115 _opened = true;
117 if (ate &&
118 seekoff(0, ios_base::end, flags) == pos_type(traits_type::eof())) {
119 close();
120 return NULL;
121 }
123 return this;
124 }
127 PRfilebuf *PRfilebuf::attach(PRFileDesc *fd)
128 {
129 if (_fd != NULL) {
130 return NULL; // Error if already open.
131 }
133 _opened = false;
134 _fd = fd;
135 return this;
136 }
139 PRfilebuf *PRfilebuf::close()
140 {
141 if (_fd == NULL)
142 return NULL;
144 int status = sync();
146 if (PR_Close(_fd) == PR_FAILURE ||
147 traits_type::eq_int_type(status, traits_type::eof())) {
148 return NULL;
149 }
151 _fd = NULL;
152 return this;
153 }
156 streambuf *PRfilebuf::setbuf(char_type *ptr, streamsize len)
157 {
158 if (is_open() && _buf_end) {
159 return NULL;
160 }
162 if (!ptr || len <= 0) {
163 _unbuffered = true;
164 } else {
165 setb(ptr, ptr + len, false);
166 }
168 return this;
169 }
172 streambuf::pos_type PRfilebuf::seekoff(
173 off_type offset, ios_base::seekdir dir, ios_base::openmode /*flags*/)
174 {
175 if (PR_GetDescType(_fd) != PR_DESC_FILE) {
176 return traits_type::eof();
177 }
179 PRSeekWhence whence;
180 PRInt64 pos;
182 switch (dir) {
183 case ios_base::beg: whence = PR_SEEK_SET; break;
184 case ios_base::cur: whence = PR_SEEK_CUR; break;
185 case ios_base::end: whence = PR_SEEK_END; break;
186 default:
187 return traits_type::eof(); // This should never happen.
188 }
190 if (traits_type::eq_int_type(sync(), traits_type::eof())) {
191 return traits_type::eof();
192 }
194 if ((pos = PR_Seek64(_fd, offset, whence)) == -1) {
195 return traits_type::eof();
196 }
198 return pos;
199 }
202 int PRfilebuf::sync()
203 {
204 if (_fd == NULL) {
205 return traits_type::eof();
206 }
208 if (!_unbuffered) {
209 // Sync write area.
210 PRInt32 waiting;
211 if ((waiting = pptr() - pbase()) != 0) {
212 PRInt32 nout;
213 if ((nout = PR_Write(_fd, pbase(), waiting)) != waiting) {
214 if (nout > 0) {
215 // Should set _pptr -= nout.
216 pbump(-nout);
217 memmove(pbase(), pbase() + nout, waiting - nout);
218 }
219 return traits_type::eof();
220 }
221 }
222 setp(NULL, NULL); // Empty put area.
224 if (PR_GetDescType(_fd) == PR_DESC_FILE) {
225 // Sockets can't seek; don't need this.
226 PROffset64 avail;
227 if ((avail = in_avail()) > 0) {
228 if (PR_Seek64(_fd, -avail, PR_SEEK_CUR) != -1) {
229 return traits_type::eof();
230 }
231 }
232 }
233 setg(NULL, NULL, NULL); // Empty get area.
234 }
236 return 0;
237 }
240 streambuf::int_type PRfilebuf::underflow()
241 {
242 PRInt32 count;
243 char_type byte;
245 if (gptr() != NULL && gptr() < egptr()) {
246 return traits_type::to_int_type(*gptr());
247 }
249 // Make sure there is a reserve area.
250 if (!_unbuffered && _buf_base == NULL && !allocate()) {
251 return traits_type::eof();
252 }
254 // Sync before new buffer created below.
255 if (traits_type::eq_int_type(sync(), traits_type::eof())) {
256 return traits_type::eof();
257 }
259 if (_unbuffered) {
260 if (PR_Read(_fd, &byte, 1) <= 0) {
261 return traits_type::eof();
262 }
264 return traits_type::to_int_type(byte);
265 }
267 if ((count = PR_Read(_fd, _buf_base, _buf_end - _buf_base)) <= 0) {
268 return traits_type::eof(); // Reached EOF.
269 }
271 setg(_buf_base, _buf_base, _buf_base + count);
272 return traits_type::to_int_type(*gptr());
273 }
276 streambuf::int_type PRfilebuf::overflow(int_type c)
277 {
278 // Make sure there is a reserve area.
279 if (!_unbuffered && _buf_base == NULL && !allocate()) {
280 return traits_type::eof();
281 }
283 // Sync before new buffer created below.
284 if (traits_type::eq_int_type(sync(), traits_type::eof())) {
285 return traits_type::eof();
286 }
288 if (!_unbuffered) {
289 setp(_buf_base, _buf_end);
290 }
292 if (!traits_type::eq_int_type(c, traits_type::eof())) {
293 // Extract the byte to be written.
294 // (Required on big-endian architectures.)
295 char_type byte = traits_type::to_char_type(c);
296 if (!_unbuffered && pptr() < epptr()) { // Guard against recursion.
297 return sputc(byte);
298 } else {
299 if (PR_Write(_fd, &byte, 1) != 1) {
300 return traits_type::eof();
301 }
302 }
303 }
305 return traits_type::not_eof(c);
306 }
309 bool PRfilebuf::allocate()
310 {
311 char_type *buf = new(nothrow) char_type[BUFSIZ];
312 if (buf == NULL) {
313 return false;
314 }
316 setb(buf, buf + BUFSIZ, true);
317 return true;
318 }
321 void PRfilebuf::setb(char_type *buf_base, char_type *buf_end, bool user_buf)
322 {
323 if (_buf_base && !_user_buf) {
324 delete[] _buf_base;
325 }
327 _buf_base = buf_base;
328 _buf_end = buf_end;
329 _user_buf = user_buf;
330 }
333 PRifstream::PRifstream():
334 istream(NULL),
335 _filebuf()
336 {
337 init(&_filebuf);
338 }
341 PRifstream::PRifstream(PRFileDesc *fd):
342 istream(NULL),
343 _filebuf(fd)
344 {
345 init(&_filebuf);
346 }
349 PRifstream::PRifstream(PRFileDesc *fd, char_type *ptr, streamsize len):
350 istream(NULL),
351 _filebuf(fd, ptr, len)
352 {
353 init(&_filebuf);
354 }
357 PRifstream::PRifstream(const char *name, openmode flags, PRIntn mode):
358 istream(NULL),
359 _filebuf()
360 {
361 init(&_filebuf);
362 if (!_filebuf.open(name, flags | in, mode)) {
363 setstate(failbit);
364 }
365 }
368 PRifstream::~PRifstream() { }
371 void PRifstream::open(const char *name, openmode flags, PRIntn mode)
372 {
373 if (is_open() || !_filebuf.open(name, flags | in, mode)) {
374 setstate(failbit);
375 }
376 }
379 void PRifstream::attach(PRFileDesc *fd)
380 {
381 if (!_filebuf.attach(fd)) {
382 setstate(failbit);
383 }
384 }
387 void PRifstream::close()
388 {
389 if (_filebuf.close() == NULL) {
390 setstate(failbit);
391 }
392 }
395 PRofstream::PRofstream():
396 ostream(NULL),
397 _filebuf()
398 {
399 init(&_filebuf);
400 }
403 PRofstream::PRofstream(PRFileDesc *fd):
404 ostream(NULL),
405 _filebuf(fd)
406 {
407 init(&_filebuf);
408 }
411 PRofstream::PRofstream(PRFileDesc *fd, char_type *ptr, streamsize len):
412 ostream(NULL),
413 _filebuf(fd, ptr, len)
414 {
415 init(&_filebuf);
416 }
419 PRofstream::PRofstream(const char *name, openmode flags, PRIntn mode):
420 ostream(NULL),
421 _filebuf()
422 {
423 init(&_filebuf);
424 if (!_filebuf.open(name, flags | out, mode)) {
425 setstate(failbit);
426 }
427 }
430 PRofstream::~PRofstream() { }
433 void PRofstream::open(const char *name, openmode flags, PRIntn mode)
434 {
435 if (is_open() || !_filebuf.open(name, flags | out, mode)) {
436 setstate(failbit);
437 }
438 }
441 void PRofstream::attach(PRFileDesc *fd)
442 {
443 if (!_filebuf.attach(fd)) {
444 setstate(failbit);
445 }
446 }
449 void PRofstream::close()
450 {
451 if (_filebuf.close() == NULL) {
452 setstate(failbit);
453 }
454 }
457 PRfstream::PRfstream():
458 iostream(NULL),
459 _filebuf()
460 {
461 init(&_filebuf);
462 }
465 PRfstream::PRfstream(PRFileDesc *fd):
466 iostream(NULL),
467 _filebuf(fd)
468 {
469 init(&_filebuf);
470 }
473 PRfstream::PRfstream(PRFileDesc *fd, char_type *ptr, streamsize len):
474 iostream(NULL),
475 _filebuf(fd, ptr, len)
476 {
477 init(&_filebuf);
478 }
481 PRfstream::PRfstream(const char *name, openmode flags, PRIntn mode):
482 iostream(NULL),
483 _filebuf()
484 {
485 init(&_filebuf);
486 if (!_filebuf.open(name, flags | in | out, mode)) {
487 setstate(failbit);
488 }
489 }
492 PRfstream::~PRfstream() { }
495 void PRfstream::open(const char *name, openmode flags, PRIntn mode)
496 {
497 if (is_open() || !_filebuf.open(name, flags | in | out, mode)) {
498 setstate(failbit);
499 }
500 }
503 void PRfstream::attach(PRFileDesc *fd)
504 {
505 if (!_filebuf.attach(fd)) {
506 setstate(failbit);
507 }
508 }
511 void PRfstream::close()
512 {
513 if (_filebuf.close() == NULL) {
514 setstate(failbit);
515 }
516 }