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
48namespace 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
95DirectoryCollection::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
149}
150
151
172FileEntry::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
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
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
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.
A file entry that does not use compression.
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
bool isDirectory() const
Check whether the file is a directory.
Definition filepath.cpp:388
bool isRegular() const
Check whether the file is a regular file.
Definition filepath.cpp:374
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.