zipios  2.2.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-2019 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 == nullptr || 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 occurred 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 occurred 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 == nullptr)
356  {
357  throw IOException("an I/O error occurred 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  // we must reset errno because readdir() does not change it
369  // when the end of the directory is reached
370  //
371  // Note: readdir() is expected to be thread safe as long as
372  // each thread use a different m_dir parameter
373  //
374  errno = 0;
375  struct dirent * entry(readdir(m_dir));
376  if(entry == nullptr)
377  {
378  if(errno != 0)
379  {
380  throw IOException("an I/O error occurred while reading a directory"); // LCOV_EXCL_LINE
381  }
382  return std::string();
383  }
384 
385  return entry->d_name;
386  }
387 
388  private:
389  DIR * m_dir;
390  };
391 #endif
392 
393  read_dir_t dir(m_filepath + subdir);
394  for(;;)
395  {
396  std::string const& name(dir.next());
397  if(name.empty())
398  {
399  break;
400  }
401 
402  // skip the "." and ".." directories, they are never added to
403  // a Zip archive
404  if(name != "." && name != "..")
405  {
406  FileEntry::pointer_t entry(new DirectoryEntry(m_filepath + subdir + name, ""));
407  m_entries.push_back(entry);
408 
409  if(m_recursive && entry->isDirectory())
410  {
411  load(subdir + name);
412  }
413  }
414  }
415 }
416 
417 
418 } // zipios namespace
419 
420 // Local Variables:
421 // mode: cpp
422 // indent-tabs-mode: nil
423 // c-basic-offset: 4
424 // tab-width: 4
425 // End:
426 
427 // 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
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:374
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:388
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:78
std::vector< pointer_t > vector_t
Definition: fileentry.hpp:79