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