ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
quazipdir.cpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2005-2014 Sergey A. Tachenov
3 
4 This file is part of QuaZIP.
5 
6 QuaZIP is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10 
11 QuaZIP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public License
17 along with QuaZIP. If not, see <http://www.gnu.org/licenses/>.
18 
19 See COPYING file for the full LGPL text.
20 
21 Original ZIP package is copyrighted by Gilles Vollant and contributors,
22 see quazip/(un)zip.h files for details. Basically it's the zlib license.
23 */
24 
25 #include "quazipdir.h"
26 
27 #include <QSet>
28 #include <QSharedData>
29 
30 // Qt5/Qt6 Compatibility
31 #include <QtCompat.h>
32 
33 #pragma warning(disable : 4996)
34 
36 class QuaZipDirPrivate : public QSharedData {
37  friend class QuaZipDir;
38 
39 private:
40  QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString())
41  : zip(zip),
42  dir(dir),
43  caseSensitivity(QuaZip::csDefault),
44  filter(QDir::NoFilter),
45  sorting(QDir::NoSort) {}
46  QuaZip *zip;
47  QString dir;
49  QDir::Filters filter;
50  QStringList nameFilters;
51  QDir::SortFlags sorting;
52  template <typename TFileInfoList>
53  bool entryInfoList(QStringList nameFilters,
54  QDir::Filters filter,
55  QDir::SortFlags sort,
56  TFileInfoList &result) const;
57  inline QString simplePath() const { return QDir::cleanPath(dir); }
58 };
60 
61 QuaZipDir::QuaZipDir(const QuaZipDir &that) : d(that.d) {}
62 
63 QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir)
64  : d(new QuaZipDirPrivate(zip, dir)) {
65  if (d->dir.startsWith('/')) d->dir = d->dir.mid(1);
66 }
67 
69 
70 bool QuaZipDir::operator==(const QuaZipDir &that) {
71  return d->zip == that.d->zip && d->dir == that.d->dir;
72 }
73 
75  this->d = that.d;
76  return *this;
77 }
78 
79 QString QuaZipDir::operator[](int pos) const { return entryList().at(pos); }
80 
82  return d->caseSensitivity;
83 }
84 
85 bool QuaZipDir::cd(const QString &directoryName) {
86  if (directoryName == "/") {
87  d->dir = "";
88  return true;
89  }
90  QString dirName = directoryName;
91  if (dirName.endsWith('/')) dirName.chop(1);
92  if (dirName.contains('/')) {
93  QuaZipDir dir(*this);
94  if (dirName.startsWith('/')) {
95 #ifdef QUAZIP_QUAZIPDIR_DEBUG
96  qDebug("QuaZipDir::cd(%s): going to /",
97  dirName.toUtf8().constData());
98 #endif
99  if (!dir.cd("/")) return false;
100  }
101  QStringList path = dirName.split('/', QtCompat::SkipEmptyParts);
102  for (QStringList::const_iterator i = path.constBegin(); i != path.end();
103  ++i) {
104  const QString &step = *i;
105 #ifdef QUAZIP_QUAZIPDIR_DEBUG
106  qDebug("QuaZipDir::cd(%s): going to %s",
107  dirName.toUtf8().constData(), step.toUtf8().constData());
108 #endif
109  if (!dir.cd(step)) return false;
110  }
111  d->dir = dir.path();
112  return true;
113  } else { // no '/'
114  if (dirName == ".") {
115  return true;
116  } else if (dirName == "..") {
117  if (isRoot()) {
118  return false;
119  } else {
120  int slashPos = d->dir.lastIndexOf('/');
121  if (slashPos == -1) {
122  d->dir = "";
123  } else {
124  d->dir = d->dir.left(slashPos);
125  }
126  return true;
127  }
128  } else { // a simple subdirectory
129  if (exists(dirName)) {
130  if (isRoot())
131  d->dir = dirName;
132  else
133  d->dir += "/" + dirName;
134  return true;
135  } else {
136  return false;
137  }
138  }
139  }
140 }
141 
142 bool QuaZipDir::cdUp() { return cd(".."); }
143 
144 uint QuaZipDir::count() const { return entryList().count(); }
145 
146 QString QuaZipDir::dirName() const { return QDir(d->dir).dirName(); }
147 
149  bool *ok,
150  const QString &relativeName,
151  bool isReal) {
152  QuaZipFileInfo64 info;
153  if (isReal) {
154  *ok = zip->getCurrentFileInfo(&info);
155  } else {
156  *ok = true;
157  info.compressedSize = 0;
158  info.crc = 0;
159  info.diskNumberStart = 0;
160  info.externalAttr = 0;
161  info.flags = 0;
162  info.internalAttr = 0;
163  info.method = 0;
164  info.uncompressedSize = 0;
165  info.versionCreated = info.versionNeeded = 0;
166  }
167  info.name = relativeName;
168  return info;
169 }
170 
171 static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
172  QList<QuaZipFileInfo64> &to) {
173  to = from;
174 }
175 
176 static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
177  QStringList &to) {
178  to.clear();
179  for (QList<QuaZipFileInfo64>::const_iterator i = from.constBegin();
180  i != from.constEnd(); ++i) {
181  to.append(i->name);
182  }
183 }
184 
185 static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
186  QList<QuaZipFileInfo> &to) {
187  to.clear();
188  for (QList<QuaZipFileInfo64>::const_iterator i = from.constBegin();
189  i != from.constEnd(); ++i) {
190  QuaZipFileInfo info32;
191  i->toQuaZipFileInfo(info32);
192  to.append(info32);
193  }
194 }
195 
197 
200 class QuaZipDirRestoreCurrent {
201 public:
202  inline QuaZipDirRestoreCurrent(QuaZip *zip)
203  : zip(zip), currentFile(zip->getCurrentFileName()) {}
204  inline ~QuaZipDirRestoreCurrent() { zip->setCurrentFile(currentFile); }
205 
206 private:
207  QuaZip *zip;
208  QString currentFile;
209 };
211 
213 class QuaZipDirComparator {
214 private:
215  QDir::SortFlags sort;
216  static QString getExtension(const QString &name);
217  int compareStrings(const QString &string1, const QString &string2);
218 
219 public:
220  inline QuaZipDirComparator(QDir::SortFlags sort) : sort(sort) {}
221  bool operator()(const QuaZipFileInfo64 &info1,
222  const QuaZipFileInfo64 &info2);
223 };
224 
225 QString QuaZipDirComparator::getExtension(const QString &name) {
226  if (name.endsWith('.') || name.indexOf('.', 1) == -1) {
227  return "";
228  } else {
229  return name.mid(name.lastIndexOf('.') + 1);
230  }
231 }
232 
233 int QuaZipDirComparator::compareStrings(const QString &string1,
234  const QString &string2) {
235  if (sort & QDir::LocaleAware) {
236  if (sort & QDir::IgnoreCase) {
237  return string1.toLower().localeAwareCompare(string2.toLower());
238  } else {
239  return string1.localeAwareCompare(string2);
240  }
241  } else {
242  return string1.compare(string2, (sort & QDir::IgnoreCase)
244  : Qt::CaseSensitive);
245  }
246 }
247 
248 bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1,
249  const QuaZipFileInfo64 &info2) {
250  QDir::SortFlags order =
251  sort & (QDir::Name | QDir::Time | QDir::Size | QDir::Type);
252  if ((sort & QDir::DirsFirst) == QDir::DirsFirst ||
253  (sort & QDir::DirsLast) == QDir::DirsLast) {
254  if (info1.name.endsWith('/') && !info2.name.endsWith('/'))
255  return (sort & QDir::DirsFirst) == QDir::DirsFirst;
256  else if (!info1.name.endsWith('/') && info2.name.endsWith('/'))
257  return (sort & QDir::DirsLast) == QDir::DirsLast;
258  }
259  bool result;
260  int extDiff;
261  switch (order) {
262  case QDir::Name:
263  result = compareStrings(info1.name, info2.name) < 0;
264  break;
265  case QDir::Type:
266  extDiff = compareStrings(getExtension(info1.name),
267  getExtension(info2.name));
268  if (extDiff == 0) {
269  result = compareStrings(info1.name, info2.name) < 0;
270  } else {
271  result = extDiff < 0;
272  }
273  break;
274  case QDir::Size:
275  if (info1.uncompressedSize == info2.uncompressedSize) {
276  result = compareStrings(info1.name, info2.name) < 0;
277  } else {
278  result = info1.uncompressedSize < info2.uncompressedSize;
279  }
280  break;
281  case QDir::Time:
282  if (info1.dateTime == info2.dateTime) {
283  result = compareStrings(info1.name, info2.name) < 0;
284  } else {
285  result = info1.dateTime < info2.dateTime;
286  }
287  break;
288  default:
289  qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X",
290  static_cast<unsigned>(sort));
291  return false;
292  }
293  return (sort & QDir::Reversed) ? !result : result;
294 }
295 
296 template <typename TFileInfoList>
297 bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
298  QDir::Filters filter,
299  QDir::SortFlags sort,
300  TFileInfoList &result) const {
301  QString basePath = simplePath();
302  if (!basePath.isEmpty()) basePath += "/";
303  int baseLength = basePath.length();
304  result.clear();
305  QuaZipDirRestoreCurrent saveCurrent(zip);
306  if (!zip->goToFirstFile()) {
307  return zip->getZipError() == UNZ_OK;
308  }
309  QDir::Filters fltr = filter;
310  if (fltr == QDir::NoFilter) fltr = this->filter;
311  if (fltr == QDir::NoFilter) fltr = QDir::AllEntries;
312  QStringList nmfltr = nameFilters;
313  if (nmfltr.isEmpty()) nmfltr = this->nameFilters;
314  QSet<QString> dirsFound;
315  QList<QuaZipFileInfo64> list;
316  do {
317  QString name = zip->getCurrentFileName();
318  if (!name.startsWith(basePath)) continue;
319  QString relativeName = name.mid(baseLength);
320  if (relativeName.isEmpty()) continue;
321  bool isDir = false;
322  bool isReal = true;
323  if (relativeName.contains('/')) {
324  int indexOfSlash = relativeName.indexOf('/');
325  // something like "subdir/"
326  isReal = indexOfSlash == relativeName.length() - 1;
327  relativeName = relativeName.left(indexOfSlash + 1);
328  if (dirsFound.contains(relativeName)) continue;
329  isDir = true;
330  }
331  dirsFound.insert(relativeName);
332  if ((fltr & QDir::Dirs) == 0 && isDir) continue;
333  if ((fltr & QDir::Files) == 0 && !isDir) continue;
334  if (!nmfltr.isEmpty() && !QDir::match(nmfltr, relativeName)) continue;
335  bool ok;
336  QuaZipFileInfo64 info =
337  QuaZipDir_getFileInfo(zip, &ok, relativeName, isReal);
338  if (!ok) {
339  return false;
340  }
341  list.append(info);
342  } while (zip->goToNextFile());
343  QDir::SortFlags srt = sort;
344  if (srt == QDir::NoSort) srt = sorting;
345 #ifdef QUAZIP_QUAZIPDIR_DEBUG
346  qDebug("QuaZipDirPrivate::entryInfoList(): before sort:");
347  foreach (QuaZipFileInfo64 info, list) {
348  qDebug("%s\t%s", info.name.toUtf8().constData(),
349  info.dateTime.toString(Qt::ISODate).toUtf8().constData());
350  }
351 #endif
352  if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) {
353  if (QuaZip::convertCaseSensitivity(caseSensitivity) ==
355  srt |= QDir::IgnoreCase;
356  QuaZipDirComparator lessThan(srt);
357  // qSort(list.begin(), list.end(), lessThan);
358  std::sort(list.begin(), list.end(), lessThan);
359  }
361  return true;
362 }
363 
365 
366 QList<QuaZipFileInfo> QuaZipDir::entryInfoList(const QStringList &nameFilters,
367  QDir::Filters filters,
368  QDir::SortFlags sort) const {
369  QList<QuaZipFileInfo> result;
370  if (d->entryInfoList(nameFilters, filters, sort, result))
371  return result;
372  else
373  return QList<QuaZipFileInfo>();
374 }
375 
376 QList<QuaZipFileInfo> QuaZipDir::entryInfoList(QDir::Filters filters,
377  QDir::SortFlags sort) const {
378  return entryInfoList(QStringList(), filters, sort);
379 }
380 
381 QList<QuaZipFileInfo64> QuaZipDir::entryInfoList64(
382  const QStringList &nameFilters,
383  QDir::Filters filters,
384  QDir::SortFlags sort) const {
385  QList<QuaZipFileInfo64> result;
386  if (d->entryInfoList(nameFilters, filters, sort, result))
387  return result;
388  else
389  return QList<QuaZipFileInfo64>();
390 }
391 
392 QList<QuaZipFileInfo64> QuaZipDir::entryInfoList64(QDir::Filters filters,
393  QDir::SortFlags sort) const {
394  return entryInfoList64(QStringList(), filters, sort);
395 }
396 
397 QStringList QuaZipDir::entryList(const QStringList &nameFilters,
398  QDir::Filters filters,
399  QDir::SortFlags sort) const {
400  QStringList result;
401  if (d->entryInfoList(nameFilters, filters, sort, result))
402  return result;
403  else
404  return QStringList();
405 }
406 
407 QStringList QuaZipDir::entryList(QDir::Filters filters,
408  QDir::SortFlags sort) const {
409  return entryList(QStringList(), filters, sort);
410 }
411 
412 bool QuaZipDir::exists(const QString &filePath) const {
413  if (filePath == "/" || filePath.isEmpty()) return true;
414  QString fileName = filePath;
415  if (fileName.endsWith('/')) fileName.chop(1);
416  if (fileName.contains('/')) {
417  QFileInfo fileInfo(fileName);
418 #ifdef QUAZIP_QUAZIPDIR_DEBUG
419  qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, "
420  "fileInfo.path()=%s",
421  fileName.toUtf8().constData(),
422  fileInfo.fileName().toUtf8().constData(),
423  fileInfo.path().toUtf8().constData());
424 #endif
425  QuaZipDir dir(*this);
426  return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName());
427  } else {
428  if (fileName == "..") {
429  return !isRoot();
430  } else if (fileName == ".") {
431  return true;
432  } else {
433  QStringList entries = entryList(QDir::AllEntries, QDir::NoSort);
434 #ifdef QUAZIP_QUAZIPDIR_DEBUG
435  qDebug("QuaZipDir::exists(): looking for %s",
436  fileName.toUtf8().constData());
437  for (QStringList::const_iterator i = entries.constBegin();
438  i != entries.constEnd(); ++i) {
439  qDebug("QuaZipDir::exists(): entry: %s",
440  i->toUtf8().constData());
441  }
442 #endif
443  Qt::CaseSensitivity cs =
444  QuaZip::convertCaseSensitivity(d->caseSensitivity);
445  if (filePath.endsWith('/')) {
446  return entries.contains(filePath, cs);
447  } else {
448  return entries.contains(fileName, cs) ||
449  entries.contains(fileName + "/", cs);
450  }
451  }
452  }
453 }
454 
455 bool QuaZipDir::exists() const { return QuaZipDir(d->zip).exists(d->dir); }
456 
457 QString QuaZipDir::filePath(const QString &fileName) const {
458  return QDir(d->dir).filePath(fileName);
459 }
460 
461 QDir::Filters QuaZipDir::filter() { return d->filter; }
462 
463 bool QuaZipDir::isRoot() const { return d->simplePath().isEmpty(); }
464 
465 QStringList QuaZipDir::nameFilters() const { return d->nameFilters; }
466 
467 QString QuaZipDir::path() const { return d->dir; }
468 
469 QString QuaZipDir::relativeFilePath(const QString &fileName) const {
470  return QDir("/" + d->dir).relativeFilePath(fileName);
471 }
472 
474  d->caseSensitivity = caseSensitivity;
475 }
476 
477 void QuaZipDir::setFilter(QDir::Filters filters) { d->filter = filters; }
478 
479 void QuaZipDir::setNameFilters(const QStringList &nameFilters) {
480  d->nameFilters = nameFilters;
481 }
482 
483 void QuaZipDir::setPath(const QString &path) {
484  QString newDir = path;
485  if (newDir == "/") {
486  d->dir = "";
487  } else {
488  if (newDir.endsWith('/')) newDir.chop(1);
489  if (newDir.startsWith('/')) newDir = newDir.mid(1);
490  d->dir = newDir;
491  }
492 }
493 
494 void QuaZipDir::setSorting(QDir::SortFlags sort) { d->sorting = sort; }
495 
496 QDir::SortFlags QuaZipDir::sorting() const { return d->sorting; }
std::string name
double Time(void)
Definition: MyTime.h:38
core::Tensor result
Definition: VtkUtils.cpp:76
Provides ZIP archive navigation.
Definition: quazipdir.h:55
QuaZip::CaseSensitivity caseSensitivity() const
Returns the current case sensitivity mode.
Definition: quazipdir.cpp:81
QString dirName() const
Returns the current directory name.
Definition: quazipdir.cpp:146
QStringList entryList(const QStringList &nameFilters, QDir::Filters filters=QDir::NoFilter, QDir::SortFlags sort=QDir::NoSort) const
Returns the list of the entry names in the directory.
Definition: quazipdir.cpp:397
bool operator==(const QuaZipDir &that)
The assignment operator.
Definition: quazipdir.cpp:70
bool cdUp()
Goes up.
Definition: quazipdir.cpp:142
QuaZipDir(const QuaZipDir &that)
The copy constructor.
Definition: quazipdir.cpp:61
void setFilter(QDir::Filters filters)
Sets the default filter.
Definition: quazipdir.cpp:477
uint count() const
Returns the number of entries in the directory.
Definition: quazipdir.cpp:144
QString relativeFilePath(const QString &fileName) const
Returns the path to the specified file relative to the current dir.
Definition: quazipdir.cpp:469
QuaZipDir & operator=(const QuaZipDir &that)
operator==
Definition: quazipdir.cpp:74
QString operator[](int pos) const
Returns the name of the entry at the specified position.
Definition: quazipdir.cpp:79
bool cd(const QString &dirName)
Changes the 'current' directory.
Definition: quazipdir.cpp:85
void setNameFilters(const QStringList &nameFilters)
Sets the default name filter.
Definition: quazipdir.cpp:479
QDir::Filters filter()
Returns the default filter.
Definition: quazipdir.cpp:461
bool isRoot() const
Returns if the QuaZipDir points to the root of the archive.
Definition: quazipdir.cpp:463
void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity)
Sets the default case sensitivity mode.
Definition: quazipdir.cpp:473
QStringList nameFilters() const
Return the default name filter.
Definition: quazipdir.cpp:465
QList< QuaZipFileInfo64 > entryInfoList64(const QStringList &nameFilters, QDir::Filters filters=QDir::NoFilter, QDir::SortFlags sort=QDir::NoSort) const
Returns the list of the entries in the directory with zip64 support.
Definition: quazipdir.cpp:381
QDir::SortFlags sorting() const
Returns the default sorting mode.
Definition: quazipdir.cpp:496
void setSorting(QDir::SortFlags sort)
Sets the default sorting mode.
Definition: quazipdir.cpp:494
QString path() const
Returns the path to the current dir.
Definition: quazipdir.cpp:467
bool exists(const QString &fileName) const
Returns true if the entry with the specified name exists.
Definition: quazipdir.cpp:412
void setPath(const QString &path)
Goes to the specified path.
Definition: quazipdir.cpp:483
~QuaZipDir()
Destructor.
Definition: quazipdir.cpp:68
QList< QuaZipFileInfo > entryInfoList(const QStringList &nameFilters, QDir::Filters filters=QDir::NoFilter, QDir::SortFlags sort=QDir::NoSort) const
Returns the list of the entries in the directory.
Definition: quazipdir.cpp:366
QString filePath(const QString &fileName) const
Returns the full path to the specified file.
Definition: quazipdir.cpp:457
bool exists() const
Return true if the directory pointed by this QuaZipDir exists.
Definition: quazipdir.cpp:455
ZIP archive.
Definition: quazip.h:128
static Qt::CaseSensitivity convertCaseSensitivity(CaseSensitivity cs)
Returns the actual case sensitivity for the specified QuaZIP one.
Definition: quazip.cpp:689
CaseSensitivity
Case sensitivity for the file names.
Definition: quazip.h:159
bool setCurrentFile(const QString &fileName, CaseSensitivity cs=csDefault)
Sets current file by its name.
Definition: quazip.cpp:398
bool getCurrentFileInfo(QuaZipFileInfo *info) const
Retrieves information about the current file.
Definition: quazip.cpp:477
unsigned int uint
Definition: cutil_math.h:28
constexpr QRegularExpression::PatternOption CaseInsensitive
Definition: QtCompat.h:174
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
static const std::string path
Definition: PointCloud.cpp:59
static void QuaZipDir_convertInfoList(const QList< QuaZipFileInfo64 > &from, QList< QuaZipFileInfo64 > &to)
Definition: quazipdir.cpp:171
QuaZipFileInfo64 QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, const QString &relativeName, bool isReal)
Definition: quazipdir.cpp:148
Information about a file inside archive (with zip64 support).
quint16 versionNeeded
Version needed to extract.
QString name
File name.
quint32 externalAttr
External file attributes.
quint16 method
Compression method.
QDateTime dateTime
Last modification date and time.
quint64 uncompressedSize
Uncompressed file size.
quint16 flags
General purpose flags.
quint16 versionCreated
Version created by.
quint16 diskNumberStart
Disk number start.
quint64 compressedSize
Compressed file size.
quint16 internalAttr
Internal file attributes.
Information about a file inside archive.
#define UNZ_OK
Definition: unzip.h:83