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