]> git.donarmstrong.com Git - flightcrew.git/blob - src/zipios/src/inflateinputstreambuf.cpp
Imported Upstream version 0.7.2+dfsg
[flightcrew.git] / src / zipios / src / inflateinputstreambuf.cpp
1
2 #include "zipios++/zipios-config.h"
3
4 #include "zipios++/meta-iostreams.h"
5
6 #include <zlib.h>
7
8 #include "zipios++/fcollexceptions.h"
9 #include "zipios++/inflateinputstreambuf.h"
10
11 #include "outputstringstream.h"
12
13 namespace zipios {
14
15 using std::cerr ;
16 using std::endl ;
17
18 InflateInputStreambuf::InflateInputStreambuf( streambuf *inbuf, int s_pos, bool del_inbuf ) 
19   : FilterInputStreambuf( inbuf, del_inbuf ),
20     _zs_initialized ( false            ),
21     _invecsize      ( 1000             ),
22     _invec          ( _invecsize       ),
23     _outvecsize     ( 1000             ),
24     _outvec         ( _outvecsize      )
25 {
26   // NOTICE: It is important that this constructor and the methods it
27   // calls doesn't do anything with the input streambuf _inbuf, other
28   // than repositioning it to the specified position. The reason is
29   // that this class can be subclassed, and the subclass should get a
30   // chance to read from the buffer first)
31
32   // zlib init:
33   _zs.zalloc = Z_NULL ;
34   _zs.zfree  = Z_NULL ;
35   _zs.opaque = Z_NULL ;
36
37   reset( s_pos ) ;
38   // We're not checking the return value of reset() and throwing
39   // an exception in case of an error, because we cannot catch the exception
40   // in the constructors of subclasses with all compilers.
41 }
42
43 InflateInputStreambuf::~InflateInputStreambuf() {
44   // Dealloc z_stream stuff
45   int err = inflateEnd( &_zs ) ;
46   if( err != Z_OK ) {
47     cerr << "~inflatebuf: inflateEnd failed" ;
48 #ifdef HAVE_ZERROR
49     cerr << ": " << zError( err ) ;
50 #endif
51     cerr << endl ;
52   }
53 }
54
55
56 int InflateInputStreambuf::underflow() {
57   // If not underflow don't fill buffer
58   if ( gptr() < egptr() )
59     return static_cast< unsigned char >( *gptr() ) ;
60
61   // Prepare _outvec and get array pointers
62   _zs.avail_out = _outvecsize ; 
63   _zs.next_out  = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
64
65   // Inflate until _outvec is full
66   // eof (or I/O prob) on _inbuf will break out of loop too.
67   int err = Z_OK ;
68   while ( _zs.avail_out > 0 && err == Z_OK ) {
69     if ( _zs.avail_in == 0 ) { // fill _invec
70       int bc = static_cast< int >( _inbuf->sgetn( &(_invec[ 0 ] ) , 
71                               _invecsize ) ) ;
72       // FIXME: handle i/o problems.
73       _zs.next_in  = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ;
74       _zs.avail_in = bc ;
75       // If we could not read any new data (bc == 0) and inflate isn't
76       // done it will return Z_BUF_ERROR and thus breaks out of the
77       // loop. This means we don't have to respond to the situation
78       // where we can't read more bytes here.
79     }
80
81     err = inflate( &_zs, Z_NO_FLUSH ) ;
82   }
83   // Normally the number of inflated bytes will be the
84   // full length of the output buffer, but if we can't read
85   // more input from the _inbuf streambuf, we end up with
86   // less.
87   int inflated_bytes = _outvecsize - _zs.avail_out ;
88   setg( &( _outvec[ 0 ] ),
89         &( _outvec[ 0 ] ),
90         &( _outvec[ 0 ] ) + inflated_bytes ) ;
91   // FIXME: look at the error returned from inflate here, if there is
92   // some way to report it to the InflateInputStreambuf user.
93   // Until I find out I'll just print a warning to stdout.
94   if( err != Z_OK && err != Z_STREAM_END ) {
95 #if defined (HAVE_STD_IOSTREAM) && defined (USE_STD_IOSTREAM)
96     // Throw an exception to make istream set badbit
97     OutputStringStream msgs ;
98     msgs << "InflateInputStreambuf: inflate failed" ;
99 #ifdef HAVE_ZERROR
100     msgs << ": " << zError( err ) ;
101 #endif
102     throw IOException( msgs.str() ) ;
103 #endif
104     // If HAVE_STD_IOSTREAM not defined we just return eof
105     // if no output is produced, and that happens anyway
106   }
107   if (inflated_bytes > 0 )
108     return static_cast< unsigned char >( *gptr() ) ;
109   else 
110     return EOF ; // traits_type::eof() ;
111 }
112
113
114
115 // This method is called in the constructor, so it must not
116 // read anything from the input streambuf _inbuf (see notice in constructor)
117 bool InflateInputStreambuf::reset( int stream_position ) {
118   if ( stream_position >= 0 ) { // reposition _inbuf
119     _inbuf->pubseekpos( stream_position ) ;
120   }
121
122   // _zs.next_in and avail_in must be set according to
123   // zlib.h (inline doc).
124   _zs.next_in  = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ;
125   _zs.avail_in = 0 ;
126   
127   int err ;
128   if( _zs_initialized ) {                    // just reset it
129     err = inflateReset( &_zs ) ;
130   } else {                                   // init it
131     err = inflateInit2( &_zs, -MAX_WBITS ) ;
132     /* windowBits is passed < 0 to tell that there is no zlib header.
133      Note that in this case inflate *requires* an extra "dummy" byte
134      after the compressed stream in order to complete decompression
135      and return Z_STREAM_END.  We always have an extra "dummy" byte,
136      because there is always some trailing data after the compressed
137      data (either the next entry or the central directory.  */
138     _zs_initialized = true ;
139   }
140
141   // streambuf init:
142   // The important thing here, is that 
143   // - the pointers are not NULL (which would mean unbuffered)
144   // - and that gptr() is not less than  egptr() (so we trigger underflow
145   //   the first time data is read).
146   setg( &( _outvec[ 0 ] ),
147         &( _outvec[ 0 ] ) + _outvecsize,
148         &( _outvec[ 0 ] ) + _outvecsize ) ;
149
150   if ( err == Z_OK )
151     return true ;
152   else
153     return false ;
154 }
155
156 } // namespace
157
158 /** \file
159     Implementation of InflateInputStreambuf.
160 */
161
162 /*
163   Zipios++ - a small C++ library that provides easy access to .zip files.
164   Copyright (C) 2000  Thomas Søndergaard
165   
166   This library is free software; you can redistribute it and/or
167   modify it under the terms of the GNU Lesser General Public
168   License as published by the Free Software Foundation; either
169   version 2 of the License, or (at your option) any later version.
170   
171   This library is distributed in the hope that it will be useful,
172   but WITHOUT ANY WARRANTY; without even the implied warranty of
173   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
174   Lesser General Public License for more details.
175   
176   You should have received a copy of the GNU Lesser General Public
177   License along with this library; if not, write to the Free Software
178   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
179 */