zipios  2.3.2
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-2022 Made to Order Software Corp. All Rights Reserved
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 {
67 }
68 
69 
93  std::string const & path
94  , bool recursive)
95  : m_recursive(recursive)
96  , m_filepath(path)
97 {
100 }
101 
102 
108 {
109  close();
110 }
111 
112 
119 {
120  m_entries_loaded = false;
121  m_filepath.clear();
122 
124 }
125 
126 
143 {
144  loadEntries();
145 
146  return FileCollection::entries();
147 }
148 
149 
170 FileEntry::pointer_t DirectoryCollection::getEntry(std::string const & name, MatchPath matchpath) const
171 {
172  loadEntries();
173 
174  return FileCollection::getEntry(name, matchpath);
175 }
176 
177 
204 {
205  FileEntry::pointer_t ent(getEntry(entry_name, matchpath));
206  if(ent == nullptr || ent->isDirectory())
207  {
209  }
210 
211  DirectoryCollection::stream_pointer_t p(std::make_shared<std::ifstream>(ent->getName(), std::ios::in | std::ios::binary));
212  return p;
213 }
214 
215 
224 {
225  return std::make_shared<DirectoryCollection>(*this);
226 }
227 
228 
237 {
238  // WARNING: this has to stay here because the collection could get close()'d...
239  mustBeValid();
240 
241  if(!m_entries_loaded)
242  {
243  m_entries_loaded = true;
244 
245  // if the read fails then the directory may have been deleted
246  // in which case we want to invalidate this DirectoryCollection
247  // object
248  try
249  {
250  // include the root directory
251  FileEntry::pointer_t entry(std::make_shared<DirectoryEntry>(m_filepath, ""));
252  const_cast<DirectoryCollection *>(this)->m_entries.push_back(entry);
253 
254  // now read the data inside that directory
255  if(m_filepath.isDirectory())
256  {
257  const_cast<DirectoryCollection *>(this)->load(FilePath());
258  }
259  }
260  catch(...)
261  {
262  const_cast<DirectoryCollection *>(this)->close();
263  throw;
264  }
265  }
266 }
267 
268 
279 {
280 #ifdef ZIPIOS_WINDOWS
281  struct read_dir_t
282  {
283  read_dir_t(FilePath const & path)
284  {
290  m_handle = _findfirsti64(static_cast<std::string>(path).c_str(), &m_fileinfo);
291  if(m_handle == 0)
292  {
293  if(errno == ENOENT)
294  {
295  // this can happen, the directory is empty and thus has
296  // absolutely no information
297  m_read_first = true;
298  }
299  else
300  {
301  throw IOException("an I/O error occurred while reading a directory");
302  }
303  }
304  }
305 
306  ~read_dir_t()
307  {
308  // a completely empty directory may give us a "null pointer"
309  // when calling _[w]findfirst[i64]()
310  if(m_handle != 0)
311  {
312  _findclose(m_handle);
313  }
314  }
315 
316  std::string next()
317  {
318  if(m_read_first)
319  {
320  __int64 const r(_findnexti64(m_handle, &m_fileinfo));
321  if(r != 0)
322  {
323  if(errno != ENOENT)
324  {
325  throw IOException("an I/O error occurred while reading a directory");
326  }
327  return std::string();
328  }
329  }
330  else
331  {
332  // the _findfirst() includes a response, use it!
333  m_read_first = true;
334  }
335 
336  return m_fileinfo.name;
337  }
338 
339  private:
340  long m_handle = 0;
341  struct _finddatai64_t m_fileinfo = {};
342  bool m_read_first = 0;
343  };
344 #else
345  struct read_dir_t
346  {
347  read_dir_t(FilePath const & path)
348  : m_dir(opendir(static_cast<std::string>(path).c_str()))
349  {
350  if(m_dir == nullptr)
351  {
352  throw IOException("an I/O error occurred while trying to access directory");
353  }
354  }
355 
356  ~read_dir_t()
357  {
358  closedir(m_dir);
359  }
360 
361  std::string next()
362  {
363  // we must reset errno because readdir() does not change it
364  // when the end of the directory is reached
365  //
366  // Note: readdir() is expected to be thread safe as long as
367  // each thread use a different m_dir parameter
368  //
369  errno = 0;
370  struct dirent * entry(readdir(m_dir));
371  if(entry == nullptr)
372  {
373  if(errno != 0)
374  {
375  throw IOException("an I/O error occurred while reading a directory"); // LCOV_EXCL_LINE
376  }
377  return std::string();
378  }
379 
380  return entry->d_name;
381  }
382 
383  private:
384  DIR * m_dir = nullptr;
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(std::make_shared<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
virtual FileEntry::vector_t entries() const override
Retrieve a vector to the collection entries.
Various exceptions used throughout the Zipios library, all based on zipios::Exception.
void clear()
Clear the filename.
Definition: filepath.cpp:301
std::shared_ptr< std::istream > stream_pointer_t
A shared pointer to an input stream.
Define the zipios::DirectoryCollection class.
A collection generated from reading a directory.
virtual FileEntry::vector_t entries() const
Retrieve the array of entries.
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:422
An IOException is used to signal an I/O error.
virtual void close()
Close the current FileEntry of this FileCollection.
void load(FilePath const &subdir)
This is the function loading all the file entries.
virtual void mustBeValid() const
Check whether the collection is valid.
void loadEntries() const
This is an internal function that loads the file entries.
bool isRegular() const
Check whether the file is a regular file.
Definition: filepath.cpp:408
Handle a file path and name and its statistics.
Definition: filepath.hpp:46
virtual ~DirectoryCollection() override
Clean up a DirectoryCollection object.
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