ZipFile.hpp
Go to the documentation of this file.
1 // @formatter:off
2 //
3 // Balau core C++ library
4 //
5 // Copyright (C) 2008 Bora Software (contact@borasoftware.com)
6 //
7 // Licensed under the Boost Software License - Version 1.0 - August 17th, 2003.
8 // See the LICENSE file for the full license text.
9 //
10 
16 
17 #ifndef COM_BORA_SOFTWARE__BALAU_RESOURCE__ZIP_FILE
18 #define COM_BORA_SOFTWARE__BALAU_RESOURCE__ZIP_FILE
19 
20 #include <Balau/Resource/File.hpp>
22 
23 namespace Balau::Resource {
24 
35 class ZipFile : public File {
39  public: class RecursiveZipFileIterator {
43  public: bool hasNext() const {
44  return nextEntryIndex < entryCount;
45  }
46 
50  public: ZipEntry next() {
51  return ZipEntry(archive, nextEntryIndex++);
52  }
53 
54  friend class ZipFile;
55 
56  private: RecursiveZipFileIterator(ZipFile & zipFile, bool verify, const std::string & pw)
57  : nextEntryIndex(0) {
58  archive.open(zipFile, verify, pw);
59 
60  if (!archive.isOpen()) {
62  Exception::ZipException, "Could not open zip file for reading.", File(zipFile.entry)
63  );
64  }
65 
66  entryCount = archive.entryCount();
67  }
68 
69  private: Util::Unzipper archive;
70  private: long long nextEntryIndex;
71  private: long long entryCount;
72  };
73 
74  private: class RecursiveZipFileUriIterator : public RecursiveUriIterator {
78  public: bool hasNext() const override {
79  return nextEntryIndex < entryCount;
80  }
81 
85  public: std::unique_ptr<Uri> next() override {
86  return std::unique_ptr<Uri>(new ZipEntry(archive, nextEntryIndex++));
87  }
88 
89  friend class ZipFile;
90 
91  private: RecursiveZipFileUriIterator(const ZipFile & zipFile, bool verify, const std::string & pw)
92  : nextEntryIndex(0) {
93  archive.open(zipFile, verify, pw);
94 
95  if (!archive.isOpen()) {
97  Exception::ZipException, "Could not open zip file for reading.", File(zipFile.entry)
98  );
99  }
100 
101  entryCount = archive.entryCount();
102  }
103 
104  private: Util::Unzipper archive;
105  private: long long nextEntryIndex;
106  private: long long entryCount;
107  };
108 
114  public: class ZipFileIterator {
118  public: bool hasNext() const {
119  return nextEntryIndex < entryCount;
120  }
121 
125  public: ZipEntry next() {
126  return ZipEntry(archive, nextEntryIndex++);
127  }
128 
129  friend class ZipFile;
130 
131  private: explicit ZipFileIterator(ZipFile & zipFile, bool verify, const std::string & pw)
132  : nextEntryIndex(0) {
134 
135  archive.open(zipFile, verify, pw);
136 
137  if (!archive.isOpen()) {
139  Exception::ZipException, "Could not open zip file for reading.", File(zipFile.entry)
140  );
141  }
142 
143  entryCount = archive.entryCount();
144  }
145 
146  private: Util::Unzipper archive;
147  private: long long nextEntryIndex;
148  private: long long entryCount;
149  };
150 
151  // TODO not yet implemented
152  private: class ZipFileUriIterator : public UriIterator {
156  public: bool hasNext() const override {
157  return nextEntryIndex < entryCount;
158  }
159 
163  public: std::unique_ptr<Uri> next() override {
164  return std::unique_ptr<Uri>(new ZipEntry(archive, nextEntryIndex++));
165  }
166 
167  friend class ZipFile;
168 
169  private: ZipFileUriIterator(const ZipFile & zipFile, bool verify, const std::string & pw)
170  : nextEntryIndex(0) {
172 
173  archive.open(zipFile, verify, pw);
174 
175  if (!archive.isOpen()) {
177  Exception::ZipException, "Could not open zip file for reading.", File(zipFile.entry)
178  );
179  }
180 
181  entryCount = archive.entryCount();
182  }
183 
184  private: Util::Unzipper archive;
185  private: long long nextEntryIndex;
186  private: long long entryCount;
187  };
188 
198  public: explicit ZipFile(File file_, std::string password_ = "")
199  : File(std::move(file_))
200  , password(std::move(password_)) {}
201 
205  public: ZipFile(const ZipFile & zipFile) = default;
206 
210  public: ZipFile(ZipFile && zipFile) noexcept
211  : File(std::move(zipFile)) {}
212 
216  public: ZipFile & operator = (const ZipFile & zipFile) = default;
217 
221  public: ZipFile & operator = (ZipFile && zipFile) = default;
222 
223  public: std::unique_ptr<Uri> clone() const override {
224  return std::unique_ptr<Uri>(new ZipFile(*this));
225  }
226 
227  public: std::unique_ptr<Uri> append(const std::string & pathComponent) const override {
228  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile does not support path appending.");
229  }
230 
231  public: std::unique_ptr<Uri> resolve(std::string_view path) const override {
232  static const std::regex scheme { "[a-zA-Z][a-zA-Z0-9+-\\.]*:" };
233 
234  auto cleanPath = Util::Strings::trim(path);
235  auto str = std::string(cleanPath);
236 
237  if (Util::Strings::startsWithRegex(str, scheme)) {
238  std::unique_ptr<Uri> uri;
239  fromString(uri, str);
240  return uri;
241  }
242 
243  boost::filesystem::path p(str);
244 
245  if (p.is_relative()) {
246  auto p2 = boost::filesystem::relative(p, entry.path());
247  return std::unique_ptr<Uri>(new ZipFile(File(p2)));
248  } else { // absolute
249  return std::unique_ptr<Uri>(new ZipFile(File(p)));
250  }
251  }
252 
253  public: bool canReadFrom() const override {
254  return false;
255  }
256 
257  public: bool canWriteTo() const override {
258  return false;
259  }
260 
261  public: std::unique_ptr<ByteReadResource> byteReadResource() const override {
262  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have a byte read resource.");
263  }
264 
265  public: std::unique_ptr<Utf8To32ReadResource> utf8To32ReadResource() const override {
266  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have a Unicode read resource.");
267  }
268 
269  public: std::unique_ptr<ByteWriteResource> byteWriteResource() override {
270  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have a byte write resource.");
271  }
272 
273  public: std::unique_ptr<Utf32To8WriteResource> utf32To8WriteResource() override {
274  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have a Unicode write resource.");
275  }
276 
277  public: bool isRecursivelyIterable() const override {
278  return true;
279  }
280 
281  public: bool isIterable() const override {
282  return true;
283  }
284 
285  public: std::unique_ptr<RecursiveUriIterator> recursiveIterator() const override {
286  return std::unique_ptr<RecursiveUriIterator>(new RecursiveZipFileUriIterator(*this, false, ""));
287  }
288 
289  public: std::unique_ptr<UriIterator> iterator() const override {
290  return std::unique_ptr<UriIterator>(new ZipFileUriIterator(*this, false, ""));
291  }
292 
300  public: RecursiveZipFileIterator recursiveZipFileIterator(bool verify = false, const std::string & pw = "") {
301  return RecursiveZipFileIterator(*this, verify, pw);
302  }
303 
311  public: ZipFileIterator zipFileIterator(bool verify = false, const std::string & pw = "") {
312  return ZipFileIterator(*this, verify, pw);
313  }
314 
315  public: RecursiveFileIterator recursiveFileIterator() const override {
316  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have recursive file iterators.");
317  }
318 
319  public: FileIterator fileIterator() const override {
320  ThrowBalauException(Exception::UnsupportedOperationException, "ZipFile URIs do not have file iterators.");
321  }
322 
323  public: bool operator == (const Uri & rhs) const override {
324  const auto * o = dynamic_cast<const ZipFile *>(&rhs);
325  return o == nullptr ? false : getEntry() == o->getEntry();
326  }
327 
328  public: bool isRegularDirectory() const override {
329  return false;
330  }
331 
332  public: bool isRegularFile() const override {
333  return true;
334  }
335 
336  public: void dispatch(UriDispatcher & dispatcher) const override {
337  dispatcher.dispatch(*this);
338  }
339 
341 
342  private: std::string password;
343 };
344 
350 template <typename AllocatorT>
352  return zipFile.toRawString<AllocatorT>();
353 }
354 
360 inline std::string toString(const ZipFile & zipFile) {
361  return zipFile.toRawString();
362 }
363 
364 } // namespace Balau::Resource
365 
366 namespace std { // NOLINT
367 
368 template <> struct hash<Balau::Resource::ZipFile> {
369  size_t operator () (const Balau::Resource::ZipFile & zipFile) const noexcept {
370  return zipFile.hashcode();
371  }
372 };
373 
374 template <> struct equal_to<Balau::Resource::ZipFile> {
375  bool operator () (const Balau::Resource::ZipFile & lhs, const Balau::Resource::ZipFile & rhs) const {
376  return lhs == rhs;
377  }
378 };
379 
380 } // namespace std
381 
382 #endif // COM_BORA_SOFTWARE__BALAU_RESOURCE__ZIP_FILE
bool isRecursivelyIterable() const override
Does the URI have a recursive iterator (examples: file and zip archive URIs).
Definition: ZipFile.hpp:277
virtual void dispatch(const File &object)=0
Visit a File URI.
ZipFile(ZipFile &&zipFile) noexcept
Create a new zip file by moving the contents of the supplied instance.
Definition: ZipFile.hpp:210
std::unique_ptr< Utf8To32ReadResource > utf8To32ReadResource() const override
Get a UTF-8 to UTF-32 read resource for the URI.
Definition: ZipFile.hpp:265
Random access to the entries in a zip archive.
Definition: Zip.hpp:155
Recursive iterator into a zip file.
Definition: ZipFile.hpp:39
RecursiveFileIterator recursiveFileIterator() const override
Get a recursive file iterator for this file (directory).
Definition: ZipFile.hpp:315
std::unique_ptr< UriIterator > iterator() const override
Get a (non-recursive) iterator.
Definition: ZipFile.hpp:289
A file on the local file system.
#define ThrowBalauException(ExceptionClass,...)
Throw a Balau style exception, with implicit file and line number, and optional stacktrace.
Definition: BalauException.hpp:45
virtual void open(const Resource::File &path_, bool verify)
Open the specified archive for reading.
bool canReadFrom() const override
Can data be read from the URI via a read resource.
Definition: ZipFile.hpp:253
Recursive iteration into a directory structure.
Definition: File.hpp:39
ZipFile & operator=(const ZipFile &zipFile)=default
Assign the zip file by copying the supplied instance.
Non-recursive iterator into a zip file.
Definition: ZipFile.hpp:114
void fromString(File &destination, std::string_view value)
Overwrite the supplied file URI by assignment by converting the supplied UTF-8 string to a file URI...
Definition: File.hpp:733
bool isRegularFile() const override
Returns true if the file URI points to a regular file.
Definition: ZipFile.hpp:332
ZipEntry next()
Get the next item in the iterator.
Definition: ZipFile.hpp:125
A zip file on the local file system.
Definition: ZipFile.hpp:35
An abstract universal resource identifier.
Definition: Uri.hpp:131
bool isRegularDirectory() const override
Returns true if the file URI points to a directory.
Definition: ZipFile.hpp:328
STL namespace.
bool hasNext() const
Returns true if there is another item available in the iterator.
Definition: ZipFile.hpp:118
Thrown when a zip resource has an error.
Definition: ResourceExceptions.hpp:124
bool hasNext() const
Returns true if there is another item available in the iterator.
Definition: ZipFile.hpp:43
The unified resource class hierarchy.
Definition: ByteReadResource.hpp:24
ZipFile(File file_, std::string password_="")
Create a new zip file for the specified file.
Definition: ZipFile.hpp:198
std::unique_ptr< ByteWriteResource > byteWriteResource() override
Get a byte write resource for the URI.
Definition: ZipFile.hpp:269
Thrown when a feature is not yet implemented.
Definition: BalauException.hpp:162
An abstract read iterator that iterates recursively.
Definition: Uri.hpp:37
ZipFileIterator zipFileIterator(bool verify=false, const std::string &pw="")
Get a non-recursive zip file iterator, specifying if the zip file should be verified and an optional ...
Definition: ZipFile.hpp:311
Non-recursive iteration over a directory&#39;s contents.
Definition: File.hpp:97
FileIterator fileIterator() const override
Get a non-recursive file iterator for this file (directory).
Definition: ZipFile.hpp:319
Balau::U8String< AllocatorT > toString(const File &file)
Print the file URI as a UTF-8 string.
Definition: File.hpp:724
std::unique_ptr< Uri > append(const std::string &pathComponent) const override
Appends the path component to the supplied URI, returning a new URI.
Definition: ZipFile.hpp:227
std::unique_ptr< RecursiveUriIterator > recursiveIterator() const override
Get a recursive iterator.
Definition: ZipFile.hpp:285
boost::filesystem::directory_entry getEntry() const
Get the underlying directory entry for this file URI.
Definition: File.hpp:400
void dispatch(UriDispatcher &dispatcher) const override
Visitor pattern dispatching.
Definition: ZipFile.hpp:336
static std::string_view trim(const std::string_view &input)
Trim whitespace from the beginning and end of the supplied UTF-8 string.
Definition: Strings.hpp:706
std::unique_ptr< Uri > clone() const override
Clone the concrete Uri.
Definition: ZipFile.hpp:223
A file on the local file system.
Definition: File.hpp:35
std::unique_ptr< Uri > resolve(std::string_view path) const override
Resolve the relative or absolute path, in reference to the current URI.
Definition: ZipFile.hpp:231
std::unique_ptr< Utf32To8WriteResource > utf32To8WriteResource() override
Get a UTF-32 to UTF-8 write resource for the URI.
Definition: ZipFile.hpp:273
std::unique_ptr< ByteReadResource > byteReadResource() const override
Get a byte read resource for the URI.
Definition: ZipFile.hpp:261
RecursiveZipFileIterator recursiveZipFileIterator(bool verify=false, const std::string &pw="")
Get a recursive zip file iterator, specifying if the zip file should be verified and an optional encr...
Definition: ZipFile.hpp:300
std::basic_string< char, std::char_traits< char >, AllocatorT > U8String
UTF-8 string type with selectable allocator.
Definition: ToStringA.hpp:41
std::string toRawString() const override
Get a string representing the raw URI.
Definition: File.hpp:572
static bool startsWithRegex(const std::string &str, const std::regex &prefix)
Does the string start with the specified regular expression?
Definition: Strings.hpp:94
bool operator==(const Uri &rhs) const override
Compare the supplied URI to the current URI.
Definition: ZipFile.hpp:323
size_t hashcode() const noexcept override
Get the URI&#39;s hash code.
Definition: File.hpp:580
long long entryCount() const
Get the number of entries in the original archive if one exists.
An abstract read iterator.
Definition: Uri.hpp:84
File()=default
Create an empty file URI.
An entry in a zip archive on the local file system.
An entry in a zip archive on the local file system.
Definition: ZipEntry.hpp:35
bool canWriteTo() const override
Can data be written to the URI via a write resource.
Definition: ZipFile.hpp:257
bool isOpen() const
Is an archive currently open?
Definition: Zip.hpp:180
bool isIterable() const override
Does the URI have a non-recursive iterator (examples: file and zip archive URIs). ...
Definition: ZipFile.hpp:281
Thrown when an operation is deliberately not implemented.
Definition: BalauException.hpp:154
Visitor interface for URIs.
Definition: UriDispatcher.hpp:32
ZipEntry next()
Get the next item in the iterator.
Definition: ZipFile.hpp:50