Mercurial > jwe > octave
comparison libinterp/corefcn/gzfstream.cc @ 30123:d809b99f1280
maint: rename "zfstream.[h|cc]" to "gzfstream.[h|cc]" to match class name.
* gzfstream.cc: Renamed from zfstream.cc
* gzfstream.h: Renamed from zfstream.h
* libinterp/corefcn/module.mk: Rename files in build system.
* load-save.cc: Update #include to renamed file.
author | Rik <rik@octave.org> |
---|---|
date | Sun, 05 Sep 2021 19:40:02 -0700 |
parents | libinterp/corefcn/zfstream.cc@a7813409b8c6 |
children | 4412f57132c4 |
comparison
equal
deleted
inserted
replaced
30122:a7813409b8c6 | 30123:d809b99f1280 |
---|---|
1 //////////////////////////////////////////////////////////////////////// | |
2 // | |
3 // Copyright (C) 2005-2021 The Octave Project Developers | |
4 // | |
5 // See the file COPYRIGHT.md in the top-level directory of this | |
6 // distribution or <https://octave.org/copyright/>. | |
7 // | |
8 // This file is part of Octave. | |
9 // | |
10 // Octave is free software: you can redistribute it and/or modify it | |
11 // under the terms of the GNU General Public License as published by | |
12 // the Free Software Foundation, either version 3 of the License, or | |
13 // (at your option) any later version. | |
14 // | |
15 // Octave is distributed in the hope that it will be useful, but | |
16 // WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 // GNU General Public License for more details. | |
19 // | |
20 // You should have received a copy of the GNU General Public License | |
21 // along with Octave; see the file COPYING. If not, see | |
22 // <https://www.gnu.org/licenses/>. | |
23 // | |
24 //////////////////////////////////////////////////////////////////////// | |
25 | |
26 /* | |
27 | |
28 This file is adapted from the zlib 1.2.2 contrib/iostream3 code, | |
29 written by | |
30 | |
31 Ludwig Schwardt <schwardt@sun.ac.za> | |
32 original version by Kevin Ruland <kevin@rodin.wustl.edu> | |
33 | |
34 */ | |
35 | |
36 #if defined (HAVE_CONFIG_H) | |
37 # include "config.h" | |
38 #endif | |
39 | |
40 #include <iomanip> | |
41 #include <istream> | |
42 #include <ostream> | |
43 | |
44 #include "gzfstream.h" | |
45 | |
46 #if defined (HAVE_ZLIB) | |
47 | |
48 // For strcpy, strcat, strlen (mode strings). | |
49 #include <cstring> | |
50 // For BUFSIZ. | |
51 #include <cstdio> | |
52 | |
53 // Internal buffer sizes (default and "unbuffered" versions) | |
54 #define STASHED_CHARACTERS 16 | |
55 #define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS) | |
56 #define SMALLBUFSIZE 1 | |
57 | |
58 // Default constructor | |
59 gzfilebuf::gzfilebuf () | |
60 : m_file(nullptr), m_io_mode(std::ios_base::openmode(0)), m_own_fd(false), | |
61 m_buffer(nullptr), m_buffer_size(BIGBUFSIZE), m_own_buffer(true) | |
62 { | |
63 // No buffers to start with | |
64 this->disable_buffer (); | |
65 } | |
66 | |
67 // Destructor | |
68 gzfilebuf::~gzfilebuf () | |
69 { | |
70 // Sync output buffer and close only if responsible for file | |
71 // (i.e., attached streams should be left open at this stage) | |
72 this->sync (); | |
73 if (m_own_fd) | |
74 this->close (); | |
75 // Make sure internal buffer is deallocated | |
76 this->disable_buffer (); | |
77 } | |
78 | |
79 // Set compression level and strategy | |
80 int | |
81 gzfilebuf::setcompression (int comp_level, int comp_strategy) | |
82 { | |
83 return gzsetparams (m_file, comp_level, comp_strategy); | |
84 } | |
85 | |
86 // Open gzipped file | |
87 gzfilebuf* | |
88 gzfilebuf::open (const char *name, std::ios_base::openmode mode) | |
89 { | |
90 // Fail if file already open | |
91 if (this->is_open ()) | |
92 return nullptr; | |
93 // Don't support simultaneous read/write access (yet) | |
94 if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) | |
95 return nullptr; | |
96 | |
97 // Build mode string for gzopen and check it [27.8.1.3.2] | |
98 char char_mode[6] = "\0\0\0\0\0"; | |
99 if (! this->open_mode (mode, char_mode)) | |
100 return nullptr; | |
101 | |
102 // Attempt to open file | |
103 if ((m_file = gzopen (name, char_mode)) == nullptr) | |
104 return nullptr; | |
105 | |
106 // On success, allocate internal buffer and set flags | |
107 this->enable_buffer (); | |
108 m_io_mode = mode; | |
109 m_own_fd = true; | |
110 return this; | |
111 } | |
112 | |
113 // Attach to gzipped file | |
114 gzfilebuf* | |
115 gzfilebuf::attach (int fd, std::ios_base::openmode mode) | |
116 { | |
117 // Fail if file already open | |
118 if (this->is_open ()) | |
119 return nullptr; | |
120 // Don't support simultaneous read/write access (yet) | |
121 if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) | |
122 return nullptr; | |
123 | |
124 // Build mode string for gzdopen and check it [27.8.1.3.2] | |
125 char char_mode[6] = "\0\0\0\0\0"; | |
126 if (! this->open_mode (mode, char_mode)) | |
127 return nullptr; | |
128 | |
129 // Attempt to attach to file | |
130 if ((m_file = gzdopen (fd, char_mode)) == nullptr) | |
131 return nullptr; | |
132 | |
133 // On success, allocate internal buffer and set flags | |
134 this->enable_buffer (); | |
135 m_io_mode = mode; | |
136 m_own_fd = false; | |
137 return this; | |
138 } | |
139 | |
140 // Close gzipped file | |
141 gzfilebuf* | |
142 gzfilebuf::close () | |
143 { | |
144 // Fail immediately if no file is open | |
145 if (! this->is_open ()) | |
146 return nullptr; | |
147 // Assume success | |
148 gzfilebuf *retval = this; | |
149 // Attempt to sync and close gzipped file | |
150 if (this->sync () == -1) | |
151 retval = nullptr; | |
152 if (gzclose (m_file) < 0) | |
153 retval = nullptr; | |
154 // File is now gone anyway (postcondition [27.8.1.3.8]) | |
155 m_file = nullptr; | |
156 m_own_fd = false; | |
157 // Destroy internal buffer if it exists | |
158 this->disable_buffer (); | |
159 return retval; | |
160 } | |
161 | |
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
163 | |
164 // Convert int open mode to mode string | |
165 bool | |
166 gzfilebuf::open_mode (std::ios_base::openmode mode, char *c_mode) const | |
167 { | |
168 // FIXME: do we need testb? | |
169 // bool testb = mode & std::ios_base::binary; | |
170 bool testi = mode & std::ios_base::in; | |
171 bool testo = mode & std::ios_base::out; | |
172 bool testt = mode & std::ios_base::trunc; | |
173 bool testa = mode & std::ios_base::app; | |
174 | |
175 // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) | |
176 // Original zfstream hardcoded the compression level to maximum here... | |
177 // Double the time for less than 1% size improvement seems | |
178 // excessive though - keeping it at the default level | |
179 // To change back, just append "9" to the next three mode strings | |
180 if (! testi && testo && ! testt && ! testa) | |
181 strcpy (c_mode, "w"); | |
182 if (! testi && testo && ! testt && testa) | |
183 strcpy (c_mode, "a"); | |
184 if (! testi && testo && testt && ! testa) | |
185 strcpy (c_mode, "w"); | |
186 if (testi && ! testo && ! testt && ! testa) | |
187 strcpy (c_mode, "r"); | |
188 // No read/write mode yet | |
189 // if (testi && testo && ! testt && ! testa) | |
190 // strcpy(c_mode, "r+"); | |
191 // if (testi && testo && testt && ! testa) | |
192 // strcpy(c_mode, "w+"); | |
193 | |
194 // Mode string should be empty for invalid combination of flags | |
195 if (strlen (c_mode) == 0) | |
196 return false; | |
197 | |
198 strcat (c_mode, "b"); | |
199 | |
200 return true; | |
201 } | |
202 | |
203 // Determine number of characters in internal get buffer | |
204 std::streamsize | |
205 gzfilebuf::showmanyc () | |
206 { | |
207 // Calls to underflow will fail if file not opened for reading | |
208 if (! this->is_open () || ! (m_io_mode & std::ios_base::in)) | |
209 return -1; | |
210 // Make sure get area is in use | |
211 if (this->gptr () && (this->gptr () < this->egptr ())) | |
212 return std::streamsize (this->egptr () - this->gptr ()); | |
213 else | |
214 return 0; | |
215 } | |
216 | |
217 // Puts back a character to the stream in two cases. Firstly, when there | |
218 // is no putback position available, and secondly when the character putback | |
219 // differs from the one in the file. We can only support the first case | |
220 // with gzipped files. | |
221 gzfilebuf::int_type | |
222 gzfilebuf::pbackfail (gzfilebuf::int_type c) | |
223 { | |
224 if (this->is_open ()) | |
225 { | |
226 if (gzseek (m_file, this->gptr () - this->egptr () - 1, SEEK_CUR) < 0) | |
227 return traits_type::eof (); | |
228 | |
229 // Invalidates contents of the buffer | |
230 enable_buffer (); | |
231 | |
232 // Attempt to fill internal buffer from gzipped file | |
233 // (buffer must be guaranteed to exist...) | |
234 int bytes_read = gzread (m_file, m_buffer, m_buffer_size); | |
235 // Indicates error or EOF | |
236 if (bytes_read <= 0) | |
237 { | |
238 // Reset get area | |
239 this->setg (m_buffer, m_buffer, m_buffer); | |
240 return traits_type::eof (); | |
241 } | |
242 | |
243 // Make all bytes read from file available as get area | |
244 this->setg (m_buffer, m_buffer, m_buffer + bytes_read); | |
245 | |
246 // If next character in get area differs from putback character | |
247 // flag a failure | |
248 gzfilebuf::int_type ret = traits_type::to_int_type (*(this->gptr ())); | |
249 if (ret != c) | |
250 return traits_type::eof (); | |
251 else | |
252 return ret; | |
253 } | |
254 else | |
255 return traits_type::eof (); | |
256 } | |
257 | |
258 // Fill get area from gzipped file | |
259 gzfilebuf::int_type | |
260 gzfilebuf::underflow () | |
261 { | |
262 // If something is left in the get area by chance, return it | |
263 // (this shouldn't normally happen, as underflow is only supposed | |
264 // to be called when gptr >= egptr, but it serves as error check) | |
265 if (this->gptr () && (this->gptr () < this->egptr ())) | |
266 return traits_type::to_int_type (*(this->gptr ())); | |
267 | |
268 // If the file hasn't been opened for reading, produce error | |
269 if (! this->is_open () || ! (m_io_mode & std::ios_base::in)) | |
270 return traits_type::eof (); | |
271 | |
272 // Copy the final characters to the front of the buffer | |
273 int stash = 0; | |
274 if (this->eback () && m_buffer && m_buffer_size > STASHED_CHARACTERS) | |
275 { | |
276 char_type *ptr1 = m_buffer; | |
277 char_type *ptr2 = this->egptr () - STASHED_CHARACTERS + 1; | |
278 if (ptr2 > this->eback ()) | |
279 while (stash++ <= STASHED_CHARACTERS) | |
280 *ptr1++ = *ptr2++; | |
281 } | |
282 | |
283 // Attempt to fill internal buffer from gzipped file | |
284 // (buffer must be guaranteed to exist...) | |
285 int bytes_read = gzread (m_file, m_buffer + stash, m_buffer_size - stash); | |
286 | |
287 // Indicates error or EOF | |
288 if (bytes_read <= 0) | |
289 { | |
290 // Reset get area | |
291 this->setg (m_buffer, m_buffer, m_buffer); | |
292 return traits_type::eof (); | |
293 } | |
294 // Make all bytes read from file plus the stash available as get area | |
295 this->setg (m_buffer, m_buffer + stash, m_buffer + bytes_read + stash); | |
296 | |
297 // Return next character in get area | |
298 return traits_type::to_int_type (*(this->gptr ())); | |
299 } | |
300 | |
301 // Write put area to gzipped file | |
302 gzfilebuf::int_type | |
303 gzfilebuf::overflow (int_type c) | |
304 { | |
305 // Determine whether put area is in use | |
306 if (this->pbase ()) | |
307 { | |
308 // Double-check pointer range | |
309 if (this->pptr () > this->epptr () || this->pptr () < this->pbase ()) | |
310 return traits_type::eof (); | |
311 // Add extra character to buffer if not EOF | |
312 if (! traits_type::eq_int_type (c, traits_type::eof ())) | |
313 { | |
314 *(this->pptr ()) = traits_type::to_char_type (c); | |
315 this->pbump (1); | |
316 } | |
317 // Number of characters to write to file | |
318 int bytes_to_write = this->pptr () - this->pbase (); | |
319 // Overflow doesn't fail if nothing is to be written | |
320 if (bytes_to_write > 0) | |
321 { | |
322 // If the file hasn't been opened for writing, produce error | |
323 if (! this->is_open () || ! (m_io_mode & std::ios_base::out)) | |
324 return traits_type::eof (); | |
325 // If gzipped file won't accept all bytes written to it, fail | |
326 if (gzwrite (m_file, this->pbase (), bytes_to_write) | |
327 != bytes_to_write) | |
328 return traits_type::eof (); | |
329 // Reset next pointer to point to pbase on success | |
330 this->pbump (-bytes_to_write); | |
331 } | |
332 } | |
333 // Write extra character to file if not EOF | |
334 else if (! traits_type::eq_int_type (c, traits_type::eof ())) | |
335 { | |
336 // If the file hasn't been opened for writing, produce error | |
337 if (! this->is_open () || ! (m_io_mode & std::ios_base::out)) | |
338 return traits_type::eof (); | |
339 // Impromptu char buffer (allows "unbuffered" output) | |
340 char_type last_char = traits_type::to_char_type (c); | |
341 // If gzipped file won't accept this character, fail | |
342 if (gzwrite (m_file, &last_char, 1) != 1) | |
343 return traits_type::eof (); | |
344 } | |
345 | |
346 // If you got here, you have succeeded (even if c was EOF) | |
347 // The return value should therefore be non-EOF | |
348 if (traits_type::eq_int_type (c, traits_type::eof ())) | |
349 return traits_type::not_eof (c); | |
350 else | |
351 return c; | |
352 } | |
353 | |
354 // Assign new buffer | |
355 std::streambuf* | |
356 gzfilebuf::setbuf (char_type *p, std::streamsize n) | |
357 { | |
358 // First make sure stuff is sync'ed, for safety | |
359 if (this->sync () == -1) | |
360 return nullptr; | |
361 // If buffering is turned off on purpose via setbuf(0,0), still allocate one. | |
362 // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at | |
363 // least a buffer of size 1 (very inefficient though, therefore make it | |
364 // bigger?). This follows from [27.5.2.4.3]/12 (gptr needs to point at | |
365 // something, it seems). | |
366 if (! p || ! n) | |
367 { | |
368 // Replace existing buffer (if any) with small internal buffer | |
369 this->disable_buffer (); | |
370 m_buffer = nullptr; | |
371 m_buffer_size = 0; | |
372 m_own_buffer = true; | |
373 this->enable_buffer (); | |
374 } | |
375 else | |
376 { | |
377 // Replace existing buffer (if any) with external buffer | |
378 this->disable_buffer (); | |
379 m_buffer = p; | |
380 m_buffer_size = n; | |
381 m_own_buffer = false; | |
382 this->enable_buffer (); | |
383 } | |
384 return this; | |
385 } | |
386 | |
387 // Write put area to gzipped file (i.e., ensures that put area is empty) | |
388 int | |
389 gzfilebuf::sync () | |
390 { | |
391 return traits_type::eq_int_type (this->overflow (), | |
392 traits_type::eof ()) ? -1 : 0; | |
393 } | |
394 | |
395 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
396 | |
397 // Allocate internal buffer | |
398 void | |
399 gzfilebuf::enable_buffer () | |
400 { | |
401 // If internal buffer required, allocate one | |
402 if (m_own_buffer && ! m_buffer) | |
403 { | |
404 // Check for buffered vs. "unbuffered" | |
405 if (m_buffer_size > 0) | |
406 { | |
407 // Allocate internal buffer | |
408 m_buffer = new char_type [m_buffer_size]; | |
409 // Get area starts empty and will be expanded by underflow as needed | |
410 this->setg (m_buffer, m_buffer, m_buffer); | |
411 // Setup entire internal buffer as put area. | |
412 // The one-past-end pointer actually points to the last element of | |
413 // the buffer, so that overflow(c) can safely add the extra character | |
414 // c to the sequence. These pointers remain in place for the | |
415 // duration of the buffer | |
416 this->setp (m_buffer, m_buffer + m_buffer_size - 1); | |
417 } | |
418 else | |
419 { | |
420 // Even in "unbuffered" case, (small?) get buffer is still required | |
421 m_buffer_size = SMALLBUFSIZE; | |
422 m_buffer = new char_type [m_buffer_size]; | |
423 this->setg (m_buffer, m_buffer, m_buffer); | |
424 // "Unbuffered" means no put buffer | |
425 this->setp (nullptr, nullptr); | |
426 } | |
427 } | |
428 else | |
429 { | |
430 // If buffer already allocated, reset buffer pointers just to make sure no | |
431 // stale chars are lying around | |
432 this->setg (m_buffer, m_buffer, m_buffer); | |
433 this->setp (m_buffer, m_buffer + m_buffer_size - 1); | |
434 } | |
435 } | |
436 | |
437 // Destroy internal buffer | |
438 void | |
439 gzfilebuf::disable_buffer () | |
440 { | |
441 // If internal buffer exists, deallocate it | |
442 if (m_own_buffer && m_buffer) | |
443 { | |
444 // Preserve unbuffered status by zeroing size | |
445 if (! this->pbase ()) | |
446 m_buffer_size = 0; | |
447 delete [] m_buffer; | |
448 m_buffer = nullptr; | |
449 this->setg (nullptr, nullptr, nullptr); | |
450 this->setp (nullptr, nullptr); | |
451 } | |
452 else | |
453 { | |
454 // Reset buffer pointers to initial state if external buffer exists | |
455 this->setg (m_buffer, m_buffer, m_buffer); | |
456 if (m_buffer) | |
457 this->setp (m_buffer, m_buffer + m_buffer_size - 1); | |
458 else | |
459 this->setp (nullptr, nullptr); | |
460 } | |
461 } | |
462 | |
463 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
464 | |
465 // Seek functions | |
466 gzfilebuf::pos_type | |
467 gzfilebuf::seekoff (off_type off, std::ios_base::seekdir way, | |
468 std::ios_base::openmode) | |
469 { | |
470 pos_type ret = pos_type (off_type (-1)); | |
471 | |
472 if (this->is_open ()) | |
473 { | |
474 off_type computed_off = off; | |
475 | |
476 if ((m_io_mode & std::ios_base::in) && way == std::ios_base::cur) | |
477 computed_off += this->gptr () - this->egptr (); | |
478 | |
479 // Handle tellg/tellp as a special case up front, no need to seek | |
480 // or invalidate get/put buffers | |
481 if (off == 0 && way == std::ios_base::cur) | |
482 return pos_type (gztell (m_file) + computed_off); | |
483 | |
484 if (way == std::ios_base::beg) | |
485 ret = pos_type (gzseek (m_file, computed_off, SEEK_SET)); | |
486 else if (way == std::ios_base::cur) | |
487 ret = pos_type (gzseek (m_file, computed_off, SEEK_CUR)); | |
488 else | |
489 // Can't seek from end of a gzipped file, so this will give -1 | |
490 ret = pos_type (gzseek (m_file, computed_off, SEEK_END)); | |
491 | |
492 if (m_io_mode & std::ios_base::in) | |
493 // Invalidates contents of the buffer | |
494 enable_buffer (); | |
495 else | |
496 // flush contents of buffer to file | |
497 overflow (); | |
498 } | |
499 | |
500 return ret; | |
501 } | |
502 | |
503 gzfilebuf::pos_type | |
504 gzfilebuf::seekpos (pos_type sp, std::ios_base::openmode) | |
505 { | |
506 pos_type ret = pos_type (off_type (-1)); | |
507 | |
508 if (this->is_open ()) | |
509 { | |
510 ret = pos_type (gzseek (m_file, sp, SEEK_SET)); | |
511 | |
512 if (m_io_mode & std::ios_base::in) | |
513 // Invalidates contents of the buffer | |
514 enable_buffer (); | |
515 else | |
516 // flush contents of buffer to file | |
517 overflow (); | |
518 } | |
519 | |
520 return ret; | |
521 } | |
522 | |
523 // Default constructor initializes stream buffer | |
524 gzifstream::gzifstream () | |
525 : std::istream (nullptr), sb () | |
526 { this->init (&sb); } | |
527 | |
528 // Initialize stream buffer and open file | |
529 gzifstream::gzifstream (const char *name, std::ios_base::openmode mode) | |
530 : std::istream (nullptr), sb () | |
531 { | |
532 this->init (&sb); | |
533 this->open (name, mode); | |
534 } | |
535 | |
536 // Initialize stream buffer and attach to file | |
537 gzifstream::gzifstream (int fd, std::ios_base::openmode mode) | |
538 : std::istream (nullptr), sb () | |
539 { | |
540 this->init (&sb); | |
541 this->attach (fd, mode); | |
542 } | |
543 | |
544 // Open file and go into fail() state if unsuccessful | |
545 void | |
546 gzifstream::open (const char *name, std::ios_base::openmode mode) | |
547 { | |
548 if (! sb.open (name, mode | std::ios_base::in)) | |
549 this->setstate (std::ios_base::failbit); | |
550 else | |
551 this->clear (); | |
552 } | |
553 | |
554 // Attach to file and go into fail() state if unsuccessful | |
555 void | |
556 gzifstream::attach (int fd, std::ios_base::openmode mode) | |
557 { | |
558 if (! sb.attach (fd, mode | std::ios_base::in)) | |
559 this->setstate (std::ios_base::failbit); | |
560 else | |
561 this->clear (); | |
562 } | |
563 | |
564 // Close file | |
565 void | |
566 gzifstream::close () | |
567 { | |
568 if (! sb.close ()) | |
569 this->setstate (std::ios_base::failbit); | |
570 } | |
571 | |
572 // Default constructor initializes stream buffer | |
573 gzofstream::gzofstream () | |
574 : std::ostream (nullptr), sb () | |
575 { this->init (&sb); } | |
576 | |
577 // Initialize stream buffer and open file | |
578 gzofstream::gzofstream (const char *name, std::ios_base::openmode mode) | |
579 : std::ostream (nullptr), sb () | |
580 { | |
581 this->init (&sb); | |
582 this->open (name, mode); | |
583 } | |
584 | |
585 // Initialize stream buffer and attach to file | |
586 gzofstream::gzofstream (int fd, std::ios_base::openmode mode) | |
587 : std::ostream (nullptr), sb () | |
588 { | |
589 this->init (&sb); | |
590 this->attach (fd, mode); | |
591 } | |
592 | |
593 // Open file and go into fail() state if unsuccessful | |
594 void | |
595 gzofstream::open (const char *name, std::ios_base::openmode mode) | |
596 { | |
597 if (! sb.open (name, mode | std::ios_base::out)) | |
598 this->setstate (std::ios_base::failbit); | |
599 else | |
600 this->clear (); | |
601 } | |
602 | |
603 // Attach to file and go into fail() state if unsuccessful | |
604 void | |
605 gzofstream::attach (int fd, std::ios_base::openmode mode) | |
606 { | |
607 if (! sb.attach (fd, mode | std::ios_base::out)) | |
608 this->setstate (std::ios_base::failbit); | |
609 else | |
610 this->clear (); | |
611 } | |
612 | |
613 // Close file | |
614 void | |
615 gzofstream::close () | |
616 { | |
617 if (! sb.close ()) | |
618 this->setstate (std::ios_base::failbit); | |
619 } | |
620 | |
621 #endif |