00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifdef HAVE_CONFIG_H
00035 #include <config.h>
00036 #endif
00037
00038 #include <iostream>
00039
00040 #include "zfstream.h"
00041
00042 #ifdef HAVE_ZLIB
00043
00044 #include <cstring>
00045 #include <cstdio>
00046
00047
00048 #define STASHED_CHARACTERS 16
00049 #define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS)
00050 #define SMALLBUFSIZE 1
00051
00052
00053
00054
00055 gzfilebuf::gzfilebuf()
00056 : file(0), io_mode(std::ios_base::openmode(0)), own_fd(false),
00057 buffer(0), buffer_size(BIGBUFSIZE), own_buffer(true)
00058 {
00059
00060 this->disable_buffer();
00061 }
00062
00063
00064 gzfilebuf::~gzfilebuf()
00065 {
00066
00067
00068 this->sync();
00069 if (own_fd)
00070 this->close();
00071
00072 this->disable_buffer();
00073 }
00074
00075
00076 int
00077 gzfilebuf::setcompression(int comp_level,
00078 int comp_strategy)
00079 {
00080 return gzsetparams(file, comp_level, comp_strategy);
00081 }
00082
00083
00084 gzfilebuf*
00085 gzfilebuf::open(const char *name,
00086 std::ios_base::openmode mode)
00087 {
00088
00089 if (this->is_open())
00090 return 0;
00091
00092 if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
00093 return 0;
00094
00095
00096 char char_mode[6] = "\0\0\0\0\0";
00097 if (!this->open_mode(mode, char_mode))
00098 return 0;
00099
00100
00101 if ((file = gzopen(name, char_mode)) == 0)
00102 return 0;
00103
00104
00105 this->enable_buffer();
00106 io_mode = mode;
00107 own_fd = true;
00108 return this;
00109 }
00110
00111
00112 gzfilebuf*
00113 gzfilebuf::attach(int fd,
00114 std::ios_base::openmode mode)
00115 {
00116
00117 if (this->is_open())
00118 return 0;
00119
00120 if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
00121 return 0;
00122
00123
00124 char char_mode[6] = "\0\0\0\0\0";
00125 if (!this->open_mode(mode, char_mode))
00126 return 0;
00127
00128
00129 if ((file = gzdopen(fd, char_mode)) == 0)
00130 return 0;
00131
00132
00133 this->enable_buffer();
00134 io_mode = mode;
00135 own_fd = false;
00136 return this;
00137 }
00138
00139
00140 gzfilebuf*
00141 gzfilebuf::close()
00142 {
00143
00144 if (!this->is_open())
00145 return 0;
00146
00147 gzfilebuf* retval = this;
00148
00149 if (this->sync() == -1)
00150 retval = 0;
00151 if (gzclose(file) < 0)
00152 retval = 0;
00153
00154 file = 0;
00155 own_fd = false;
00156
00157 this->disable_buffer();
00158 return retval;
00159 }
00160
00161
00162
00163
00164 bool
00165 gzfilebuf::open_mode(std::ios_base::openmode mode,
00166 char* c_mode) const
00167 {
00168
00169
00170 bool testi = mode & std::ios_base::in;
00171 bool testo = mode & std::ios_base::out;
00172 bool testt = mode & std::ios_base::trunc;
00173 bool testa = mode & std::ios_base::app;
00174
00175
00176
00177
00178
00179
00180 if (!testi && testo && !testt && !testa)
00181 strcpy(c_mode, "w");
00182 if (!testi && testo && !testt && testa)
00183 strcpy(c_mode, "a");
00184 if (!testi && testo && testt && !testa)
00185 strcpy(c_mode, "w");
00186 if (testi && !testo && !testt && !testa)
00187 strcpy(c_mode, "r");
00188
00189
00190
00191
00192
00193
00194
00195 if (strlen(c_mode) == 0)
00196 return false;
00197
00198 strcat(c_mode, "b");
00199
00200 return true;
00201 }
00202
00203
00204 std::streamsize
00205 gzfilebuf::showmanyc()
00206 {
00207
00208 if (!this->is_open() || !(io_mode & std::ios_base::in))
00209 return -1;
00210
00211 if (this->gptr() && (this->gptr() < this->egptr()))
00212 return std::streamsize(this->egptr() - this->gptr());
00213 else
00214 return 0;
00215 }
00216
00217
00218
00219
00220
00221 gzfilebuf::int_type
00222 gzfilebuf::pbackfail (gzfilebuf::int_type c)
00223 {
00224 if (this->is_open())
00225 {
00226 if (gzseek (file, this->gptr() - this->egptr() - 1, SEEK_CUR) < 0)
00227 return traits_type::eof();
00228
00229
00230 enable_buffer ();
00231
00232
00233
00234 int bytes_read = gzread(file, buffer, buffer_size);
00235
00236 if (bytes_read <= 0)
00237 {
00238
00239 this->setg(buffer, buffer, buffer);
00240 return traits_type::eof();
00241 }
00242
00243
00244 this->setg(buffer, buffer, buffer + bytes_read);
00245
00246
00247
00248 gzfilebuf::int_type ret = traits_type::to_int_type(*(this->gptr()));
00249 if (ret != c)
00250 return traits_type::eof();
00251 else
00252 return ret;
00253 }
00254 else
00255 return traits_type::eof();
00256 }
00257
00258
00259 gzfilebuf::int_type
00260 gzfilebuf::underflow()
00261 {
00262
00263
00264
00265 if (this->gptr() && (this->gptr() < this->egptr()))
00266 return traits_type::to_int_type(*(this->gptr()));
00267
00268
00269 if (!this->is_open() || !(io_mode & std::ios_base::in))
00270 return traits_type::eof();
00271
00272
00273 int stash = 0;
00274 if (this->eback() && buffer && buffer_size > STASHED_CHARACTERS)
00275 {
00276 char_type *ptr1 = buffer;
00277 char_type *ptr2 = this->egptr() - STASHED_CHARACTERS + 1;
00278 if (ptr2 > this->eback())
00279 while (stash++ <= STASHED_CHARACTERS)
00280 *ptr1++ = *ptr2++;
00281 }
00282
00283
00284
00285 int bytes_read = gzread(file, buffer + stash, buffer_size - stash);
00286
00287
00288 if (bytes_read <= 0)
00289 {
00290
00291 this->setg(buffer, buffer, buffer);
00292 return traits_type::eof();
00293 }
00294
00295 this->setg(buffer, buffer + stash, buffer + bytes_read + stash);
00296
00297
00298 return traits_type::to_int_type(*(this->gptr()));
00299 }
00300
00301
00302 gzfilebuf::int_type
00303 gzfilebuf::overflow(int_type c)
00304 {
00305
00306 if (this->pbase())
00307 {
00308
00309 if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
00310 return traits_type::eof();
00311
00312 if (!traits_type::eq_int_type(c, traits_type::eof()))
00313 {
00314 *(this->pptr()) = traits_type::to_char_type(c);
00315 this->pbump(1);
00316 }
00317
00318 int bytes_to_write = this->pptr() - this->pbase();
00319
00320 if (bytes_to_write > 0)
00321 {
00322
00323 if (!this->is_open() || !(io_mode & std::ios_base::out))
00324 return traits_type::eof();
00325
00326 if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
00327 return traits_type::eof();
00328
00329 this->pbump(-bytes_to_write);
00330 }
00331 }
00332
00333 else if (!traits_type::eq_int_type(c, traits_type::eof()))
00334 {
00335
00336 if (!this->is_open() || !(io_mode & std::ios_base::out))
00337 return traits_type::eof();
00338
00339 char_type last_char = traits_type::to_char_type(c);
00340
00341 if (gzwrite(file, &last_char, 1) != 1)
00342 return traits_type::eof();
00343 }
00344
00345
00346
00347 if (traits_type::eq_int_type(c, traits_type::eof()))
00348 return traits_type::not_eof(c);
00349 else
00350 return c;
00351 }
00352
00353
00354 std::streambuf*
00355 gzfilebuf::setbuf(char_type* p,
00356 std::streamsize n)
00357 {
00358
00359 if (this->sync() == -1)
00360 return 0;
00361
00362
00363
00364
00365 if (!p || !n)
00366 {
00367
00368 this->disable_buffer();
00369 buffer = 0;
00370 buffer_size = 0;
00371 own_buffer = true;
00372 this->enable_buffer();
00373 }
00374 else
00375 {
00376
00377 this->disable_buffer();
00378 buffer = p;
00379 buffer_size = n;
00380 own_buffer = false;
00381 this->enable_buffer();
00382 }
00383 return this;
00384 }
00385
00386
00387 int
00388 gzfilebuf::sync()
00389 {
00390 return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
00391 }
00392
00393
00394
00395
00396 void
00397 gzfilebuf::enable_buffer()
00398 {
00399
00400 if (own_buffer && !buffer)
00401 {
00402
00403 if (buffer_size > 0)
00404 {
00405
00406 buffer = new char_type[buffer_size];
00407
00408 this->setg(buffer, buffer, buffer);
00409
00410
00411
00412
00413 this->setp(buffer, buffer + buffer_size - 1);
00414 }
00415 else
00416 {
00417
00418 buffer_size = SMALLBUFSIZE;
00419 buffer = new char_type[buffer_size];
00420 this->setg(buffer, buffer, buffer);
00421
00422 this->setp(0, 0);
00423 }
00424 }
00425 else
00426 {
00427
00428
00429 this->setg(buffer, buffer, buffer);
00430 this->setp(buffer, buffer + buffer_size - 1);
00431 }
00432 }
00433
00434
00435 void
00436 gzfilebuf::disable_buffer()
00437 {
00438
00439 if (own_buffer && buffer)
00440 {
00441
00442 if (!this->pbase())
00443 buffer_size = 0;
00444 delete[] buffer;
00445 buffer = 0;
00446 this->setg(0, 0, 0);
00447 this->setp(0, 0);
00448 }
00449 else
00450 {
00451
00452 this->setg(buffer, buffer, buffer);
00453 if (buffer)
00454 this->setp(buffer, buffer + buffer_size - 1);
00455 else
00456 this->setp(0, 0);
00457 }
00458 }
00459
00460
00461
00462
00463 gzfilebuf::pos_type
00464 gzfilebuf::seekoff(off_type off, std::ios_base::seekdir way,
00465 std::ios_base::openmode)
00466 {
00467 pos_type ret = pos_type (off_type (-1));
00468
00469 if (this->is_open())
00470 {
00471 off_type computed_off = off;
00472
00473 if ((io_mode & std::ios_base::in) && way == std::ios_base::cur)
00474 computed_off += this->gptr() - this->egptr();
00475
00476
00477
00478 if (off == 0 && way == std::ios_base::cur)
00479 return pos_type (gztell (file) + computed_off);
00480
00481 if (way == std::ios_base::beg)
00482 ret = pos_type (gzseek (file, computed_off, SEEK_SET));
00483 else if (way == std::ios_base::cur)
00484 ret = pos_type (gzseek (file, computed_off, SEEK_CUR));
00485 else
00486
00487 ret = pos_type (gzseek (file, computed_off, SEEK_END));
00488
00489 if (io_mode & std::ios_base::in)
00490
00491 enable_buffer ();
00492 else
00493
00494 overflow ();
00495 }
00496
00497 return ret;
00498 }
00499
00500 gzfilebuf::pos_type
00501 gzfilebuf::seekpos(pos_type sp, std::ios_base::openmode)
00502 {
00503 pos_type ret = pos_type (off_type (-1));
00504
00505 if (this->is_open ())
00506 {
00507 ret = pos_type (gzseek (file, sp, SEEK_SET));
00508
00509 if (io_mode & std::ios_base::in)
00510
00511 enable_buffer ();
00512 else
00513
00514 overflow ();
00515 }
00516
00517 return ret;
00518 }
00519
00520
00521
00522
00523 gzifstream::gzifstream()
00524 : std::istream(0), sb()
00525 { this->init(&sb); }
00526
00527
00528 gzifstream::gzifstream(const char* name,
00529 std::ios_base::openmode mode)
00530 : std::istream(0), sb()
00531 {
00532 this->init(&sb);
00533 this->open(name, mode);
00534 }
00535
00536
00537 gzifstream::gzifstream(int fd,
00538 std::ios_base::openmode mode)
00539 : std::istream(0), sb()
00540 {
00541 this->init(&sb);
00542 this->attach(fd, mode);
00543 }
00544
00545
00546 void
00547 gzifstream::open(const char* name,
00548 std::ios_base::openmode mode)
00549 {
00550 if (!sb.open(name, mode | std::ios_base::in))
00551 this->setstate(std::ios_base::failbit);
00552 else
00553 this->clear();
00554 }
00555
00556
00557 void
00558 gzifstream::attach(int fd,
00559 std::ios_base::openmode mode)
00560 {
00561 if (!sb.attach(fd, mode | std::ios_base::in))
00562 this->setstate(std::ios_base::failbit);
00563 else
00564 this->clear();
00565 }
00566
00567
00568 void
00569 gzifstream::close()
00570 {
00571 if (!sb.close())
00572 this->setstate(std::ios_base::failbit);
00573 }
00574
00575
00576
00577
00578 gzofstream::gzofstream()
00579 : std::ostream(0), sb()
00580 { this->init(&sb); }
00581
00582
00583 gzofstream::gzofstream(const char* name,
00584 std::ios_base::openmode mode)
00585 : std::ostream(0), sb()
00586 {
00587 this->init(&sb);
00588 this->open(name, mode);
00589 }
00590
00591
00592 gzofstream::gzofstream(int fd,
00593 std::ios_base::openmode mode)
00594 : std::ostream(0), sb()
00595 {
00596 this->init(&sb);
00597 this->attach(fd, mode);
00598 }
00599
00600
00601 void
00602 gzofstream::open(const char* name,
00603 std::ios_base::openmode mode)
00604 {
00605 if (!sb.open(name, mode | std::ios_base::out))
00606 this->setstate(std::ios_base::failbit);
00607 else
00608 this->clear();
00609 }
00610
00611
00612 void
00613 gzofstream::attach(int fd,
00614 std::ios_base::openmode mode)
00615 {
00616 if (!sb.attach(fd, mode | std::ios_base::out))
00617 this->setstate(std::ios_base::failbit);
00618 else
00619 this->clear();
00620 }
00621
00622
00623 void
00624 gzofstream::close()
00625 {
00626 if (!sb.close())
00627 this->setstate(std::ios_base::failbit);
00628 }
00629
00630 #endif // HAVE_ZLIB