#include "zipios++/zipios-config.h" #include "zipios++/meta-iostreams.h" #include "zipios++/fcoll.h" #include "zipios++/zipfile.h" #include "zipios++/zipinputstream.h" #include "zipios++/zipios_defs.h" #include "backbuffer.h" namespace zipios { // // Public // ZipFile ZipFile::openEmbeddedZipFile( const string &name ) { // open zipfile, read 4 last bytes close file // create ZipFile object. ifstream ifs( name.c_str(), ios::in | ios::binary ) ; ifs.seekg( -4, ios::end ) ; uint32 start_offset = readUint32( ifs ) ; ifs.close() ; return ZipFile( name, start_offset, 4 ) ; } ZipFile::ZipFile( const string &name , int s_off, int e_off /* , ios::open_mode mode */ ) : _vs( s_off, e_off ) { _filename = name ; ifstream _zipfile( name.c_str(), ios::in | ios::binary ) ; init( _zipfile ) ; } FileCollection *ZipFile::clone() const { return new ZipFile( *this ) ; } ZipFile::~ZipFile() { close() ; } void ZipFile::close() { _valid = false ; } istream *ZipFile::getInputStream( const ConstEntryPointer &entry ) { if ( ! _valid ) throw InvalidStateException( "Attempt to use an invalid FileCollection" ) ; return getInputStream( entry->getName() ) ; } istream *ZipFile::getInputStream( const string &entry_name, MatchPath matchpath ) { if ( ! _valid ) throw InvalidStateException( "Attempt to use an invalid ZipFile" ) ; ConstEntryPointer ent = getEntry( entry_name, matchpath ) ; if ( ent == 0 ) return 0 ; else return new ZipInputStream( _filename, static_cast< const ZipCDirEntry * >( ent.get() )-> getLocalHeaderOffset() + _vs.startOffset() ) ; } // // Private // bool ZipFile::init( istream &_zipfile ) { // Check stream error state if ( ! _zipfile ) { setError ( "Error reading from file" ) ; return false ; } _valid = readCentralDirectory( _zipfile ) ; return _valid ; } bool ZipFile::readCentralDirectory ( istream &_zipfile ) { // Find and read eocd. if ( ! readEndOfCentralDirectory( _zipfile ) ) throw FCollException( "Unable to find zip structure: End-of-central-directory" ) ; // Position read pointer to start of first entry in central dir. _vs.vseekg( _zipfile, _eocd.offset(), ios::beg ) ; int entry_num = 0 ; // Giving the default argument in the next line to keep Visual C++ quiet _entries.resize ( _eocd.totalCount(), 0 ) ; while ( ( entry_num < _eocd.totalCount() ) ) { ZipCDirEntry *ent = new ZipCDirEntry ; _entries[ entry_num ] = ent ; _zipfile >> *ent ; if ( ! _zipfile ) { if ( _zipfile.bad() ) throw IOException( "Error reading zip file while reading zip file central directory" ) ; else if ( _zipfile.fail() ) throw FCollException( "Zip file consistency problem. Failure while reading zip file central directory" ) ; else if ( _zipfile.eof() ) throw IOException( "Premature end of file while reading zip file central directory" ) ; } ++entry_num ; } // Consistency check. eocd should start here int pos = _vs.vtellg( _zipfile ) ; _vs.vseekg( _zipfile, 0, ios::end ) ; int remaining = static_cast< int >( _vs.vtellg( _zipfile ) ) - pos ; if ( remaining != _eocd.eocdOffSetFromEnd() ) throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ; // Consistency check 2, are local headers consistent with // cd headers if ( ! confirmLocalHeaders( _zipfile ) ) throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ; return true ; } bool ZipFile::readEndOfCentralDirectory ( istream &_zipfile ) { BackBuffer bb( _zipfile, _vs ) ; int read_p = -1 ; bool found = false ; while ( ! found ) { if ( read_p < 0 ) if ( ! bb.readChunk ( read_p ) ) { found = false ; break ; } if ( _eocd.read( bb, read_p ) ) { found = true ; break ; } --read_p ; } return found ; } bool ZipFile::confirmLocalHeaders( istream &_zipfile ) { Entries::const_iterator it ; ZipCDirEntry *ent ; int inconsistencies = 0 ; ZipLocalEntry zlh ; for ( it = _entries.begin() ; it != _entries.end() ; it++ ) { ent = static_cast< ZipCDirEntry * >( (*it).get() ) ; _vs.vseekg( _zipfile, ent->getLocalHeaderOffset(), ios::beg ) ; _zipfile >> zlh ; if ( ! _zipfile || zlh != *ent ) { inconsistencies++ ; _zipfile.clear() ; } } return ! inconsistencies ; } void ZipFile::setError ( string error_str ) { _valid = false ; #ifdef _USE_EXCEPTIONS throw error_str ; // define exception class instead. #else cerr << error_str << endl ; // define operator<< for exception class if such a class replaces string #endif } } /** \file The implementation of ZipFile. */ /* Zipios++ - a small C++ library that provides easy access to .zip files. Copyright (C) 2000 Thomas Søndergaard This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */