Zipios++
|
00001 00002 #include "zipios++/zipios-config.h" 00003 00004 #include "zipios++/meta-iostreams.h" 00005 00006 #include "zipios++/fcoll.h" 00007 #include "zipios++/zipfile.h" 00008 #include "zipios++/zipinputstream.h" 00009 #include "zipios++/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 ZipInputStream *zis( new ZipInputStream( _filename, 00072 static_cast< const ZipCDirEntry * >( ent.get() )-> 00073 getLocalHeaderOffset() + _vs.startOffset() ) ) ; 00074 zis->getNextEntry(); 00075 return zis; 00076 } 00077 } 00078 00079 00080 // 00081 // Private 00082 // 00083 00084 bool ZipFile::init( istream &_zipfile ) { 00085 00086 // Check stream error state 00087 if ( ! _zipfile ) { 00088 setError ( "Error reading from file" ) ; 00089 return false ; 00090 } 00091 00092 _valid = readCentralDirectory( _zipfile ) ; 00093 00094 return _valid ; 00095 } 00096 00097 00098 bool ZipFile::readCentralDirectory ( istream &_zipfile ) { 00099 // Find and read eocd. 00100 if ( ! readEndOfCentralDirectory( _zipfile ) ) 00101 throw FCollException( "Unable to find zip structure: End-of-central-directory" ) ; 00102 00103 // Position read pointer to start of first entry in central dir. 00104 _vs.vseekg( _zipfile, _eocd.offset(), ios::beg ) ; 00105 00106 int entry_num = 0 ; 00107 // Giving the default argument in the next line to keep Visual C++ quiet 00108 _entries.resize ( _eocd.totalCount(), 0 ) ; 00109 while ( ( entry_num < _eocd.totalCount() ) ) { 00110 ZipCDirEntry *ent = new ZipCDirEntry ; 00111 _entries[ entry_num ] = ent ; 00112 _zipfile >> *ent ; 00113 if ( ! _zipfile ) { 00114 if ( _zipfile.bad() ) 00115 throw IOException( "Error reading zip file while reading zip file central directory" ) ; 00116 else if ( _zipfile.fail() ) 00117 throw FCollException( "Zip file consistency problem. Failure while reading zip file central directory" ) ; 00118 else if ( _zipfile.eof() ) 00119 throw IOException( "Premature end of file while reading zip file central directory" ) ; 00120 } 00121 ++entry_num ; 00122 } 00123 00124 // Consistency check. eocd should start here 00125 00126 int pos = _vs.vtellg( _zipfile ) ; 00127 _vs.vseekg( _zipfile, 0, ios::end ) ; 00128 int remaining = static_cast< int >( _vs.vtellg( _zipfile ) ) - pos ; 00129 if ( remaining != _eocd.eocdOffSetFromEnd() ) 00130 throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ; 00131 00132 // Consistency check 2, are local headers consistent with 00133 // cd headers 00134 if ( ! confirmLocalHeaders( _zipfile ) ) 00135 throw FCollException( "Zip file consistency problem. Zip file data fields are inconsistent with zip file layout" ) ; 00136 00137 return true ; 00138 } 00139 00140 00141 bool ZipFile::readEndOfCentralDirectory ( istream &_zipfile ) { 00142 BackBuffer bb( _zipfile, _vs ) ; 00143 int read_p = -1 ; 00144 bool found = false ; 00145 while ( ! found ) { 00146 if ( read_p < 0 ) 00147 if ( ! bb.readChunk ( read_p ) ) { 00148 found = false ; 00149 break ; 00150 } 00151 if ( _eocd.read( bb, read_p ) ) { 00152 found = true ; 00153 break ; 00154 } 00155 --read_p ; 00156 } 00157 00158 return found ; 00159 } 00160 00161 bool ZipFile::confirmLocalHeaders( istream &_zipfile ) { 00162 Entries::const_iterator it ; 00163 ZipCDirEntry *ent ; 00164 int inconsistencies = 0 ; 00165 ZipLocalEntry zlh ; 00166 for ( it = _entries.begin() ; it != _entries.end() ; it++ ) { 00167 ent = static_cast< ZipCDirEntry * >( (*it).get() ) ; 00168 _vs.vseekg( _zipfile, ent->getLocalHeaderOffset(), ios::beg ) ; 00169 _zipfile >> zlh ; 00170 if ( ! _zipfile || zlh != *ent ) { 00171 inconsistencies++ ; 00172 _zipfile.clear() ; 00173 } 00174 } 00175 return ! inconsistencies ; 00176 } 00177 00178 void ZipFile::setError ( string error_str ) { 00179 _valid = false ; 00180 #ifdef _USE_EXCEPTIONS 00181 throw error_str ; // define exception class instead. 00182 #else 00183 cerr << error_str << endl ; // define operator<< for exception class if such a class replaces string 00184 #endif 00185 } 00186 00187 00188 } 00189 00194 /* 00195 Zipios++ - a small C++ library that provides easy access to .zip files. 00196 Copyright (C) 2000 Thomas Søndergaard 00197 00198 This library is free software; you can redistribute it and/or 00199 modify it under the terms of the GNU Lesser General Public 00200 License as published by the Free Software Foundation; either 00201 version 2 of the License, or (at your option) any later version. 00202 00203 This library is distributed in the hope that it will be useful, 00204 but WITHOUT ANY WARRANTY; without even the implied warranty of 00205 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00206 Lesser General Public License for more details. 00207 00208 You should have received a copy of the GNU Lesser General Public 00209 License along with this library; if not, write to the Free Software 00210 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00211 */