]> git.donarmstrong.com Git - flightcrew.git/blob - src/zipios/src/zipoutputstreambuf.cpp
update changelog, target experimental
[flightcrew.git] / src / zipios / src / zipoutputstreambuf.cpp
1
2 #include <time.h>
3
4 #include "zipios++/zipios-config.h"
5
6 #include <algorithm>
7 #include "zipios++/meta-iostreams.h"
8
9 #include <zlib.h>
10
11 #include "zipios++/zipoutputstreambuf.h"
12
13 namespace zipios {
14
15 using std::ios ;
16 using std::cerr ;
17 using std::endl ;
18 //using std::min ;
19
20 ZipOutputStreambuf::ZipOutputStreambuf( streambuf *outbuf, bool del_outbuf ) 
21   : DeflateOutputStreambuf( outbuf, false, del_outbuf ),
22     _open_entry( false    ),
23     _open      ( true     ),
24     _method    ( DEFLATED ),
25     _level     ( 6        )
26 {
27 }
28
29
30 void ZipOutputStreambuf::closeEntry() {
31   if ( ! _open_entry )
32     return ;
33
34   closeStream() ;
35
36   updateEntryHeaderInfo() ;
37   setEntryClosedState( ) ;
38 }
39
40
41 void ZipOutputStreambuf::close() {
42   finish() ;
43 }
44
45
46 void ZipOutputStreambuf::finish() {
47   if( ! _open )
48     return ;
49   closeEntry() ;
50   ostream os( _outbuf ) ;
51   writeCentralDirectory( _entries, EndOfCentralDirectory( _zip_comment), os ) ;
52   _open = false ;
53 }
54
55
56 ZipOutputStreambuf::~ZipOutputStreambuf() {
57   finish() ;
58 }
59
60
61 void ZipOutputStreambuf::putNextEntry( const ZipCDirEntry &entry ) {
62   if ( _open_entry )
63     closeEntry() ;
64
65   if ( ! init( _level ) )
66     cerr << "ZipOutputStreambuf::putNextEntry(): init() failed!\n" ;
67
68   _entries.push_back( entry ) ;
69   ZipCDirEntry &ent = _entries.back() ;
70
71   ostream os( _outbuf ) ;
72
73   // Update entry header info
74   ent.setLocalHeaderOffset( static_cast< uint32 >( os.tellp() ) ) ;
75   ent.setMethod( _method ) ;
76   
77   os << static_cast< ZipLocalEntry >( ent ) ;
78
79   _open_entry = true ;
80 }
81
82
83 void ZipOutputStreambuf::setComment( const string &comment ) {
84   _zip_comment = comment ;
85 }
86
87
88 void ZipOutputStreambuf::setLevel( int level ) {
89   _level = level ;
90 }
91
92
93 void ZipOutputStreambuf::setMethod( StorageMethod method ) {
94   _method = method ;
95   if( method == STORED )
96     setLevel( NO_COMPRESSION ) ;
97   else if ( method == DEFLATED ) {
98     if( _level == NO_COMPRESSION )
99       setLevel( DEFAULT_COMPRESSION ) ; 
100   } else 
101     throw FCollException( "Specified compression method not supported" ) ;
102 }
103
104 //
105 // Protected and private methods
106 //
107
108 int ZipOutputStreambuf::overflow( int c ) {
109   return DeflateOutputStreambuf::overflow( c ) ;
110 //    // FIXME: implement
111   
112 //    cout << "ZipOutputStreambuf::overflow() not implemented yet!\n" ;
113 //    return EOF ;
114 }
115
116
117
118 int ZipOutputStreambuf::sync() {
119   return DeflateOutputStreambuf::sync() ;
120 //    // FIXME: implement
121 //    cout << "ZipOutputStreambuf::sync() not implemented yet!\n" ;
122 //    return EOF ;
123 }
124
125
126
127 void ZipOutputStreambuf::setEntryClosedState() {
128   _open_entry = false ;
129   // FIXME: update put pointers to trigger overflow on write. overflow
130   // should then return EOF while _open_entry is false.
131 }
132
133
134 void ZipOutputStreambuf::updateEntryHeaderInfo() {
135   if ( ! _open_entry )
136     return ;
137
138   ostream os( _outbuf ) ;
139   int curr_pos = static_cast< int >( os.tellp() ) ;
140   
141   // update fields in _entries.back()
142   ZipCDirEntry &entry = _entries.back() ;
143   entry.setSize( getCount() ) ;
144   entry.setCrc( getCrc32() ) ;
145   entry.setCompressedSize( curr_pos - entry.getLocalHeaderOffset() 
146                            - entry.getLocalHeaderSize() ) ;
147
148   // Mark Donszelmann: added current date and time
149   time_t ltime;
150   time( &ltime );
151   struct tm *now;
152   now = localtime( &ltime );
153   int dosTime = (now->tm_year - 80) << 25 | (now->tm_mon + 1) << 21 | now->tm_mday << 16 |
154               now->tm_hour << 11 | now->tm_min << 5 | now->tm_sec >> 1;
155   entry.setTime(dosTime);
156
157   // write ZipLocalEntry header to header position
158   os.seekp( entry.getLocalHeaderOffset() ) ;
159   os << static_cast< ZipLocalEntry >( entry ) ;
160   os.seekp( curr_pos ) ;
161 }
162
163
164 void ZipOutputStreambuf::writeCentralDirectory( const vector< ZipCDirEntry > &entries, 
165                                                 EndOfCentralDirectory eocd, 
166                                                 ostream &os ) {
167   int cdir_start = static_cast< int >( os.tellp() ) ;
168   std::vector< ZipCDirEntry >::const_iterator it ;
169   int cdir_size = 0 ;
170
171   for ( it = entries.begin() ; it != entries.end() ; ++it ) {
172     os << *it ;
173     cdir_size += it->getCDirHeaderSize() ;
174   }
175   eocd.setOffset( cdir_start ) ;
176   eocd.setCDirSize( cdir_size ) ;
177   eocd.setTotalCount( static_cast< uint16 >( entries.size() ) ) ;
178   os << eocd ;
179 }
180
181 } // namespace
182
183 /** \file
184     Implementation of ZipOutputStreambuf.
185 */
186
187 /*
188   Zipios++ - a small C++ library that provides easy access to .zip files.
189   Copyright (C) 2000  Thomas Søndergaard
190   
191   This library is free software; you can redistribute it and/or
192   modify it under the terms of the GNU Lesser General Public
193   License as published by the Free Software Foundation; either
194   version 2 of the License, or (at your option) any later version.
195   
196   This library is distributed in the hope that it will be useful,
197   but WITHOUT ANY WARRANTY; without even the implied warranty of
198   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
199   Lesser General Public License for more details.
200   
201   You should have received a copy of the GNU Lesser General Public
202   License along with this library; if not, write to the Free Software
203   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
204 */