Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/ZippedDirectory.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.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 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:34.
Permission is granted to use this page to write and publish articles regarding Visualization Library.