Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ZippedDirectory.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
34 #include <vlCore/FileSystem.hpp>
35 #include <set>
36 
37 using namespace vl;
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 {
43  ref<VirtualFile> v_file = defFileSystem()->locateFile(zip_file);
44  if (v_file)
45  setSourceZipFile(v_file.get());
46  else
47  Log::error( Say("ZippedDirectory() could not locate zip file '%s'.\n") << zip_file );
48 }
49 //-----------------------------------------------------------------------------
51 {
52  if (zip_file)
53  setSourceZipFile(zip_file);
54 }
55 //-----------------------------------------------------------------------------
57 {
58  String root = name;
59  root.trim();
60  root.normalizeSlashes();
61  if (root.empty())
62  {
63  Log::error("ZippedDirectory::setPath() given an empty path.\n");
64  return false;
65  }
66  if (!root.endsWith('/'))
67  {
68  // Log::warning( Say("ZippedDirectory::setPath() : path (%s) must end with a '/'.\n") << root );
69  root += '/';
70  }
71 
72  std::map< String, ref<ZippedFile> > file_map;
73  for( std::map< String, ref<ZippedFile> >::iterator it = mFiles.begin(); it != mFiles.end(); ++it )
74  {
75  String p = it->first;
76  if ( !p.startsWith(path()) )
77  {
78  Log::warning( Say("ZippedDirectory::setPath() : invalid path file '%s'.\n") << p );
79  continue;
80  }
81  p = p.right(-path().length());
82  it->second->setPath(root + p);
83  file_map[it->second->path()] = it->second;
84  }
85  mFiles = file_map;
86  mPath = root;
87  return true;
88 }
89 //-----------------------------------------------------------------------------
91 {
92  return mSourceZipFile.get();
93 }
94 //-----------------------------------------------------------------------------
96 {
97  return mSourceZipFile.get();
98 }
99 //-----------------------------------------------------------------------------
101 {
102  reset();
104  if(file)
105  init();
106 }
107 //-----------------------------------------------------------------------------
109 {
111  mFiles.clear();
112 }
113 //-----------------------------------------------------------------------------
115 {
116  mFiles.clear();
117  if (path().empty())
118  {
119  Log::error( "VirtualDirectory::path() must not be empty!\n" );
120  return false;
121  }
123  if (!zip)
124  {
125  Log::error("ZippedFile::init() called but not zip file mounted.\n");
126  return false;
127  }
128  zip->close();
129  if ( !zip->open(OM_ReadOnly) )
130  {
131  Log::error("ZippedDirectory::init(): cannot open source zip file.\n");
132  return false;
133  }
134 
135  for( unsigned int local_file_header_signature = 0;
136  zip->read(&local_file_header_signature, 4) && local_file_header_signature == 0x04034b50;
137  local_file_header_signature = 0 )
138  {
139  // creates and fills a new ZippedFileInfo and a new ZippedFile
140  ref<ZippedFileInfo> zfile_info = new ZippedFileInfo;
141  zfile_info->setSourceZipFile( sourceZipFile()->clone().get() );
142 
143  unsigned short last_mod_file_time;
144  unsigned short last_mod_file_date;
145 
146  zfile_info->mVersionNeeded = zip->readUInt16();
147  zfile_info->mGeneralPurposeFlag = zip->readUInt16();
148  zfile_info->mCompressionMethod = zip->readUInt16();
149  last_mod_file_time = zip->readUInt16();
150  last_mod_file_date = zip->readUInt16();
151  zfile_info->mCRC32 = zip->readUInt32();
152  zfile_info->mCompressedSize = zip->readUInt32();
153  zfile_info->mUncompressedSize = zip->readUInt32();
154  zfile_info->mFileNameLength = zip->readUInt16();
155  zfile_info->mExtraFieldLength = zip->readUInt16();
156 
157  String name;
158 
159  // file name
160  std::string file_name;
161  file_name.resize(zfile_info->mFileNameLength);
162  zip->read(&file_name[0], file_name.size());
163  file_name.push_back(0);
164  name = String::fromUTF8( file_name.c_str() );
165  name.normalizeSlashes();
166 
167  // don't add directories
168  if (name.endsWith('/'))
169  continue;
170 
171  ref<ZippedFile> zipped_file = new ZippedFile;
172  zipped_file->setZippedFileInfo( zfile_info.get() );
173 
174  zfile_info->mFileName = name;
175  zipped_file->setPath( path() + name );
176  mFiles[zipped_file->path()] = zipped_file;
177 
178  // extra field
179  if ( zfile_info->mExtraFieldLength )
180  {
181  std::vector<char> extra_field;
182  extra_field.resize(zfile_info->mExtraFieldLength);
183  zip->read(&extra_field[0], extra_field.size());
184  }
185 
186  // MS DOS Time MS DOS Date
187  // 0 - 4 5 - 10 11 - 15 16 - 20 21 - 24 25 - 31
188  // second minute hour day (1 - 31) month (1 - 12) years from 1980
189 
190  zfile_info->mSecond = int(( last_mod_file_time & 31 ) / 31.0f * 59.5f);
191  zfile_info->mMinute = (last_mod_file_time>>5) & 63;
192  zfile_info->mHour = (last_mod_file_time>>11) & 31;
193  zfile_info->mDay = last_mod_file_date & 31;
194  zfile_info->mMonth = (last_mod_file_date>>5) & 15;
195  zfile_info->mYear = ((last_mod_file_date>>9) & 127 ) + 1980;
196 
197  #if 0
198  #if !defined(NDEBUG)
199  printf("-------------------------\n");
200  printf("%s\n", name.toStdString().c_str());
201  printf("mVersionNeeded = %d\n", zfile_info->mVersionNeeded);
202  printf("mGeneralPurposeFlag = %d\n", zfile_info->mGeneralPurposeFlag);
203  printf("mCompressionMethod = %d\n", zfile_info->mCompressionMethod);
204  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);
205  printf("mUncompressedSize = %d\n", zfile_info->mUncompressedSize);
206  printf("mCompressedSize = %d -> %.1f\n", zfile_info->mCompressedSize, 100.0f * zfile_info->mCompressedSize / zfile_info->mUncompressedSize);
207  printf("mCRC32 = %08X\n", zfile_info->mCRC32);
208  #endif
209  #endif
210 
211  long long cur_pos = zip->position();
212 
213  // 2*4 + 4*4 is the length of a v2.0 zip header
214  if (cur_pos < 2*4 + 4*4)
215  {
216  Log::error("ZippedDirectory::init(): mounted a non seek-able zip file.\n");
217  zip->close();
218  mFiles.clear();
219  return false;
220  }
221 
222  zfile_info->mZippedFileOffset = (unsigned int)cur_pos;
223 
224  // skip compressed data
225  zip->seekCur( zfile_info->mCompressedSize );
226 
227  if ( zfile_info->mGeneralPurposeFlag & (1<<3) )
228  {
229  zfile_info->mCRC32 = zip->readUInt32();
230  // sometimes the first 4 bytes are the header according to the specs... !!!
231  if (zfile_info->mCRC32 == 0x08074b50)
232  zfile_info->mCRC32 = zip->readUInt32();
233  zfile_info->mCompressedSize = zip->readUInt32();
234  zfile_info->mUncompressedSize = zip->readUInt32();
235  }
236  }
237 
238  if (zip->position() == 4)
239  {
240  Log::error( Say("ZippedDirectory::init(): '%s' does not look like a zip file.\n") << sourceZipFile()->path() );
241  return false;
242  }
243 
244  zip->close();
245  return true;
246 }
247 //-----------------------------------------------------------------------------
249 {
250  return zippedFile(name);
251 }
252 //-----------------------------------------------------------------------------
254 {
255  return (int)mFiles.size();
256 }
257 //-----------------------------------------------------------------------------
259 {
260  std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin();
261  for(int i=0; i<index && it != mFiles.end(); ++i)
262  ++it;
263  if ( it == mFiles.end() )
264  return NULL;
265  else
266  return it->second.get();
267 }
268 //-----------------------------------------------------------------------------
270 {
271  std::map< String, ref<ZippedFile> >::iterator it = mFiles.begin();
272  for(int i=0; i<index && it != mFiles.end(); ++i)
273  ++it;
274  if ( it == mFiles.end() )
275  return NULL;
276  else
277  return it->second.get();
278 }
279 //-----------------------------------------------------------------------------
281 {
282  String p = translatePath(name);
283  std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.find(p);
284  if (it == mFiles.end())
285  return NULL;
286  else
287  {
288  ref<ZippedFile> zip_file = new ZippedFile;
289  zip_file->operator=(*it->second);
290  return zip_file.get();
291  }
292 }
293 //-----------------------------------------------------------------------------
294 void ZippedDirectory::listFilesRecursive( std::vector<String>& file_list ) const
295 {
296  file_list.clear();
297  if (path().empty())
298  {
299  Log::error( "VirtualDirectory::path() must not be empty!\n" );
300  return;
301  }
302  for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it)
303  {
304  if (!it->first.startsWith(path()))
305  vl::Log::warning( Say("ZippedFile '%s' does not belong to ZippedDirectory '%s'.\n") << it->first << path() );
306  file_list.push_back( it->first );
307  }
308 }
309 //-----------------------------------------------------------------------------
310 void ZippedDirectory::listSubDirs(std::vector<String>& dirs, bool append) const
311 {
312  if (!append)
313  dirs.clear();
314  if (path().empty())
315  {
316  Log::error( "VirtualDirectory::path() must not be empty!\n" );
317  return;
318  }
319  std::set<String> sub_dirs;
320  for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
321  {
322  VL_CHECK(it->first.startsWith(path()))
323  String p = it->first.extractPath();
324  if (path().length())
325  p = p.right(-path().length());
326  while(p.startsWith('/'))
327  p = p.right(-1);
328  String drive_letter;
329  if (p.length()>3 && p[1] == ':' && p[2] == '/')
330  {
331  drive_letter = p.left(3);
332  p = p.right(-3);
333  }
334  if (p.empty()) // is a file
335  continue;
336  std::vector<String> tokens;
337  p.split('/',tokens,true);
338  if (tokens.size())
339  sub_dirs.insert(path() + tokens[0]);
340  }
341  for(std::set<String>::const_iterator it = sub_dirs.begin(); it != sub_dirs.end(); ++it)
342  dirs.push_back(*it);
343 }
344 //-----------------------------------------------------------------------------
346 {
347  if (path().empty())
348  {
349  Log::error( "VirtualDirectory::path() must not be empty!\n" );
350  return NULL;
351  }
352  String p = translatePath(subdir_name);
354  for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
355  {
356  if (it->first.startsWith(p+'/'))
357  {
358  ref<ZippedFile> mfile = static_cast<ZippedFile*>(it->second->clone().get());
359  VL_CHECK(mfile)
360  dir->mFiles[mfile->path()] = mfile;
361  }
362  }
363 
364  if (dir->mFiles.empty())
365  return NULL;
366  else
367  return dir;
368 }
369 //-----------------------------------------------------------------------------
370 void ZippedDirectory::listFiles(std::vector<String>& file_list, bool append) const
371 {
372  if (!append)
373  file_list.clear();
374  if (path().empty())
375  {
376  Log::error( "VirtualDirectory::path() must not be empty!\n" );
377  return;
378  }
379  for( std::map< String, ref<ZippedFile> >::const_iterator it = mFiles.begin(); it != mFiles.end(); ++it )
380  {
381  if (it->first.extractPath().left(-1) == path())
382  file_list.push_back( it->first );
383  }
384 }
385 //-----------------------------------------------------------------------------
387 {
388  if ( !init() )
389  return true;
390  for (int i=0; i<zippedFileCount(); ++i)
391  if ( zippedFile(i)->crc32() != zippedFile(i)->zippedFileInfo()->crc32() )
392  return true;
393  return false;
394 }
395 //-----------------------------------------------------------------------------
long long read(void *buffer, long long byte_count)
Reads byte_count bytes from a file. Returns the number of bytes actually read.
Definition: VirtualFile.cpp:82
VLCORE_EXPORT FileSystem * defFileSystem()
Returns the default FileSystem used by VisualizationLibrary.
Definition: pimpl.cpp:97
const VirtualFile * sourceZipFile() const
std::map< String, ref< ZippedFile > > mFiles
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
Collects the information about a ZippedFile.
Definition: ZippedFile.hpp:46
A simple String formatting class.
Definition: Say.hpp:124
static void warning(const String &message)
Use this function to provide information about situations that might lead to errors or loss of data...
Definition: Log.cpp:155
String & resize(int character_count)
Resizes the string to the specified character count.
Definition: String.cpp:146
static String fromUTF8(const char *str, int byte_count=-1)
Accepts strings with and without UTF8 signature.
Definition: String.cpp:1000
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
unsigned short mCompressionMethod
Definition: ZippedFile.hpp:99
bool seekCur(long long offset)
Changes the current read/write position of a file.
unsigned short mExtraFieldLength
Definition: ZippedFile.hpp:104
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
String extractPath() const
If the String contains a file path the function returns the path with trailing slash, without the file name.
Definition: String.cpp:830
ref< VirtualFile > mSourceZipFile
virtual ref< VirtualFile > locateFile(const String &full_path, const String &alternate_path=String()) const
Looks for a VirtualFile on the disk and in the currently active FileSystem.
Definition: FileSystem.cpp:61
bool setPath(const String &name)
Changes the path name of a VirtualDirectory. Must not be an empty string.
ref< ZippedDirectory > zippedSubDir(const String &subdir_name) const
String left(int count) const
Returns the count leftmost caracters of a String. If count is negative the function returns all but t...
Definition: String.cpp:814
String & normalizeSlashes()
Transform \ slashes in / slashes and removes duplicates.
Definition: String.cpp:534
String & trim(wchar_t ch)
Removes the specified character ch from the beginning and the end of the String.
Definition: String.cpp:322
virtual void close()=0
Closes the file.
ref< VirtualFile > file(const String &name) const
Returns the VirtualFile with the given name if any, NULL otherwise.
const String & path() const
Returns the path of the file.
Definition: VirtualFile.hpp:98
Visualization Library main namespace.
virtual const String & path() const
void setZippedFileInfo(ZippedFileInfo *info)
Definition: ZippedFile.cpp:359
unsigned short mFileNameLength
Definition: ZippedFile.hpp:103
void setSourceZipFile(VirtualFile *file)
bool empty() const
Returns true if length() == 0.
Definition: String.hpp:136
virtual bool open(EOpenMode mode)=0
Opens the file in the specified mode.
void split(wchar_t separator, std::vector< String > &fields, bool remove_empty_fields=false) const
Splits a String into a set of fields. The fields are separated by the specified separator and are ret...
Definition: String.cpp:386
bool startsWith(const String &str) const
Returns true if a String starts with the specified String str.
Definition: String.cpp:720
void listSubDirs(std::vector< String > &dirs, bool append=false) const
#define NULL
Definition: OpenGLDefs.hpp:81
void setSourceZipFile(VirtualFile *file)
Definition: ZippedFile.hpp:94
unsigned short mGeneralPurposeFlag
Definition: ZippedFile.hpp:98
unsigned int mZippedFileOffset
Definition: ZippedFile.hpp:113
unsigned short readUInt16(bool little_endian_data=true)
Reads single entry.
void setPath(const String &name)
Changes the path bound to a VirtualFile. Use carefully this function, you shouldn&#39;t rename a VirtualF...
void reset()
Sets the source zip file to NULL and disposes all the files contained in this directory.
void listFilesRecursive(std::vector< String > &file_list) const
Returns the list of files contained in the VirtualDirectory.
ref< ZippedFile > zippedFile(const String &name) const
Accepts absolute and relative paths.
unsigned int readUInt32(bool little_endian_data=true)
Reads single entry.
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
unsigned short mVersionNeeded
Definition: ZippedFile.hpp:97
T length(T v)
Definition: glsl_math.hpp:1084
String right(int count) const
Returns the count rightmost caracters of a String. If count is negative the function returns all but ...
Definition: String.cpp:822
std::string toStdString() const
Returns a UTF8 encoded std::string.
Definition: String.cpp:1156
bool endsWith(const String &str) const
Returns true if a String ends with the specified String str.
Definition: String.cpp:705
long long position() const
Returns the current position in the file.
Definition: VirtualFile.cpp:98
#define VL_CHECK(expr)
Definition: checks.hpp:73
String translatePath(const String &p) const
void listFiles(std::vector< String > &file_list, bool append=false) const
A VirtualFile used to read a file contained in a .zip archive.
Definition: ZippedFile.hpp:133
unsigned int mCompressedSize
Definition: ZippedFile.hpp:101
unsigned int mCRC32
Definition: ZippedFile.hpp:100
unsigned int mUncompressedSize
Definition: ZippedFile.hpp:102