zipfile.cpp

Go to the documentation of this file.
00001 
00002 #include "zipios-config.h"
00003 
00004 #include "meta-iostreams.h"
00005 
00006 #include "fcoll.h"
00007 #include "zipfile.h"
00008 #include "zipinputstream.h"
00009 #include "zipios_defs.h"
00010 
00011 #include "backbuffer.h"
00012 
00013 namespace zipios {
00014 
00015 //
00016 // Public
00017 //
00018 
00019 ZipFile ZipFile::openEmbeddedZipFile( const string &name ) {
00020   // open zipfile, read 4 last bytes close file
00021   // create ZipFile object.
00022   ifstream ifs( name.c_str(), ios::in | ios::binary ) ;
00023   ifs.seekg( -4, ios::end ) ;
00024   uint32 start_offset = readUint32( ifs ) ;
00025   ifs.close() ;
00026   return ZipFile( name, start_offset, 4 ) ; 
00027 }
00028 
00029 
00030 ZipFile::ZipFile( const string &name , int s_off, int e_off
00031                   /* , ios::open_mode mode */ ) 
00032   : _vs( s_off, e_off ) {
00033 
00034   _filename = name ;
00035   
00036   ifstream _zipfile( name.c_str(), ios::in | ios::binary ) ;
00037   init( _zipfile ) ;
00038 }
00039 
00040 
00041 FileCollection *ZipFile::clone() const {
00042   return new ZipFile( *this ) ;
00043 }
00044 
00045 
00046 ZipFile::~ZipFile() {
00047   close() ;
00048 }
00049 
00050 void ZipFile::close() {
00051   _valid = false ;
00052 
00053 }
00054 
00055 istream *ZipFile::getInputStream( const ConstEntryPointer &entry ) {
00056   if ( ! _valid )
00057     throw InvalidStateException( "Attempt to use an invalid FileCollection" ) ;
00058   return getInputStream( entry->getName() ) ;
00059 }
00060 
00061 istream *ZipFile::getInputStream( const string &entry_name, 
00062                                   MatchPath matchpath ) {
00063   if ( ! _valid )
00064     throw InvalidStateException( "Attempt to use an invalid ZipFile" ) ;
00065 
00066   ConstEntryPointer ent = getEntry( entry_name, matchpath ) ;
00067   
00068   if ( ent == 0 )
00069     return 0 ;
00070   else
00071     return new ZipInputStream( _filename,       
00072                            static_cast< const ZipCDirEntry * >( ent.get() )->
00073                            getLocalHeaderOffset() + _vs.startOffset() ) ;
00074 }
00075 
00076 
00077 //
00078 // Private
00079 //
00080 
00081 bool ZipFile::init( istream &_zipfile ) {
00082 
00083   // Check stream error state
00084   if ( ! _zipfile ) {
00085     setError ( "Error reading from file" ) ;
00086     return false ;
00087   }
00088   
00089   _valid = readCentralDirectory( _zipfile ) ;
00090 
00091   return _valid ;
00092 }
00093 
00094 
00095 bool ZipFile::readCentralDirectory ( istream &_zipfile ) {
00096   // Find and read eocd. 
00097   if ( ! readEndOfCentralDirectory( _zipfile ) )
00098     throw FCollException( "Unable to find zip structure: End-of-central-directory" ) ;
00099 
00100   // Position read pointer to start of first entry in central dir.
00101   _vs.vseekg( _zipfile,  _eocd.offset(), ios::beg ) ;
00102 
00103   int entry_num = 0 ;
00104   // Giving the default argument in the next line to keep Visual C++ quiet
00105   _entries.resize ( _eocd.totalCount(), 0 ) ;
00106   while ( ( entry_num < _eocd.totalCount() ) ) {
00107     ZipCDirEntry *ent = new ZipCDirEntry ; 
00108     _entries[ entry_num ] = ent ;
00109     _zipfile >>  *ent ;
00110     if ( ! _zipfile ) {
00111       if ( _zipfile.bad()  ) 
00112         throw IOException( "Error reading zip file while reading zip file central directory" ) ;
00113       else if ( _zipfile.fail() )
00114         throw FCollException( "Zip file consistency problem. Failure while reading zip file central directory" ) ;
00115       else if ( _zipfile.eof()  )
00116         throw IOException( "Premature end of file while reading zip file central directory" ) ;
00117     }
00118     ++entry_num ;
00119   }
00120 
00121   // Consistency check. eocd should start here
00122   
00123   int pos = _vs.vtellg( _zipfile ) ;
00124   _vs.vseekg( _zipfile, 0, ios::end ) ;
00125   int remaining = static_cast< int >( _vs.vtellg( _zipfile ) ) - pos ;
00126   if ( remaining != _eocd.eocdOffSetFromEnd() )
00127     throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ;
00128 
00129   // Consistency check 2, are local headers consistent with
00130   // cd headers
00131   if ( ! confirmLocalHeaders( _zipfile ) )
00132     throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ;
00133   
00134   return true ;
00135 }
00136 
00137 
00138 bool ZipFile::readEndOfCentralDirectory ( istream &_zipfile ) {
00139   BackBuffer bb( _zipfile, _vs ) ;
00140   int read_p = -1 ;
00141   bool found = false ;
00142   while ( ! found ) {
00143     if ( read_p < 0 )
00144       if ( ! bb.readChunk ( read_p ) ) {
00145         found = false ;
00146         break ;
00147       }
00148     if ( _eocd.read( bb, read_p ) ) {
00149       found = true ;
00150       break ;
00151     }
00152     --read_p ;
00153   }
00154 
00155   return found ;
00156 }
00157 
00158 bool ZipFile::confirmLocalHeaders( istream &_zipfile ) {
00159   Entries::const_iterator it ;
00160   ZipCDirEntry *ent ;
00161   int inconsistencies = 0 ;
00162   ZipLocalEntry zlh ;
00163   for ( it = _entries.begin() ; it != _entries.end() ; it++ ) {
00164     ent = static_cast< ZipCDirEntry * >( (*it).get()  ) ;
00165     _vs.vseekg( _zipfile, ent->getLocalHeaderOffset(), ios::beg ) ;
00166     _zipfile >> zlh ;
00167     if ( ! _zipfile || zlh != *ent ) {
00168       inconsistencies++ ;
00169       _zipfile.clear() ;
00170     }
00171   }
00172   return ! inconsistencies ;
00173 }
00174 
00175 void ZipFile::setError ( string error_str ) {
00176   _valid = false ;
00177 #ifdef _USE_EXCEPTIONS
00178     throw  error_str ; // define exception class instead.
00179 #else
00180     cerr << error_str << endl ; // define operator<< for exception class if such a class replaces string
00181 #endif
00182 }
00183 
00184 
00185 }
00186 
00191 /*
00192   Zipios++ - a small C++ library that provides easy access to .zip files.
00193   Copyright (C) 2000  Thomas Søndergaard
00194   
00195   This library is free software; you can redistribute it and/or
00196   modify it under the terms of the GNU Lesser General Public
00197   License as published by the Free Software Foundation; either
00198   version 2 of the License, or (at your option) any later version.
00199   
00200   This library is distributed in the hope that it will be useful,
00201   but WITHOUT ANY WARRANTY; without even the implied warranty of
00202   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00203   Lesser General Public License for more details.
00204   
00205   You should have received a copy of the GNU Lesser General Public
00206   License along with this library; if not, write to the Free Software
00207   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00208 */

Generated on Wed Nov 23 19:01:12 2011 for FreeCAD by  doxygen 1.6.1