Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

filesystemzip.cpp

Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 
00003    this file is part of rcssserver3D
00004    Fri May 9 2003
00005    Copyright (C) 2002,2003 Koblenz University
00006    Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group
00007    $Id: filesystemzip.cpp,v 1.4 2004/04/18 16:21:56 rollmark Exp $
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; version 2 of the License.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 #include "filesystemzip.h"
00023 #include <salt/fileclasses.h>
00024 #include <zeitgeist/logserver/logserver.h>
00025 #include <string.h>
00026 #include <zlib.h>
00027 #include <boost/regex.hpp>
00028 
00029 #ifndef HAVE_STRUPR
00030 #include <ctype.h>
00031 char*
00032 strupr( char* s1 )
00033 {
00034     int i;
00035     for (i=0; i<strlen(s1); ++i)
00036         {
00037             s1[i] = toupper(s1[i]);
00038         }
00039     return s1;
00040 }
00041 #endif
00042 
00043 //ZIP Format Definitions
00044 #define SIG_LOCAL_HEADER          0x04034b50
00045 #define SIG_FILE_HEADER           0x02014b50
00046 #define SIG_CENTRAL_DIRECTORY_END 0x06054b50
00047 
00048 #define ZIP_STORE   0
00049 #define ZIP_DEFLATE 8
00050 
00051 using namespace salt;
00052 using namespace std;
00053 using namespace boost;
00054 
00055 FileSystemZIP::FileSystemZIP()
00056 {
00057 }
00058 
00059 FileSystemZIP::~FileSystemZIP()
00060 {
00061     Clear();
00062 }
00063 
00064 int FileSystemZIP::ForEachFile(const string& expression, TCallback callback, void* param)
00065 {
00066     if (!callback)
00067         {
00068             return 0;
00069         }
00070 
00071     int count = 0;
00072     boost::regex regExpression(expression);
00073 
00074     for (TEntryMap::iterator i = mEntryMap.begin(); i != mEntryMap.end(); ++i)
00075         {
00076             TArchiveEntry *cur = (*i).second;
00077             // check if we have a file
00078             if (!(cur->attr&16))
00079                 {
00080                     if (boost::regex_match(cur->filename, regExpression))
00081                         {
00082                             callback(cur->filename,param);
00083                             ++count;
00084                         }
00085                 }
00086         }
00087 
00088     return count;
00089 }
00090 
00091 //
00092 // This sets the path to the archive this object will be associated with.
00093 // The behavior is quite simple. First it will try 'inName' then 'inName.zip'
00094 //
00095 bool FileSystemZIP::SetPath(const string& inName)
00096 {
00097     if(mHandle.get() != 0)
00098         {
00099             //Already selected an archive so unselect it
00100             Clear();
00101         }
00102 
00103     // get a stdio file
00104     mHandle = shared_ptr<StdFile>(new StdFile());
00105 
00106     // try inName directly
00107     if(! mHandle->Open(inName.c_str()))
00108         {
00109             // ok, let's try it with a '.zip' extension
00110             string tryName = inName + ".zip";
00111             if(! mHandle->Open(tryName.c_str()))
00112                 {
00113                     GetLog()->Error() << "(FileSystemZIP) ERROR: unable to open '"
00114                                       << inName << "'\n";
00115                     return false;
00116                 }
00117         }
00118 
00119     //The open operation succeeded, so we can store the name of the
00120     //archive file
00121     mArchiveName = inName;
00122 
00123     //Read Central Directory End
00124     TCentralDirectoryEnd    cde;
00125     ZIPGetCentralDirectoryEndFirst(&cde);
00126 
00127     //Move to beginning of the Central Directory
00128     mHandle->Seek(cde.offset_start_cd, SEEK_SET);
00129 
00130     //Free memory
00131     delete[] cde.zipfile_comment;
00132 
00133     //Start reading data
00134     TLocalHeader lh;
00135     TFileHeader fh;
00136     TArchiveEntry* ae;
00137 
00138     int sig = mHandle->Igetl();
00139 
00140     while(! mHandle->Eof())
00141         {
00142             switch(sig){
00143             case SIG_LOCAL_HEADER:
00144                 //We should actually never get here, but this is left in for completeness
00145                 ZIPGetLocalHeader(&lh);
00146                 ZIPSkipData(&lh);
00147 
00148                 delete[] lh.filename;
00149                 delete[] lh.extra_field;
00150                 break;
00151             case SIG_FILE_HEADER:
00152                 //The data for this block is added to our internal database
00153                 ZIPGetFileHeader(&fh);
00154                 ae = new TArchiveEntry;
00155                 ae->filename    = strupr(fh.filename);
00156                 ae->data                = fh.relative_offset+4;
00157                 ae->attr                = (fh.external_file_attributes)&0xff;
00158                 AddArchiveEntry(ae);
00159 
00160                 delete[] fh.extra_field;
00161                 delete[] fh.file_comment;
00162                 break;
00163             case SIG_CENTRAL_DIRECTORY_END:
00164                 //Again useless reading of data, but we need to eat up the stuff, so here goes
00165                 ZIPGetCentralDirectoryEnd(&cde);
00166 
00167                 delete[] cde.zipfile_comment;
00168                 break;
00169             default:
00170                 // an error has occured
00171                 return false;
00172         }
00173 
00174         //Get next signature and update EOF flag
00175         sig = mHandle->Igetl();
00176     }
00177     return true;
00178 }
00179 
00180 shared_ptr<salt::RFile> FileSystemZIP::Open(const string& inName)
00181 {
00182     char            *fileName;
00183     TArchiveEntry   *cur;
00184     TLocalHeader    lh;
00185     unsigned int    bytes_left=0;
00186     size_t                  size;
00187     unsigned int    buf_size=4096;
00188     unsigned char   *compr, *uncompr;
00189     unsigned int    err;
00190     z_stream        d_stream; /* decompression stream */
00191 
00192     // if no file is open, return 0
00193     if(mHandle.get() == 0)
00194         {
00195             return shared_ptr<salt::RFile>();
00196         }
00197 
00198     // we have an archive, now get a local copy of inName
00199     fileName = new char[inName.size()+1];
00200     strcpy(fileName, inName.c_str());
00201 
00202     // search for file
00203     TEntryMap::iterator i = mEntryMap.find(std::string(strupr(fileName)));
00204     delete[]fileName;
00205 
00206     if (i == mEntryMap.end())
00207         {
00208             return shared_ptr<salt::RFile>();
00209         }
00210 
00211     // we have found a file
00212     cur = (*i).second;
00213 
00214     //Move to beginning of data
00215     mHandle->Seek(cur->data,SEEK_SET);
00216 
00217     //Get the local header
00218     ZIPGetLocalHeader(&lh);
00219 
00220     //Allocate memory for file
00221     uncompr = new unsigned char[lh.uncompressed_size];
00222 
00223     //Get data based on compression method used
00224     switch(lh.compression_method)
00225         {
00226         case ZIP_STORE:
00227             //Data is not compressed, so just read it from the file
00228             mHandle->Read(uncompr, lh.uncompressed_size);
00229             break;
00230         case ZIP_DEFLATE:
00231             //Data is compressed, so decompress it
00232             bytes_left                      = lh.uncompressed_size;
00233             d_stream.zalloc         = (alloc_func)0;
00234             d_stream.zfree          = (free_func)0;
00235             d_stream.opaque         = (voidpf)0;
00236             d_stream.avail_out      = lh.uncompressed_size;
00237             d_stream.next_out       = uncompr;
00238 
00239             // get memory for buffer
00240             compr                   = new unsigned char[buf_size];
00241 
00242             //This makes ZLIB able to decompress ZIP File streams
00243             inflateInit2(&d_stream, -15);
00244 
00245             while(bytes_left)
00246                 {
00247                     d_stream.next_in = compr;
00248                     if(bytes_left > buf_size)
00249                         size = buf_size;
00250                     else
00251                         size = bytes_left;
00252 
00253                     d_stream.avail_in = mHandle->Read(compr, size);
00254                     err = inflate(&d_stream,bytes_left>size ? Z_PARTIAL_FLUSH : Z_FINISH);
00255                     bytes_left -= size;
00256                 }
00257 
00258             //Finished decompression
00259             inflateEnd(&d_stream);
00260             //Free decompression buffer
00261             delete[]compr;
00262             break;
00263         default:
00264             //Mode not supported
00265             delete []uncompr;
00266             uncompr=0;
00267             break;
00268         }
00269 
00270     shared_ptr<salt::RFile> f;
00271     if(uncompr != 0)
00272         {
00273             MemFile* mf = new MemFile();
00274             mf->Open(uncompr, lh.uncompressed_size);
00275             f.reset(mf);
00276         }
00277 
00278     delete[] lh.filename;
00279     delete[] lh.extra_field;
00280     return f;
00281 }
00282 
00283 void FileSystemZIP::Clear()
00284 {
00285     mArchiveName = "";
00286     mHandle.reset();
00287 
00288     for (TEntryMap::iterator i = mEntryMap.begin(); i != mEntryMap.end(); ++i)
00289         {
00290             TArchiveEntry *cur = (*i).second;
00291             delete[] cur->filename;
00292             delete cur;
00293         }
00294 
00295 
00296     mEntryMap.clear();
00297 }
00298 
00299 void FileSystemZIP::ZIPGetLocalHeader(TLocalHeader *lh)
00300 {
00301     int i;
00302 
00303     lh->signature                   = SIG_LOCAL_HEADER;
00304     lh->version_needed              = mHandle->Igetw();
00305     lh->general_purpose             = mHandle->Igetw();
00306     lh->compression_method  = mHandle->Igetw();
00307     lh->last_mod_time               = mHandle->Igetw();
00308     lh->last_mod_date               = mHandle->Igetw();
00309     lh->crc32                               = mHandle->Igetl();
00310     lh->compressed_size             = mHandle->Igetl();
00311     lh->uncompressed_size   = mHandle->Igetl();
00312     lh->filename_length             = mHandle->Igetw();
00313     lh->extra_field_length  = mHandle->Igetw();
00314 
00315     lh->filename = new char[lh->filename_length+1];
00316     for(i=0;i<lh->filename_length;i++)
00317         lh->filename[i]=mHandle->Getc();
00318 
00319     lh->filename[i] = 0;
00320 
00321     lh->extra_field = new char[lh->extra_field_length+1];
00322     for(i=0;i<lh->extra_field_length;i++)
00323         lh->extra_field[i]=mHandle->Getc();
00324 
00325     lh->extra_field[i] = 0;
00326 }
00327 
00328 void FileSystemZIP::ZIPSkipData(TLocalHeader *lh)
00329 {
00330     mHandle->Seek(lh->compressed_size,SEEK_CUR);
00331 }
00332 
00333 void FileSystemZIP::ZIPGetFileHeader(TFileHeader *fh)
00334 {
00335     int i;
00336 
00337     fh->signature              = SIG_FILE_HEADER;
00338     fh->version_made           = mHandle->Igetw();
00339     fh->version_needed         = mHandle->Igetw();
00340     fh->general_purpose        = mHandle->Igetw();
00341     fh->compression_method     = mHandle->Igetw();
00342     fh->last_mod_time          = mHandle->Igetw();
00343     fh->last_mod_date          = mHandle->Igetw();
00344     fh->crc32                  = mHandle->Igetl();
00345     fh->compressed_size        = mHandle->Igetl();
00346     fh->uncompressed_size      = mHandle->Igetl();
00347     fh->filename_length        = mHandle->Igetw();
00348     fh->extra_field_length     = mHandle->Igetw();
00349     fh->file_comment_length    = mHandle->Igetw();
00350     fh->disk_number_start      = mHandle->Igetw();
00351     fh->internal_file_attributes = mHandle->Igetw();
00352     fh->external_file_attributes = mHandle->Igetl();
00353     fh->relative_offset           = mHandle->Igetl();
00354 
00355     fh->filename = new char[fh->filename_length+1];
00356     for(i=0;i<fh->filename_length;i++)
00357         fh->filename[i]=mHandle->Getc();
00358 
00359     fh->filename[i] = 0;
00360 
00361     fh->extra_field = new char[fh->extra_field_length+1];
00362     for(i=0;i<fh->extra_field_length;i++)
00363         fh->extra_field[i]=mHandle->Getc();
00364 
00365     fh->extra_field[i] = 0;
00366 
00367     fh->file_comment = new char[fh->file_comment_length+1];
00368     for(i=0;i<fh->file_comment_length;i++)
00369         fh->file_comment[i]=mHandle->Getc();
00370 
00371     fh->file_comment[i] = 0;
00372 }
00373 
00374 void FileSystemZIP::ZIPGetCentralDirectoryEnd(TCentralDirectoryEnd *cde)
00375 {
00376     int i;
00377 
00378     cde->signature                  = SIG_CENTRAL_DIRECTORY_END;
00379     cde->this_disk_no               = mHandle->Igetw();
00380     cde->cds_disk_no                = mHandle->Igetw();
00381     cde->num_entries_this_disk      = mHandle->Igetw();
00382     cde->num_entries_total          = mHandle->Igetw();
00383     cde->cd_size                    = mHandle->Igetl();
00384     cde->offset_start_cd            = mHandle->Igetl();
00385     cde->zipfile_comment_length     = mHandle->Igetw();
00386 
00387     cde->zipfile_comment = new char[cde->zipfile_comment_length+1];
00388     for(i=0;i<cde->zipfile_comment_length;i++)
00389         cde->zipfile_comment[i]=mHandle->Getc();
00390 
00391     cde->zipfile_comment[i] = 0;
00392 }
00393 
00394 void FileSystemZIP::ZIPGetCentralDirectoryEndFirst(TCentralDirectoryEnd *cde)
00395 {
00396     int save_pos = mHandle->Tell();
00397     long sig = 0;
00398 
00399     //position fpointer to end of file
00400     //fseek(f,0,SEEK_END) did not work!
00401     if(mHandle->Seek(mHandle->Size()-21,SEEK_SET)) return;
00402     sig = mHandle->Igetl();
00403     while(sig!=SIG_CENTRAL_DIRECTORY_END)
00404         {
00405             if(mHandle->Seek(-5,SEEK_CUR)) return;
00406             sig = mHandle->Igetl();
00407         }
00408 
00409     ZIPGetCentralDirectoryEnd(cde);
00410     mHandle->Seek(save_pos, SEEK_SET);
00411 }
00412 
00413 void FileSystemZIP::AddArchiveEntry(TArchiveEntry *ae)
00414 {
00415     mEntryMap[std::string(ae->filename)] = ae;
00416 }

Generated on Thu Apr 6 15:25:37 2006 for rcssserver3d by  doxygen 1.4.4