00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
00093
00094
00095 bool FileSystemZIP::SetPath(const string& inName)
00096 {
00097 if(mHandle.get() != 0)
00098 {
00099
00100 Clear();
00101 }
00102
00103
00104 mHandle = shared_ptr<StdFile>(new StdFile());
00105
00106
00107 if(! mHandle->Open(inName.c_str()))
00108 {
00109
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
00120
00121 mArchiveName = inName;
00122
00123
00124 TCentralDirectoryEnd cde;
00125 ZIPGetCentralDirectoryEndFirst(&cde);
00126
00127
00128 mHandle->Seek(cde.offset_start_cd, SEEK_SET);
00129
00130
00131 delete[] cde.zipfile_comment;
00132
00133
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
00145 ZIPGetLocalHeader(&lh);
00146 ZIPSkipData(&lh);
00147
00148 delete[] lh.filename;
00149 delete[] lh.extra_field;
00150 break;
00151 case SIG_FILE_HEADER:
00152
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
00165 ZIPGetCentralDirectoryEnd(&cde);
00166
00167 delete[] cde.zipfile_comment;
00168 break;
00169 default:
00170
00171 return false;
00172 }
00173
00174
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;
00191
00192
00193 if(mHandle.get() == 0)
00194 {
00195 return shared_ptr<salt::RFile>();
00196 }
00197
00198
00199 fileName = new char[inName.size()+1];
00200 strcpy(fileName, inName.c_str());
00201
00202
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
00212 cur = (*i).second;
00213
00214
00215 mHandle->Seek(cur->data,SEEK_SET);
00216
00217
00218 ZIPGetLocalHeader(&lh);
00219
00220
00221 uncompr = new unsigned char[lh.uncompressed_size];
00222
00223
00224 switch(lh.compression_method)
00225 {
00226 case ZIP_STORE:
00227
00228 mHandle->Read(uncompr, lh.uncompressed_size);
00229 break;
00230 case ZIP_DEFLATE:
00231
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
00240 compr = new unsigned char[buf_size];
00241
00242
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
00259 inflateEnd(&d_stream);
00260
00261 delete[]compr;
00262 break;
00263 default:
00264
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
00400
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 }