]> git.donarmstrong.com Git - flightcrew.git/blob - src/zipios/src/zipfile.cpp
Imported Upstream version 0.7.2+dfsg
[flightcrew.git] / src / zipios / src / zipfile.cpp
1
2 #include "zipios++/zipios-config.h"
3
4 #include "zipios++/meta-iostreams.h"
5
6 #include "zipios++/fcoll.h"
7 #include "zipios++/zipfile.h"
8 #include "zipios++/zipinputstream.h"
9 #include "zipios++/zipios_defs.h"
10
11 #include "backbuffer.h"
12
13 #include "../../FlightCrew/Misc/BoostFilesystemUse.h"
14
15 namespace zipios {
16
17 //
18 // Public
19 //
20
21 ZipFile ZipFile::openEmbeddedZipFile( const string &name ) {
22   // open zipfile, read 4 last bytes close file
23   // create ZipFile object.
24   ifstream ifs( name.c_str(), ios::in | ios::binary ) ;
25   ifs.seekg( -4, ios::end ) ;
26   uint32 start_offset = readUint32( ifs ) ;
27   ifs.close() ;
28   return ZipFile( name, start_offset, 4 ) ; 
29 }
30
31
32 ZipFile::ZipFile( const string &name , int s_off, int e_off
33                   /* , ios::open_mode mode */ ) 
34   : _vs( s_off, e_off ) {
35
36   _filename = name ;
37   
38   ifstream _zipfile( name.c_str(), ios::in | ios::binary ) ;
39   init( _zipfile ) ;
40 }
41
42 ZipFile::ZipFile( const fs::path &name , int s_off, int e_off
43                   /* , ios::open_mode mode */ ) 
44   : _vs( s_off, e_off ) {
45
46   _filename = name.string();
47   
48   fs::ifstream _zipfile( name, ios::in | ios::binary ) ;
49   init( _zipfile ) ;
50 }
51
52
53 FileCollection *ZipFile::clone() const {
54   return new ZipFile( *this ) ;
55 }
56
57
58 ZipFile::~ZipFile() {
59   close() ;
60 }
61
62 void ZipFile::close() {
63   _valid = false ;
64
65 }
66
67 istream *ZipFile::getInputStream( const ConstEntryPointer &entry ) {
68   if ( ! _valid )
69     throw InvalidStateException( "Attempt to use an invalid FileCollection" ) ;
70   return getInputStream( entry->getName() ) ;
71 }
72
73 istream *ZipFile::getInputStream( const string &entry_name, 
74                                   MatchPath matchpath ) {
75   if ( ! _valid )
76     throw InvalidStateException( "Attempt to use an invalid ZipFile" ) ;
77
78   ConstEntryPointer ent = getEntry( entry_name, matchpath ) ;
79   
80   if ( ent == 0 )
81     return 0 ;
82   else {
83     ZipInputStream *zis( new ZipInputStream( _filename,
84       static_cast< const ZipCDirEntry * >( ent.get() )->
85       getLocalHeaderOffset() + _vs.startOffset() ) ) ;
86     zis->getNextEntry();
87     return zis;
88   }
89 }
90
91
92 //
93 // Private
94 //
95
96 bool ZipFile::init( istream &_zipfile ) {
97
98   // Check stream error state
99   if ( ! _zipfile ) {
100     setError ( "Error reading from file" ) ;
101     return false ;
102   }
103   
104   _valid = readCentralDirectory( _zipfile ) ;
105
106   return _valid ;
107 }
108
109
110 bool ZipFile::readCentralDirectory ( istream &_zipfile ) {
111   // Find and read eocd. 
112   if ( ! readEndOfCentralDirectory( _zipfile ) )
113     throw FCollException( "Unable to find zip structure: End-of-central-directory" ) ;
114
115   // Position read pointer to start of first entry in central dir.
116   _vs.vseekg( _zipfile,  _eocd.offset(), ios::beg ) ;
117
118   int entry_num = 0 ;
119   // Giving the default argument in the next line to keep Visual C++ quiet
120   _entries.resize ( _eocd.totalCount(), 0 ) ;
121   while ( ( entry_num < _eocd.totalCount() ) ) {
122     ZipCDirEntry *ent = new ZipCDirEntry ; 
123     _entries[ entry_num ] = ent ;
124     _zipfile >>  *ent ;
125     if ( ! _zipfile ) {
126       if ( _zipfile.bad()  ) 
127         throw IOException( "Error reading zip file while reading zip file central directory" ) ;
128       else if ( _zipfile.fail() )
129         throw FCollException( "Zip file consistency problem. Failure while reading zip file central directory" ) ;
130       else if ( _zipfile.eof()  )
131         throw IOException( "Premature end of file while reading zip file central directory" ) ;
132     }
133     ++entry_num ;
134   }
135
136   // Consistency check. eocd should start here
137   
138   int pos = _vs.vtellg( _zipfile ) ;
139   _vs.vseekg( _zipfile, 0, ios::end ) ;
140   int remaining = static_cast< int >( _vs.vtellg( _zipfile ) ) - pos ;
141   if ( remaining != _eocd.eocdOffSetFromEnd() )
142     throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ;
143
144   // Consistency check 2, are local headers consistent with
145   // cd headers
146   if ( ! confirmLocalHeaders( _zipfile ) )
147     throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ;
148   
149   return true ;
150 }
151
152
153 bool ZipFile::readEndOfCentralDirectory ( istream &_zipfile ) {
154   BackBuffer bb( _zipfile, _vs ) ;
155   int read_p = -1 ;
156   bool found = false ;
157   while ( ! found ) {
158     if ( read_p < 0 )
159       if ( ! bb.readChunk ( read_p ) ) {
160         found = false ;
161         break ;
162       }
163     if ( _eocd.read( bb, read_p ) ) {
164       found = true ;
165       break ;
166     }
167     --read_p ;
168   }
169
170   return found ;
171 }
172
173 bool ZipFile::confirmLocalHeaders( istream &_zipfile ) {
174   Entries::const_iterator it ;
175   ZipCDirEntry *ent ;
176   int inconsistencies = 0 ;
177   ZipLocalEntry zlh ;
178   for ( it = _entries.begin() ; it != _entries.end() ; it++ ) {
179     ent = static_cast< ZipCDirEntry * >( (*it).get()  ) ;
180     _vs.vseekg( _zipfile, ent->getLocalHeaderOffset(), ios::beg ) ;
181     _zipfile >> zlh ;
182     if ( ! _zipfile || zlh != *ent ) {
183       inconsistencies++ ;
184       _zipfile.clear() ;
185     }
186   }
187   return ! inconsistencies ;
188 }
189
190 void ZipFile::setError ( string error_str ) {
191   _valid = false ;
192 #ifdef _USE_EXCEPTIONS
193     throw  error_str ; // define exception class instead.
194 #else
195     cerr << error_str << endl ; // define operator<< for exception class if such a class replaces string
196 #endif
197 }
198
199
200 }
201
202 /** \file
203     The implementation of ZipFile.
204 */
205
206 /*
207   Zipios++ - a small C++ library that provides easy access to .zip files.
208   Copyright (C) 2000  Thomas Søndergaard
209   
210   This library is free software; you can redistribute it and/or
211   modify it under the terms of the GNU Lesser General Public
212   License as published by the Free Software Foundation; either
213   version 2 of the License, or (at your option) any later version.
214   
215   This library is distributed in the hope that it will be useful,
216   but WITHOUT ANY WARRANTY; without even the implied warranty of
217   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
218   Lesser General Public License for more details.
219   
220   You should have received a copy of the GNU Lesser General Public
221   License along with this library; if not, write to the Free Software
222   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
223 */