GzStream.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                                                                      |
00003 |                      __   __    ____ _____ ____                      |
00004 |                      \ \ / /_ _/ ___|_   _|___ \                     |
00005 |                       \ V / _` \___ \ | |   __) |                    |
00006 |                        | | (_| |___) || |  / __/                     |
00007 |                        |_|\__,_|____/ |_| |_____|                    |
00008 |                                                                      |
00009 |                               core system                            |
00010 |                                         (C) SuSE Linux Products GmbH |
00011 \----------------------------------------------------------------------/
00012 
00013   File:       GzStream.cc
00014 
00015   Author:     Michael Andres <ma@suse.de>
00016   Maintainer: Michael Andres <ma@suse.de>
00017 
00018   Purpose: Streams reading and writing gzip files.
00019 
00020 /-*/
00021 
00022 #include <cerrno>
00023 #include <iostream>
00024 #include <zypp/base/LogControl.h>
00025 #include <zypp/base/LogTools.h>
00026 using std::endl;
00027 
00028 #include "zypp/base/GzStream.h"
00029 
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <fcntl.h>
00033 
00035 namespace zypp
00036 { 
00037 
00038   namespace gzstream_detail
00039   { 
00040 
00041 
00043     //
00044     //  CLASS NAME : ZlibError
00045     //
00047 
00049     //
00050     //  METHOD NAME : ZlibError::strerror
00051     //  METHOD TYPE : std::string
00052     //
00053     std::string
00054     ZlibError::strerror() const
00055     {
00056       std::string ret = ( _zError ? ::zError( _zError ) : "OK" );
00057       if ( _zError == Z_ERRNO )
00058         ret += std::string("(") + ::strerror( _errno ) + ")";
00059       return ret;
00060     }
00061 
00063     //
00064     //  CLASS NAME : fgzstreambuf
00065     //
00067 
00069     //
00070     //  METHOD NAME : fgzstreambuf::open
00071     //  METHOD TYPE : fgzstreambuf *
00072     //
00073     fgzstreambuf *
00074     fgzstreambuf::open( const char * name_r, std::ios_base::openmode mode_r )
00075     {
00076       fgzstreambuf * ret = NULL;
00077       if ( ! isOpen() )
00078         {
00079           // we expect gzdopen to handle errors of ::open
00080           if ( mode_r == std::ios_base::in )
00081           {
00082             _fd = ::open( name_r, O_RDONLY );
00083             _file = gzdopen( _fd, "rb" );
00084           }
00085           else if ( mode_r == std::ios_base::out )
00086           {
00087             _fd = ::open( name_r, O_WRONLY|O_CREAT, 0666 );
00088             _file = gzdopen( _fd, "wb" );
00089           }
00090           // else: not supported
00091 
00092           if ( isOpen() )
00093             {
00094               // Store mode and initialize the internal buffer.
00095               _mode = mode_r;
00096               if ( inReadMode() )
00097                 {
00098                   setp( NULL, NULL );
00099                   setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
00100                 }
00101               else
00102                 {
00103                   setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) );
00104                   setg( NULL, NULL, NULL );
00105                 }
00106               ret = this;
00107             }
00108           else
00109             setZError();
00110         }
00111       return ret;
00112     }
00113 
00115     //
00116     //  METHOD NAME : fgzstreambuf::close
00117     //  METHOD TYPE : fgzstreambuf *
00118     //
00119     fgzstreambuf *
00120     fgzstreambuf::close()
00121     {
00122       fgzstreambuf * ret = NULL;
00123       if ( isOpen() )
00124         {
00125           bool failed = false;
00126           if ( sync() != 0 )
00127             failed = true;
00128           // it also closes _fd, fine
00129           int r = gzclose( _file );
00130           if ( r != Z_OK )
00131             {
00132               failed = true;
00133               // DONT call setZError() here, as _file is no longer valid
00134               _error._zError = r;
00135               _error._errno = errno;
00136             }
00137 
00138           // Reset everything
00139           _fd = -1;
00140           _file = NULL;
00141           _mode = std::ios_base::openmode(0);
00142           setp( NULL, NULL );
00143           setg( NULL, NULL, NULL );
00144           if ( ! failed )
00145             ret = this;
00146         }
00147       return ret;
00148     }
00149 
00151     //
00152     //  METHOD NAME : fgzstreambuf::sync
00153     //  METHOD TYPE : int
00154     //
00155     int
00156     fgzstreambuf::sync()
00157     {
00158       int ret = 0;
00159       if ( pbase() < pptr() ) {
00160         const int_type res = overflow();
00161         if ( traits_type::eq_int_type( res, traits_type::eof() ) )
00162           ret = -1;
00163       }
00164       return ret;
00165     }
00166 
00168     //
00169     //  METHOD NAME : fgzstreambuf::overflow
00170     //  METHOD TYPE : fgzstreambuf::int_type
00171     //
00172     fgzstreambuf::int_type
00173     fgzstreambuf::overflow( int_type c )
00174     {
00175       int_type ret = traits_type::eof();
00176       if ( inWriteMode() )
00177         {
00178           if ( ! traits_type::eq_int_type( c, traits_type::eof() ) )
00179             {
00180               *pptr() = traits_type::to_char_type( c );
00181               pbump(1);
00182             }
00183           if ( pbase() <= pptr() )
00184             {
00185               if ( zWriteFrom( pbase(), pptr() - pbase() ) )
00186                 {
00187                   setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) );
00188                   ret = traits_type::not_eof( c );
00189                 }
00190               // else: error writing the file
00191             }
00192         }
00193       return ret;
00194     }
00195 
00197     //
00198     //  METHOD NAME : fgzstreambuf::underflow
00199     //  METHOD TYPE : fgzstreambuf::int_type
00200     //
00201     fgzstreambuf::int_type
00202     fgzstreambuf::underflow()
00203     {
00204       int_type ret = traits_type::eof();
00205       if ( inReadMode() )
00206         {
00207           if ( gptr() < egptr() )
00208             return traits_type::to_int_type( *gptr() );
00209 
00210           const std::streamsize got = zReadTo( &(_buffer[0]), _buffer.size() );
00211           if ( got > 0 )
00212             {
00213               setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[got]) );
00214               ret = traits_type::to_int_type( *gptr() );
00215             }
00216           else if ( got == 0 )
00217             {
00218               // EOF
00219               setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
00220             }
00221           // else: error reading the file
00222         }
00223       return ret;
00224     }
00225 
00227     //
00228     //  METHOD NAME : fgzstreambuf::zReadTo
00229     //  METHOD TYPE : std::streamsize
00230     //
00231     std::streamsize
00232     fgzstreambuf::zReadTo( char * buffer_r, std::streamsize maxcount_r )
00233     {
00234       int read = gzread( _file, buffer_r, maxcount_r );
00235       if ( read < 0 )
00236         setZError();
00237       return read;
00238     }
00239 
00241     //
00242     //  METHOD NAME : fgzstreambuf::zWriteFrom
00243     //  METHOD TYPE : bool
00244     //
00245     bool
00246     fgzstreambuf::zWriteFrom( const char * buffer_r, std::streamsize count_r )
00247     {
00248       int written = 0;
00249       if ( count_r )
00250         {
00251           if ( (written = gzwrite( _file, buffer_r, count_r )) == 0 )
00252             setZError();
00253         }
00254       return( written == count_r );
00255     }
00256 
00258     //
00259     //  METHOD NAME : fgzstreambuf::zSeekTo
00260     //  METHOD TYPE : fgzstreambuf::pos_type
00261     //
00262     fgzstreambuf::pos_type
00263     fgzstreambuf::zSeekTo( off_type off_r, std::ios_base::seekdir way_r )
00264     {
00265       z_off_t ret = gzseek( _file, off_r, way_r );
00266       if ( ret == -1 )
00267         setZError();
00268       return ret;
00269     }
00270 
00272     //
00273     //  METHOD NAME : fgzstreambuf::zTell
00274     //  METHOD TYPE : fgzstreambuf::pos_type
00275     //
00276     fgzstreambuf::pos_type
00277     fgzstreambuf::zTell()
00278     {
00279       z_off_t ret = gztell( _file );
00280       if ( ret == -1 )
00281         setZError();
00282       return ret;
00283     }
00284 
00286     //
00287     //  METHOD NAME : fgzstreambuf::seekTo
00288     //  METHOD TYPE : fgzstreambuf::pos_type
00289     //
00290     fgzstreambuf::pos_type
00291     fgzstreambuf::seekTo( off_type off_r, std::ios_base::seekdir way_r )
00292     {
00293       pos_type ret = pos_type(off_type(-1));
00294       if ( isOpen() )
00295         {
00296           if ( inWriteMode() )
00297             {
00298               if ( sync() == 0 )
00299                 ret = zSeekTo( off_r, way_r );
00300             }
00301           else
00302             {
00303               off_type zegptr = zTell();
00304               if ( zegptr != off_type(-1) )
00305                 {
00306                   if ( way_r == std::ios_base::end )
00307                     {
00308                       // Invalidate buffer and seek.
00309                       // XXX improve by transformation into ios_base::beg
00310                       // to see whether we stay inside the buffer.
00311                       setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
00312                       ret = zSeekTo( off_r, way_r );
00313                     }
00314                   else
00315                     {
00316                       // Transform into ios_base::beg and seek.
00317                       off_type zeback = zegptr - ( egptr() - eback() );
00318                       off_type zgptr  = zegptr - ( egptr() - gptr() );
00319                       off_type zngptr = off_r;
00320                       if ( way_r == std::ios_base::cur )
00321                         {
00322                           zngptr += zgptr;
00323                           way_r = std::ios_base::beg;
00324                         }
00325 
00326                       if ( way_r == std::ios_base::beg )
00327                         {
00328                           if ( zeback <= zngptr && zngptr <= zegptr )
00329                             {
00330                               // Still inside buffer, adjust gptr and
00331                               // calculate new position.
00332                               setg( eback(),
00333                                     eback() + (zngptr-zeback),
00334                                     egptr() );
00335                               ret = pos_type(zngptr);
00336                             }
00337                           else
00338                             {
00339                               // Invalidate buffer and seek.
00340                               setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
00341                               ret = zSeekTo( off_r, way_r );
00342                             }
00343                         }
00344                     }
00345                 }
00346             }
00347         }
00348       return ret;
00349     }
00350 
00351     fgzstreambuf::pos_type
00352     fgzstreambuf::compressed_tell() const
00353     {
00354         off_t pos = lseek (_fd, 0, SEEK_CUR);
00355         // hopefully the conversion is ok
00356         return pos;
00357     }
00358 
00360   } // namespace gzstream_detail
00363 } // namespace zypp
00365 

doxygen