zipios  2.1.1
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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
30 #if !defined(ZIPIOS_WINDOWS) && (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.
The zipios namespace includes the Zipios++ library definitions.
Definition: backbuffer.cpp:35
std::shared_ptr< FileCollection > pointer_t
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.
virtual pointer_t clone() const override
Create another DirectoryCollection.
virtual FileEntry::pointer_t getEntry(std::string const &name, MatchPath matchpath=MatchPath::MATCH) const override
Get an entry from the collection.
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.
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.
std::shared_ptr< FileEntry > pointer_t
Definition: fileentry.hpp:77
virtual FileEntry::vector_t entries() const override
Retrieve a vector to the collection entries.
std::vector< pointer_t > vector_t
Definition: fileentry.hpp:78