prstrms.cpp 11 KB

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