Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlCore/ZippedDirectory.hpp>
00033 #include <vlCore/VisualizationLibrary.hpp>
00034 #include <vlCore/FileSystem.hpp>
00035 #include <set>
00036
00037 using namespace vl;
00038
00039 ZippedDirectory::ZippedDirectory() {}
00040
00041 ZippedDirectory::ZippedDirectory(const String& zip_file)
00042 {
00043 ref<VirtualFile> v_file = defFileSystem()->locateFile(zip_file);
00044 if (v_file)
00045 setSourceZipFile(v_file.get());
00046 else
00047 Log::error( Say("ZippedDirectory() could not locate zip file '%s'.\n") << zip_file );
00048 }
00049
00050 ZippedDirectory::ZippedDirectory(VirtualFile* zip_file)
00051 {
00052 if (zip_file)
00053 setSourceZipFile(zip_file);
00054 }
00055
00056 bool ZippedDirectory::setPath(const String& name)
00057 {
00058 String root = name;
00059 root.trim();
00060 root.normalizeSlashes();
00061 if (root.empty())
00062 {
00063 Log::error("ZippedDirectory::setPath() given an empty path.\n");
00064 return false;
00065 }
00066 if (!root.endsWith('/'))
00067 {
00068
00069 root += '/';
00070 }
00071
00072 std::map< String, ref<ZippedFile> > file_map;
00073 for( std::map< String, ref<ZippedFile> >::iterator it = mFiles.begin(); it != mFiles.end(); ++it )
00074 {
00075 String p = it->first;
00076 if ( !p.startsWith(path()) )
00077 {
00078 Log::warning( Say("ZippedDirectory::setPath() : invalid path file '%s'.\n") << p );
00079 continue;
00080 }
00081 p = p.right(-path().length());
00082 it->second->setPath(root + p);
00083 file_map[it->second->path()] = it->second;
00084 }
00085 mFiles = file_map;
00086 mPath = root;
00087 return true;
00088 }
00089
00090 const VirtualFile* ZippedDirectory::sourceZipFile() const
00091 {
00092 return mSourceZipFile.get();
00093 }
00094
00095 VirtualFile* ZippedDirectory::sourceZipFile()
00096 {
00097 return mSourceZipFile.get();
00098 }
00099
00100 void ZippedDirectory::setSourceZipFile(VirtualFile* file)
00101 {
00102 reset();
00103 mSourceZipFile = file;
00104 if(file)
00105 init();
00106 }
00107
00108 void ZippedDirectory::reset()
00109 {
00110 mSourceZipFile = NULL;
00111 mFiles.clear();
00112 }
00113
00114 bool ZippedDirectory::init()
00115 {
00116 mFiles.clear();
00117 if (path().empty())
00118 {
00119 Log::error( "VirtualDirectory::path() must not be empty!\n" );
00120 return false;
00121 }
00122 ref<VirtualFile> zip = sourceZipFile();
00123 if (!zip)
00124 {
00125 Log::error("ZippedFile::init() called but not zip file mounted.\n");
00126 return false;
00127 }
00128 zip->close();
00129 if ( !zip->open(OM_ReadOnly) )
00130 {
00131 Log::error("ZippedDirectory::init(): cannot open source zip file.\n");
00132 return false;
00133 }
00134
00135 for( unsigned int local_file_header_signature = 0;
00136 zip->read(&local_file_header_signature, 4) && local_file_header_signature == 0x04034b50;
00137 local_file_header_signature = 0 )
00138 {
00139
00140 ref<ZippedFileInfo> zfile_info = new ZippedFileInfo;
00141 zfile_info->setSourceZipFile( sourceZipFile()->clone().get() );
00142
00143 unsigned short last_mod_file_time;
00144 unsigned short last_mod_file_date;
00145
00146 zfile_info->mVersionNeeded = zip->readUInt16();
00147 zfile_info->mGeneralPurposeFlag = zip->readUInt16();
00148 zfile_info->mCompressionMethod = zip->readUInt16();
00149 last_mod_file_time = zip->readUInt16();
00150 last_mod_file_date = zip->readUInt16();
00151 zfile_info->mCRC32 = zip->readUInt32();
00152 zfile_info->mCompressedSize = zip->readUInt32();
00153 zfile_info->mUncompressedSize = zip->readUInt32();
00154 zfile_info->mFileNameLength = zip->readUInt16();
00155 zfile_info->mExtraFieldLength = zip->readUInt16();
00156
00157 String name;
00158
00159
00160 std::string file_name;
00161 file_name.resize(zfile_info->mFileNameLength);
00162 zip->read(&file_name[0], file_name.size());
00163 file_name.push_back(0);
00164 name = String::fromUTF8( file_name.c_str() );
00165 name.normalizeSlashes();
00166
00167
00168 if (name.endsWith('/'))
00169 continue;
00170
00171 ref<ZippedFile> zipped_file = new ZippedFile;
00172 zipped_file->setZippedFileInfo( zfile_info.get() );
00173
00174 zfile_info->mFileName = name;
00175 zipped_file->setPath( path() + name );
00176 mFiles[zipped_file->path()] = zipped_file;
00177
00178
00179 if ( zfile_info->mExtraFieldLength )
00180 {
00181 std::vector<char> extra_field;
00182 extra_field.resize(zfile_info->mExtraFieldLength);
00183 zip->read(&extra_field[0], extra_field.size());
00184 }
00185
00186
00187
00188
00189
00190 zfile_info->mSecond = int(( last_mod_file_time & 31 ) / 31.0f * 59.5f);
00191 zfile_info->mMinute = (last_mod_file_time>>5) & 63;
00192 zfile_info->mHour = (last_mod_file_time>>11) & 31;
00193 zfile_info->mDay = last_mod_file_date & 31;
00194 zfile_info->mMonth = (last_mod_file_date>>5) & 15;
00195 zfile_info->mYear = ((last_mod_file_date>>9) & 127 ) + 1980;
00196
00197 #if 0
00198 #if !defined(NDEBUG)
00199 printf("-------------------------\n");
00200 printf("%s\n", name.toStdString().c_str());
00201 printf("mVersionNeeded = %d\n", zfile_info->mVersionNeeded);
00202 printf("mGeneralPurposeFlag = %d\n", zfile_info->mGeneralPurposeFlag);
00203 printf("mCompressionMethod = %d\n", zfile_info->mCompressionMethod);
00204 printf("Time and date = %d/%d/%d %d:%d:%d\n", zfile_info->mYear, zfile_info->mMonth, zfile_info->mDay, zfile_info->mHour, zfile_info->mMinute, zfile_info->mSecond);
00205 printf("mUncompressedSize = %d\n", zfile_info->mUncompressedSize);
00206 printf("mCompressedSize = %d -> %.1f\n", zfile_info->mCompressedSize, 100.0f * zfile_info->mCompressedSize / zfile_info->mUncompressedSize);
00207 printf("mCRC32 = %08X\n", zfile_info->mCRC32);
00208 #endif
00209 #endif
00210
00211 long long cur_pos = zip->position();
00212
00213
00214 if (cur_pos < 2*4 + 4*4)
00215 {
00216 Log::error("ZippedDirectory::init(): mounted a non seek-able zip file.\n");
00217 zip->close();
00218 mFiles.clear();
00219 return false;
00220 }
00221
00222 zfile_info->mZippedFileOffset = (unsigned int)cur_pos;
00223
00224
00225 zip->seekCur( zfile_info->mCompressedSize );
00226
00227 if ( zfile_info->mGeneralPurposeFlag & (1<<3) )
00228 {
00229 zfile_info->mCRC32 = zip->readUInt32();
00230
00231 if (zfile_info->mCRC32 == 0x08074b50)
00232 zfile_info->mCRC32 = zip->readUInt32();
00233 zfile_info->mCompressedSize = zip->readUInt32();
00234 zfile_info->mUncompressedSize = zip->readUInt32();
00235 }
00236 }
00237
00238 if (zip->position() == 4)
00239 {
00240 Log::error( Say("ZippedDirectory::init(): '%s' does not look like a zip file.\n") << sourceZipFile()->path() );
00241 return false;
00242 }
00243
00244 zip->close();
00245 return true;
00246 }
00247
00248 ref<VirtualFile> ZippedDirectory::file(const String& name) const
00249 {
00250 return zippedFile(name);
00251 }
00252
00253 int ZippedDirectory::zippedFileCount() const
00254 {
00255 return (int)mFiles.size();
00256 }
00257
00258 const ZippedFile* ZippedDirectory::zippedFile(int index) const
00259 {
00260 std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin();
00261 for(int i=0; i<index && it != mFiles.end(); ++i)
00262 ++it;
00263 if ( it == mFiles.end() )
00264 return NULL;
00265 else
00266 return it->second.get();
00267 }
00268
00269 ZippedFile* ZippedDirectory::zippedFile(int index)
00270 {
00271 std::map< String, ref<ZippedFile> >::iterator it = mFiles.begin();
00272 for(int i=0; i<index && it != mFiles.end(); ++i)
00273 ++it;
00274 if ( it == mFiles.end() )
00275 return NULL;
00276 else
00277 return it->second.get();
00278 }
00279
00280 ref<ZippedFile> ZippedDirectory::zippedFile(const String& name) const
00281 {
00282 String p = translatePath(name);
00283 std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.find(p);
00284 if (it == mFiles.end())
00285 return NULL;
00286 else
00287 {
00288 ref<ZippedFile> zip_file = new ZippedFile;
00289 zip_file->operator=(*it->second);
00290 return zip_file.get();
00291 }
00292 }
00293
00294 void ZippedDirectory::listFilesRecursive( std::vector<String>& file_list ) const
00295 {
00296 file_list.clear();
00297 if (path().empty())
00298 {
00299 Log::error( "VirtualDirectory::path() must not be empty!\n" );
00300 return;
00301 }
00302 for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it)
00303 {
00304 if (!it->first.startsWith(path()))
00305 vl::Log::warning( Say("ZippedFile '%s' does not belong to ZippedDirectory '%s'.\n") << it->first << path() );
00306 file_list.push_back( it->first );
00307 }
00308 }
00309
00310 void ZippedDirectory::listSubDirs(std::vector<String>& dirs, bool append) const
00311 {
00312 if (!append)
00313 dirs.clear();
00314 if (path().empty())
00315 {
00316 Log::error( "VirtualDirectory::path() must not be empty!\n" );
00317 return;
00318 }
00319 std::set<String> sub_dirs;
00320 for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
00321 {
00322 VL_CHECK(it->first.startsWith(path()))
00323 String p = it->first.extractPath();
00324 if (path().length())
00325 p = p.right(-path().length());
00326 while(p.startsWith('/'))
00327 p = p.right(-1);
00328 String drive_letter;
00329 if (p.length()>3 && p[1] == ':' && p[2] == '/')
00330 {
00331 drive_letter = p.left(3);
00332 p = p.right(-3);
00333 }
00334 if (p.empty())
00335 continue;
00336 std::vector<String> tokens;
00337 p.split('/',tokens,true);
00338 if (tokens.size())
00339 sub_dirs.insert(path() + tokens[0]);
00340 }
00341 for(std::set<String>::const_iterator it = sub_dirs.begin(); it != sub_dirs.end(); ++it)
00342 dirs.push_back(*it);
00343 }
00344
00345 ref<ZippedDirectory> ZippedDirectory::zippedSubDir(const String& subdir_name) const
00346 {
00347 if (path().empty())
00348 {
00349 Log::error( "VirtualDirectory::path() must not be empty!\n" );
00350 return NULL;
00351 }
00352 String p = translatePath(subdir_name);
00353 ref<ZippedDirectory> dir = new ZippedDirectory(p);
00354 for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
00355 {
00356 if (it->first.startsWith(p+'/'))
00357 {
00358 ref<ZippedFile> mfile = static_cast<ZippedFile*>(it->second->clone().get());
00359 VL_CHECK(mfile)
00360 dir->mFiles[mfile->path()] = mfile;
00361 }
00362 }
00363
00364 if (dir->mFiles.empty())
00365 return NULL;
00366 else
00367 return dir;
00368 }
00369
00370 void ZippedDirectory::listFiles(std::vector<String>& file_list, bool append) const
00371 {
00372 if (!append)
00373 file_list.clear();
00374 if (path().empty())
00375 {
00376 Log::error( "VirtualDirectory::path() must not be empty!\n" );
00377 return;
00378 }
00379 for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
00380 {
00381 if (it->first.extractPath().left(-1) == path())
00382 file_list.push_back( it->first );
00383 }
00384 }
00385
00386 bool ZippedDirectory::isCorrupted()
00387 {
00388 if ( !init() )
00389 return true;
00390 for (int i=0; i<zippedFileCount(); ++i)
00391 if ( zippedFile(i)->crc32() != zippedFile(i)->zippedFileInfo()->crc32() )
00392 return true;
00393 return false;
00394 }
00395