zipoutputstreambuf.cpp
Go to the documentation of this file.00001
00002 #include "zipios-config.h"
00003
00004 #include <algorithm>
00005 #include <vector>
00006 #include <time.h>
00007 #include "meta-iostreams.h"
00008
00009 #include <zlib.h>
00010
00011 #include "zipoutputstreambuf.h"
00012
00013 namespace zipios {
00014
00015 using std::ios ;
00016 using std::cerr ;
00017 using std::endl ;
00018 using std::min ;
00019 using std::vector ;
00020
00021 ZipOutputStreambuf::ZipOutputStreambuf( streambuf *outbuf, bool del_outbuf )
00022 : DeflateOutputStreambuf( outbuf, false, del_outbuf ),
00023 _open_entry( false ),
00024 _open ( true ),
00025 _method ( DEFLATED ),
00026 _level ( 6 )
00027 {
00028 }
00029
00030
00031 void ZipOutputStreambuf::closeEntry() {
00032 if ( ! _open_entry )
00033 return ;
00034
00035 closeStream() ;
00036
00037 updateEntryHeaderInfo() ;
00038 setEntryClosedState( ) ;
00039 }
00040
00041
00042 void ZipOutputStreambuf::close() {
00043 finish() ;
00044 }
00045
00046
00047 void ZipOutputStreambuf::finish() {
00048 if( ! _open )
00049 return ;
00050 closeEntry() ;
00051 ostream os( _outbuf ) ;
00052 writeCentralDirectory( _entries, EndOfCentralDirectory( _zip_comment), os ) ;
00053 _open = false ;
00054 }
00055
00056
00057 ZipOutputStreambuf::~ZipOutputStreambuf() {
00058 finish() ;
00059 }
00060
00061
00062 void ZipOutputStreambuf::putNextEntry( const ZipCDirEntry &entry ) {
00063 if ( _open_entry )
00064 closeEntry() ;
00065
00066 if ( ! init( _level ) )
00067 cerr << "ZipOutputStreambuf::putNextEntry(): init() failed!\n" ;
00068
00069 _entries.push_back( entry ) ;
00070 ZipCDirEntry &ent = _entries.back() ;
00071
00072 ostream os( _outbuf ) ;
00073
00074
00075 ent.setLocalHeaderOffset( os.tellp() ) ;
00076 ent.setMethod( _method ) ;
00077
00078 os << static_cast< ZipLocalEntry >( ent ) ;
00079
00080 _open_entry = true ;
00081 }
00082
00083
00084 void ZipOutputStreambuf::setComment( const string &comment ) {
00085 _zip_comment = comment ;
00086 }
00087
00088
00089 void ZipOutputStreambuf::setLevel( int level ) {
00090 _level = level ;
00091 }
00092
00093
00094 void ZipOutputStreambuf::setMethod( StorageMethod method ) {
00095 _method = method ;
00096 if( method == STORED )
00097 setLevel( NO_COMPRESSION ) ;
00098 else if ( method == DEFLATED ) {
00099 if( _level == NO_COMPRESSION )
00100 setLevel( DEFAULT_COMPRESSION ) ;
00101 } else
00102 throw FCollException( "Specified compression method not supported" ) ;
00103 }
00104
00105
00106
00107
00108
00109 int ZipOutputStreambuf::overflow( int c ) {
00110 return DeflateOutputStreambuf::overflow( c ) ;
00111
00112
00113
00114
00115 }
00116
00117
00118
00119 int ZipOutputStreambuf::sync() {
00120 return DeflateOutputStreambuf::sync() ;
00121
00122
00123
00124 }
00125
00126
00127
00128 void ZipOutputStreambuf::setEntryClosedState() {
00129 _open_entry = false ;
00130
00131
00132 }
00133
00134
00135 void ZipOutputStreambuf::updateEntryHeaderInfo() {
00136 if ( ! _open_entry )
00137 return ;
00138
00139 ostream os( _outbuf ) ;
00140 int curr_pos = os.tellp() ;
00141
00142
00143 ZipCDirEntry &entry = _entries.back() ;
00144 entry.setSize( getCount() ) ;
00145 entry.setCrc( getCrc32() ) ;
00146 entry.setCompressedSize( curr_pos - entry.getLocalHeaderOffset()
00147 - entry.getLocalHeaderSize() ) ;
00148
00149
00150 time_t ltime;
00151 time( <ime );
00152 struct tm *now;
00153 now = localtime( <ime );
00154 int dosTime = (now->tm_year - 80) << 25 | (now->tm_mon + 1) << 21 | now->tm_mday << 16 |
00155 now->tm_hour << 11 | now->tm_min << 5 | now->tm_sec >> 1;
00156 entry.setTime(dosTime);
00157
00158
00159 os.seekp( entry.getLocalHeaderOffset() ) ;
00160 os << static_cast< ZipLocalEntry >( entry ) ;
00161 os.seekp( curr_pos ) ;
00162 }
00163
00164
00165 void ZipOutputStreambuf::writeCentralDirectory( const vector< ZipCDirEntry > &entries,
00166 EndOfCentralDirectory eocd,
00167 ostream &os ) {
00168 int cdir_start = os.tellp() ;
00169 std::vector< ZipCDirEntry >::const_iterator it ;
00170 int cdir_size = 0 ;
00171
00172 for ( it = entries.begin() ; it != entries.end() ; ++it ) {
00173 os << *it ;
00174 cdir_size += it->getCDirHeaderSize() ;
00175 }
00176 eocd.setOffset( cdir_start ) ;
00177 eocd.setCDirSize( cdir_size ) ;
00178 eocd.setTotalCount( entries.size() ) ;
00179 os << eocd ;
00180 }
00181
00182 }
00183
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205