zipios  2.1.0
Zipios++ – a small C++ library that provides easy access to .zip files.
directorycollection.cpp
Go to the documentation of this file.
1 /*
2  Zipios++ - a small C++ library that provides easy access to .zip files.
3 
4  Copyright (C) 2000-2007 Thomas Sondergaard
5  Copyright (C) 2015 Made to Order Software Corporation
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
30 #if defined(_WINDOWS) || defined(WIN32) || defined(_WIN32) || defined(__WIN32)
31 #define ZIPIOS_WINDOWS
32 #endif
33 
35 
37 
38 #include <fstream>
39 
40 #ifdef ZIPIOS_WINDOWS
41 #include <io.h>
42 #else
43 #include <dirent.h>
44 #include <errno.h>
45 #endif
46 
47 
48 namespace zipios
49 {
50 
66  //: m_entries_loaded(false) -- auto-init
67  //, m_recursive(true) -- auto-init
68  //, m_filepath("") -- auto-init
69 {
70 }
71 
72 
95 DirectoryCollection::DirectoryCollection(std::string const & path, bool recursive)
96  //: m_entries_loaded(false) -- auto-init
97  : m_recursive(recursive)
98  , m_filepath(path)
99 {
102 }
103 
104 
110 {
111  close();
112 }
113 
114 
121 {
122  m_entries_loaded = false;
123  m_filepath = "";
124 
126 }
127 
128 
145 {
146  loadEntries();
147 
148  return FileCollection::entries();
149 }
150 
151 
172 FileEntry::pointer_t DirectoryCollection::getEntry(std::string const & name, MatchPath matchpath) const
173 {
174  loadEntries();
175 
176  return FileCollection::getEntry(name, matchpath);
177 }
178 
179 
206 {
207  FileEntry::pointer_t ent(getEntry(entry_name, matchpath));
208  if(!ent || ent->isDirectory())
209  {
211  }
212 
213  DirectoryCollection::stream_pointer_t p(new std::ifstream(ent->getName(), std::ios::in | std::ios::binary));
214  return p;
215 }
216 
217 
226 {
228 }
229 
230 
239 {
240  // WARNING: this has to stay here because the collection could get close()'s...
241  mustBeValid();
242 
243  if(!m_entries_loaded)
244  {
245  m_entries_loaded = true;
246 
247  // if the read fails then the directory may have been deleted
248  // in which case we want to invalidate this DirectoryCollection
249  // object
250  try
251  {
252  // include the root directory
254  const_cast<DirectoryCollection *>(this)->m_entries.push_back(entry);
255 
256  // now read the data inside that directory
257  if(m_filepath.isDirectory())
258  {
259  const_cast<DirectoryCollection *>(this)->load(FilePath());
260  }
261  }
262  catch(...)
263  {
264  const_cast<DirectoryCollection *>(this)->close();
265  throw;
266  }
267  }
268 }
269 
270 
281 {
282 #ifdef ZIPIOS_WINDOWS
283  struct read_dir_t
284  {
285  read_dir_t(FilePath const& path)
286  //: m_handle(0) -- auto-init
287  //, m_fileinfo() -- initialized below
288  //, m_read_first(false) -- auto-init
289  {
295  m_handle = _findfirsti64(path.getName().c_str(), &m_findinfo);
296  if(m_handle == 0)
297  {
298  if(errno == ENOENT)
299  {
300  // this can happen, the directory is empty and thus has
301  // absolutely no information
302  f_read_first = true;
303  }
304  else
305  {
306  throw IOException("an I/O error occured while reading a directory");
307  }
308  }
309  }
310 
311  ~read_dir_t()
312  {
313  // a completely empty directory may give us a "null pointer"
314  // when calling _[w]findfirst[i64]()
315  if(m_handle != 0)
316  {
317  _findclose(m_handle);
318  }
319  }
320 
321  std::string next()
322  {
323  if(m_read_first)
324  {
325  __int64 const r(_findnexti64(m_handle, &m_fileinfo));
326  if(r != 0)
327  {
328  if(errno != ENOENT)
329  {
330  throw IOException("an I/O error occured while reading a directory");
331  }
332  return std::string();
333  }
334  }
335  else
336  {
337  // the _findfirst() includes a response, use it!
338  m_read_first = true;
339  }
340 
341  return m_fileinfo.name;
342  }
343 
344  private:
345  long m_handle = 0;
346  struct _finddata_t m_fileinfo;
347  bool m_read_first = 0;
348  };
349 #else
350  struct read_dir_t
351  {
352  read_dir_t(FilePath const& path)
353  : m_dir(opendir(static_cast<std::string>(path).c_str()))
354  {
355  if(!m_dir)
356  {
357  throw IOException("an I/O error occured while trying to access directory");
358  }
359  }
360 
361  ~read_dir_t()
362  {
363  closedir(m_dir);
364  }
365 
366  std::string next()
367  {
368  errno = 0;
369  struct dirent *entry, e;
370  int const r(readdir_r(m_dir, &e, &entry));
371  if(r != 0)
372  {
373  throw IOException("an I/O error occured while reading a directory"); // LCOV_EXCL_LINE
374  }
375  if(entry == NULL)
376  {
377  return std::string();
378  }
379 
380  return entry->d_name;
381  }
382 
383  private:
384  DIR * m_dir;
385  };
386 #endif
387 
388  read_dir_t dir(m_filepath + subdir);
389  for(;;)
390  {
391  std::string const& name(dir.next());
392  if(name.empty())
393  {
394  break;
395  }
396 
397  // skip the "." and ".." directories, they are never added to
398  // a Zip archive
399  if(name != "." && name != "..")
400  {
401  FileEntry::pointer_t entry(new DirectoryEntry(m_filepath + subdir + name, ""));
402  m_entries.push_back(entry);
403 
404  if(m_recursive && entry->isDirectory())
405  {
406  load(subdir + name);
407  }
408  }
409  }
410 }
411 
412 
413 } // zipios namespace
414 
415 // Local Variables:
416 // mode: cpp
417 // indent-tabs-mode: nil
418 // c-basic-offset: 4
419 // tab-width: 4
420 // End:
421 
422 // vim: ts=4 sw=4 et
virtual FileEntry::pointer_t getEntry(std::string const &name, MatchPath matchpath=MatchPath::MATCH) const
Get an entry from this collection.
std::shared_ptr< FileCollection > pointer_t
virtual FileEntry::vector_t entries() const override
Retrieve a vector to the collection entries.
void loadEntries() const
This is an internal function that loads the file entries.
Various exceptions used throughout the Zipios++ library, all based on zipios::Exception.
bool isRegular() const
Check whether the file is a regular file.
Definition: filepath.cpp:372
std::shared_ptr< std::istream > stream_pointer_t
A shared pointer to an input stream.
virtual FileEntry::vector_t entries() const
Retrieve the array of entries.
Define the zipios::DirectoryCollection class.
A collection generated from reading a directory.
virtual void close() override
Close the directory collection.
virtual pointer_t clone() const override
Create another DirectoryCollection.
DirectoryCollection()
Initialize a DirectoryCollection object.
FileEntry::vector_t m_entries
bool isDirectory() const
Check whether the file is a directory.
Definition: filepath.cpp:386
An IOException is used to signal an I/O error.
virtual void close()
Close the current FileEntry of this FileCollection.
virtual void mustBeValid() const
Check whether the collection is valid.
void load(FilePath const &subdir)
This is the function loading all the file entries.
Handle a file path and name and its statistics.
Definition: filepath.hpp:46
virtual ~DirectoryCollection() override
Clean up a DirectoryCollection object.
A file entry that does not use compression.
virtual stream_pointer_t getInputStream(std::string const &entry_name, MatchPath matchpath=MatchPath::MATCH) override
Retrieve pointer to an istream.
virtual FileEntry::pointer_t getEntry(std::string const &name, MatchPath matchpath=MatchPath::MATCH) const override
Get an entry from the collection.
std::shared_ptr< FileEntry > pointer_t
Definition: fileentry.hpp:77
std::vector< pointer_t > vector_t
Definition: fileentry.hpp:78