zipios 2.3.4
Zipios -- a small C++ library providing 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
48namespace zipios
49{
50
68
69
93 std::string const & path
94 , bool recursive)
95 : m_recursive(recursive)
96 , m_filepath(path)
97{
100}
101
102
111
112
125
126
148
149
170FileEntry::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
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
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
A collection generated from reading a directory.
virtual FileEntry::vector_t entries() const override
Retrieve a vector to the collection entries.
virtual ~DirectoryCollection() override
Clean up a DirectoryCollection object.
void load(FilePath const &subdir)
This is the function loading all the file entries.
virtual pointer_t clone() const override
Create another DirectoryCollection.
DirectoryCollection()
Initialize a DirectoryCollection object.
virtual stream_pointer_t getInputStream(std::string const &entry_name, MatchPath matchpath=MatchPath::MATCH) override
Retrieve pointer to an istream.
virtual void close() override
Close the directory collection.
virtual FileEntry::pointer_t getEntry(std::string const &name, MatchPath matchpath=MatchPath::MATCH) const override
Get an entry from the collection.
void loadEntries() const
This is an internal function that loads the file entries.
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 void mustBeValid() const
Check whether the collection is valid.
std::shared_ptr< std::istream > stream_pointer_t
A shared pointer to an input stream.
virtual void close()
Close the current FileEntry of this FileCollection.
FileEntry::vector_t m_entries
virtual FileEntry::vector_t entries() const
Retrieve the array of entries.
std::shared_ptr< FileEntry > pointer_t
Definition fileentry.hpp:78
std::vector< pointer_t > vector_t
Definition fileentry.hpp:79
Handle a file path and name and its statistics.
Definition filepath.hpp:47
void clear()
Clear the filename.
Definition filepath.cpp:301
bool isDirectory() const
Check whether the file is a directory.
Definition filepath.cpp:422
bool isRegular() const
Check whether the file is a regular file.
Definition filepath.cpp:408
An IOException is used to signal an I/O error.
Define the zipios::DirectoryCollection class.
The zipios namespace includes the Zipios library definitions.
Various exceptions used throughout the Zipios library, all based on zipios::Exception.