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