Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 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 // Log::warning( Say("ZippedDirectory::setPath() : path (%s) must end with a '/'.\n") << root ); 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 // creates and fills a new ZippedFileInfo and a new ZippedFile 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 // file name 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 // don't add directories 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 // extra field 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 // MS DOS Time MS DOS Date 00187 // 0 - 4 5 - 10 11 - 15 16 - 20 21 - 24 25 - 31 00188 // second minute hour day (1 - 31) month (1 - 12) years from 1980 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 // 2*4 + 4*4 is the length of a v2.0 zip header 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 // skip compressed data 00225 zip->seekCur( zfile_info->mCompressedSize ); 00226 00227 if ( zfile_info->mGeneralPurposeFlag & (1<<3) ) 00228 { 00229 zfile_info->mCRC32 = zip->readUInt32(); 00230 // sometimes the first 4 bytes are the header according to the specs... !!! 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()) // is a file 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 //-----------------------------------------------------------------------------