00001
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
00032
00033 #ifndef GROOVX_RUTZ_BZIP2STREAM_CC_UTC20060614220240_DEFINED
00034 #define GROOVX_RUTZ_BZIP2STREAM_CC_UTC20060614220240_DEFINED
00035
00036 #include "rutz/bzip2stream.h"
00037
00038 #include "rutz/error.h"
00039 #include "rutz/fstring.h"
00040 #include "rutz/sfmt.h"
00041 #include "rutz/shared_ptr.h"
00042
00043 #ifdef HAVE_BZLIB_H
00044 #include <bzlib.h>
00045 #endif
00046 #include <fstream>
00047 #include <iostream>
00048
00049 #include "rutz/trace.h"
00050
00051 using rutz::sfmt;
00052 using rutz::error;
00053 using rutz::fstring;
00054 using rutz::shared_ptr;
00055
00056 #ifndef HAVE_BZLIB_H
00057
00058 shared_ptr<std::ostream> rutz::obzip2open(const fstring& filename,
00059 std::ios::openmode flags)
00060 {
00061 fstring bzip2_ext(".bz2");
00062
00063 if (filename.ends_with(bzip2_ext))
00064 {
00065 throw error(sfmt("couldn't open file '%s' for writing: "
00066 "bzip2 libraries must be installed",
00067 filename.c_str()), SRC_POS);
00068 }
00069 else
00070 {
00071 shared_ptr<std::ostream> result =
00072 make_shared(new std::ofstream(filename.c_str(), flags));
00073 if (result->fail())
00074 throw error(sfmt("couldn't open file '%s' for writing",
00075 filename.c_str()), SRC_POS);
00076
00077 return result;
00078 }
00079 }
00080
00081 shared_ptr<std::istream> rutz::ibzip2open(const fstring& filename,
00082 std::ios::openmode flags)
00083 {
00084 fstring bzip2_ext(".bz2");
00085
00086 if (filename.ends_with(bzip2_ext))
00087 {
00088 throw error(sfmt("couldn't open file '%s' for reading: "
00089 "bzip2 libraries must be installed",
00090 filename.c_str()), SRC_POS);
00091 }
00092 else
00093 {
00094 shared_ptr<std::istream> result =
00095 make_shared(new std::ifstream(filename.c_str(), flags));
00096 if (result->fail())
00097 throw error(sfmt("couldn't open file '%s' for reading",
00098 filename.c_str()), SRC_POS);
00099
00100 return result;
00101 }
00102 }
00103
00104 #else
00105
00106 namespace
00107 {
00108 class bzip2streambuf : public std::streambuf
00109 {
00110 private:
00111 bool m_opened;
00112 int m_mode;
00113 FILE* m_file;
00114 BZFILE* m_bzfile;
00115
00116 bzip2streambuf(const bzip2streambuf&);
00117 bzip2streambuf& operator=(const bzip2streambuf&);
00118
00119 static const int s_buf_size = 4092;
00120 static const int s_pback_size = 4;
00121 char m_buf[s_buf_size];
00122
00123 int flushoutput();
00124
00125 public:
00126 bzip2streambuf(const char* name, int om);
00127 ~bzip2streambuf() { close(); }
00128
00129 bool is_open() { return m_opened; }
00130
00131 void ensure_open();
00132
00133 void close();
00134
00135 virtual int underflow();
00136
00137 virtual int overflow(int c);
00138
00139 virtual int sync();
00140 };
00141
00142 class bzip2stream : public std::iostream
00143 {
00144 private:
00145 bzip2streambuf m_buf;
00146 public:
00147 bzip2stream(const char* filename_cstr,
00148 std::ios::openmode mode)
00149 :
00150 std::iostream(0),
00151 m_buf(filename_cstr, mode)
00152 {
00153 rdbuf(&m_buf);
00154 }
00155 };
00156
00157 bzip2streambuf::bzip2streambuf(const char* name, int om)
00158 :
00159 m_opened(false),
00160 m_mode(0),
00161 m_file(0),
00162 m_bzfile(0)
00163 {
00164
00165 if ( (om & std::ios::ate) || (om & std::ios::app)
00166 || ((om & std::ios::in) && (om & std::ios::out)) )
00167 {
00168 ;
00169 }
00170 else
00171 {
00172 if (om & std::ios::in)
00173 {
00174 m_file = fopen(name, "rb");
00175
00176 if (m_file == 0)
00177 throw error(sfmt("couldn't open file '%s' for reading",
00178 name), SRC_POS);
00179
00180 int bzerror = BZ_OK;
00181 m_bzfile = BZ2_bzReadOpen(&bzerror, m_file,
00182 0,
00183 0,
00184 0,
00185 0);
00186
00187 if (m_bzfile == 0)
00188 {
00189 fclose(m_file);
00190
00191 throw error(sfmt("couldn't open file '%s' for "
00192 "bzip2 decompression", name), SRC_POS);
00193 }
00194
00195 setg(m_buf+s_pback_size,
00196 m_buf+s_pback_size,
00197 m_buf+s_pback_size);
00198 }
00199 else if (om & std::ios::out)
00200 {
00201 m_file = fopen(name, "wb");
00202
00203 if (m_file == 0)
00204 throw error(sfmt("couldn't open file '%s' for writing",
00205 name), SRC_POS);
00206
00207 int bzerror = BZ_OK;
00208 m_bzfile = BZ2_bzWriteOpen(&bzerror, m_file,
00209 9,
00210 0,
00211 30);
00212
00213 if (m_bzfile == 0)
00214 {
00215 fclose(m_file);
00216
00217 throw error(sfmt("couldn't open file '%s' for "
00218 "bzip2 compression", name), SRC_POS);
00219 }
00220
00221 setp(m_buf, m_buf+(s_buf_size-1));
00222 }
00223
00224 if (m_bzfile != NULL)
00225 {
00226 m_opened = true;
00227 m_mode = om;
00228 }
00229 }
00230
00231 if (!m_opened)
00232 {
00233 if (om & std::ios::in)
00234 {
00235 throw error(sfmt("couldn't open file '%s' for reading",
00236 name), SRC_POS);
00237 }
00238 else if (om & std::ios::out)
00239 {
00240 throw error(sfmt("couldn't open file '%s' for writing",
00241 name), SRC_POS);
00242 }
00243 }
00244 }
00245
00246 void bzip2streambuf::close()
00247 {
00248 if (m_opened)
00249 {
00250 sync();
00251 m_opened = false;
00252
00253 int bzerror = BZ_OK;
00254
00255 if (m_mode & std::ios::in)
00256 BZ2_bzReadClose(&bzerror, m_bzfile);
00257 else
00258 BZ2_bzWriteClose(&bzerror, m_bzfile, 0, 0, 0);
00259
00260 fclose(m_file);
00261 }
00262 }
00263
00264 int bzip2streambuf::underflow()
00265 {
00266 GVX_TRACE("bzip2streambuf::underflow");
00267
00268 if (gptr() < egptr())
00269 return *gptr();
00270
00271 int numPutback = 0;
00272 if (s_pback_size > 0)
00273 {
00274
00275
00276
00277 numPutback = gptr() - eback();
00278 if (numPutback > 4)
00279 numPutback = 4;
00280
00281
00282
00283 std::memcpy (m_buf+(4-numPutback), gptr()-numPutback,
00284 numPutback);
00285 }
00286
00287
00288 int bzerror = BZ_OK;
00289 const int num =
00290 BZ2_bzRead(&bzerror, m_bzfile,
00291 m_buf+s_pback_size, s_buf_size-s_pback_size);
00292
00293 if (num <= 0)
00294 return EOF;
00295
00296
00297
00298
00299
00300 if (bzerror != BZ_OK && bzerror != BZ_STREAM_END)
00301 return EOF;
00302
00303
00304 setg (m_buf+s_pback_size-numPutback,
00305 m_buf+s_pback_size,
00306 m_buf+s_pback_size+num);
00307
00308
00309
00310
00311
00312
00313 return static_cast<unsigned char>(*gptr());
00314 }
00315
00316 int bzip2streambuf::overflow(int c)
00317 {
00318 GVX_TRACE("bzip2streambuf::overflow");
00319 if (!(m_mode & std::ios::out) || !m_opened) return EOF;
00320
00321 if (c != EOF)
00322 {
00323
00324 *pptr() = c;
00325 pbump(1);
00326 }
00327
00328 if (flushoutput() == EOF)
00329 {
00330 return -1;
00331 }
00332
00333 return c;
00334 }
00335
00336 int bzip2streambuf::sync()
00337 {
00338 if (flushoutput() == EOF)
00339 {
00340 return -1;
00341 }
00342 return 0;
00343 }
00344
00345 int bzip2streambuf::flushoutput()
00346 {
00347 if (!(m_mode & std::ios::out) || !m_opened) return EOF;
00348
00349 const int num = pptr()-pbase();
00350 int bzerror = BZ_OK;
00351 BZ2_bzWrite(&bzerror, m_bzfile, pbase(), num);
00352
00353 if (bzerror != BZ_OK)
00354 return EOF;
00355
00356 pbump(-num);
00357 return num;
00358 }
00359 }
00360
00361 shared_ptr<std::ostream> rutz::obzip2open(const fstring& filename,
00362 std::ios::openmode flags)
00363 {
00364 fstring bzip2_ext(".bz2");
00365
00366 if (filename.ends_with(bzip2_ext))
00367 {
00368 return shared_ptr<std::ostream>
00369 (new bzip2stream(filename.c_str(), std::ios::out|flags));
00370 }
00371 else
00372 {
00373 shared_ptr<std::ostream> result =
00374 make_shared(new std::ofstream(filename.c_str(), flags));
00375 if (result->fail())
00376 throw error(sfmt("couldn't open file '%s' for writing",
00377 filename.c_str()), SRC_POS);
00378
00379 return result;
00380 }
00381 }
00382
00383 shared_ptr<std::istream> rutz::ibzip2open(const fstring& filename,
00384 std::ios::openmode flags)
00385 {
00386 fstring bzip2_ext(".bz2");
00387
00388 if (filename.ends_with(bzip2_ext))
00389 {
00390 return shared_ptr<std::istream>
00391 (new bzip2stream(filename.c_str(), std::ios::in|flags));
00392 }
00393 else
00394 {
00395 shared_ptr<std::istream> result =
00396 make_shared(new std::ifstream(filename.c_str(), flags));
00397 if (result->fail())
00398 throw error(sfmt("couldn't open file '%s' for reading",
00399 filename.c_str()), SRC_POS);
00400
00401 return result;
00402 }
00403 }
00404
00405 #endif // defined(HAVE_BZLIB_H)
00406
00407 shared_ptr<std::ostream> rutz::obzip2open(const char* filename,
00408 std::ios::openmode flags)
00409 {
00410 return obzip2open(fstring(filename), flags);
00411 }
00412
00413 shared_ptr<std::istream> rutz::ibzip2open(const char* filename,
00414 std::ios::openmode flags)
00415 {
00416 return ibzip2open(fstring(filename), flags);
00417 }
00418
00419 static const char vcid_groovx_rutz_bzip2stream_cc_utc20060614220240[] = "$Id: bzip2stream.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/rutz/bzip2stream.cc $";
00420 #endif // !GROOVX_RUTZ_BZIP2STREAM_CC_UTC20060614220240DEFINED