source: s10k/CommonLibs/quazip-0.7.2/quazip/quazipdir.cpp @ 1096

Last change on this file since 1096 was 1096, checked in by s10k, 22 months ago

Added zlib, quazip, basicxmlsyntaxhighlighter, conditionalsemaphore and linenumberdisplay libraries. zlib and quazip are pre-compiled, but you can compile them yourself, just delete the dll files (or equivalent binary files to your OS)

File size: 16.5 KB
Line 
1/*
2Copyright (C) 2005-2014 Sergey A. Tachenov
3
4This file is part of QuaZIP.
5
6QuaZIP is free software: you can redistribute it and/or modify
7it under the terms of the GNU Lesser General Public License as published by
8the Free Software Foundation, either version 2.1 of the License, or
9(at your option) any later version.
10
11QuaZIP is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU Lesser General Public License for more details.
15
16You should have received a copy of the GNU Lesser General Public License
17along with QuaZIP.  If not, see <http://www.gnu.org/licenses/>.
18
19See COPYING file for the full LGPL text.
20
21Original ZIP package is copyrighted by Gilles Vollant and contributors,
22see 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/// \cond internal
31class QuaZipDirPrivate: public QSharedData {
32    friend class QuaZipDir;
33private:
34    QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()):
35        zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault),
36        filter(QDir::NoFilter), sorting(QDir::NoSort) {}
37    QuaZip *zip;
38    QString dir;
39    QuaZip::CaseSensitivity caseSensitivity;
40    QDir::Filters filter;
41    QStringList nameFilters;
42    QDir::SortFlags sorting;
43    template<typename TFileInfoList>
44    bool entryInfoList(QStringList nameFilters, QDir::Filters filter,
45        QDir::SortFlags sort, TFileInfoList &result) const;
46    inline QString simplePath() const {return QDir::cleanPath(dir);}
47};
48/// \endcond
49
50QuaZipDir::QuaZipDir(const QuaZipDir &that):
51    d(that.d)
52{
53}
54
55QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir):
56    d(new QuaZipDirPrivate(zip, dir))
57{
58    if (d->dir.startsWith('/'))
59        d->dir = d->dir.mid(1);
60}
61
62QuaZipDir::~QuaZipDir()
63{
64}
65
66bool QuaZipDir::operator==(const QuaZipDir &that)
67{
68    return d->zip == that.d->zip && d->dir == that.d->dir;
69}
70
71QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that)
72{
73    this->d = that.d;
74    return *this;
75}
76
77QString QuaZipDir::operator[](int pos) const
78{
79    return entryList().at(pos);
80}
81
82QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const
83{
84    return d->caseSensitivity;
85}
86
87bool QuaZipDir::cd(const QString &directoryName)
88{
89    if (directoryName == "/") {
90        d->dir = "";
91        return true;
92    }
93    QString dirName = directoryName;
94    if (dirName.endsWith('/'))
95        dirName.chop(1);
96    if (dirName.contains('/')) {
97        QuaZipDir dir(*this);
98        if (dirName.startsWith('/')) {
99#ifdef QUAZIP_QUAZIPDIR_DEBUG
100            qDebug("QuaZipDir::cd(%s): going to /",
101                    dirName.toUtf8().constData());
102#endif
103            if (!dir.cd("/"))
104                return false;
105        }
106        QStringList path = dirName.split('/', QString::SkipEmptyParts);
107        for (QStringList::const_iterator i = path.constBegin();
108                i != path.end();
109                ++i) {
110            const QString &step = *i;
111#ifdef QUAZIP_QUAZIPDIR_DEBUG
112            qDebug("QuaZipDir::cd(%s): going to %s",
113                    dirName.toUtf8().constData(),
114                    step.toUtf8().constData());
115#endif
116            if (!dir.cd(step))
117                return false;
118        }
119        d->dir = dir.path();
120        return true;
121    } else { // no '/'
122        if (dirName == ".") {
123            return true;
124        } else if (dirName == "..") {
125            if (isRoot()) {
126                return false;
127            } else {
128                int slashPos = d->dir.lastIndexOf('/');
129                if (slashPos == -1) {
130                    d->dir = "";
131                } else {
132                    d->dir = d->dir.left(slashPos);
133                }
134                return true;
135            }
136        } else { // a simple subdirectory
137            if (exists(dirName)) {
138                if (isRoot())
139                    d->dir = dirName;
140                else
141                    d->dir += "/" + dirName;
142                return true;
143            } else {
144                return false;
145            }
146        }
147    }
148}
149
150bool QuaZipDir::cdUp()
151{
152    return cd("..");
153}
154
155uint QuaZipDir::count() const
156{
157    return entryList().count();
158}
159
160QString QuaZipDir::dirName() const
161{
162    return QDir(d->dir).dirName();
163}
164
165QuaZipFileInfo64 QuaZipDir_getFileInfo(QuaZip *zip, bool *ok,
166                                  const QString &relativeName,
167                                  bool isReal)
168{
169    QuaZipFileInfo64 info;
170    if (isReal) {
171        *ok = zip->getCurrentFileInfo(&info);
172    } else {
173        *ok = true;
174        info.compressedSize = 0;
175        info.crc = 0;
176        info.diskNumberStart = 0;
177        info.externalAttr = 0;
178        info.flags = 0;
179        info.internalAttr = 0;
180        info.method = 0;
181        info.uncompressedSize = 0;
182        info.versionCreated = info.versionNeeded = 0;
183    }
184    info.name = relativeName;
185    return info;
186}
187
188static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
189                                      QList<QuaZipFileInfo64> &to)
190{
191    to = from;
192}
193
194static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
195                                      QStringList &to)
196{
197    to.clear();
198    for (QList<QuaZipFileInfo64>::const_iterator i = from.constBegin();
199            i != from.constEnd();
200            ++i) {
201        to.append(i->name);
202    }
203}
204
205static void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo64> &from,
206                                      QList<QuaZipFileInfo> &to)
207{
208    to.clear();
209    for (QList<QuaZipFileInfo64>::const_iterator i = from.constBegin();
210            i != from.constEnd();
211            ++i) {
212        QuaZipFileInfo info32;
213        i->toQuaZipFileInfo(info32);
214        to.append(info32);
215    }
216}
217
218/// \cond internal
219/**
220  An utility class to restore the current file.
221  */
222class QuaZipDirRestoreCurrent {
223public:
224    inline QuaZipDirRestoreCurrent(QuaZip *zip):
225        zip(zip), currentFile(zip->getCurrentFileName()) {}
226    inline ~QuaZipDirRestoreCurrent()
227    {
228        zip->setCurrentFile(currentFile);
229    }
230private:
231    QuaZip *zip;
232    QString currentFile;
233};
234/// \endcond
235
236/// \cond internal
237class QuaZipDirComparator
238{
239    private:
240        QDir::SortFlags sort;
241        static QString getExtension(const QString &name);
242        int compareStrings(const QString &string1, const QString &string2);
243    public:
244        inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {}
245        bool operator()(const QuaZipFileInfo64 &info1, const QuaZipFileInfo64 &info2);
246};
247
248QString QuaZipDirComparator::getExtension(const QString &name)
249{
250    if (name.endsWith('.') || name.indexOf('.', 1) == -1) {
251        return "";
252    } else {
253        return name.mid(name.lastIndexOf('.') + 1);
254    }
255
256}
257
258int QuaZipDirComparator::compareStrings(const QString &string1,
259        const QString &string2)
260{
261    if (sort & QDir::LocaleAware) {
262        if (sort & QDir::IgnoreCase) {
263            return string1.toLower().localeAwareCompare(string2.toLower());
264        } else {
265            return string1.localeAwareCompare(string2);
266        }
267    } else {
268        return string1.compare(string2, (sort & QDir::IgnoreCase)
269                ? Qt::CaseInsensitive : Qt::CaseSensitive);
270    }
271}
272
273bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1,
274        const QuaZipFileInfo64 &info2)
275{
276    QDir::SortFlags order = sort
277        & (QDir::Name | QDir::Time | QDir::Size | QDir::Type);
278    if ((sort & QDir::DirsFirst) == QDir::DirsFirst
279            || (sort & QDir::DirsLast) == QDir::DirsLast) {
280        if (info1.name.endsWith('/') && !info2.name.endsWith('/'))
281            return (sort & QDir::DirsFirst) == QDir::DirsFirst;
282        else if (!info1.name.endsWith('/') && info2.name.endsWith('/'))
283            return (sort & QDir::DirsLast) == QDir::DirsLast;
284    }
285    bool result;
286    int extDiff;
287    switch (order) {
288        case QDir::Name:
289            result = compareStrings(info1.name, info2.name) < 0;
290            break;
291        case QDir::Type:
292            extDiff = compareStrings(getExtension(info1.name),
293                    getExtension(info2.name));
294            if (extDiff == 0) {
295                result = compareStrings(info1.name, info2.name) < 0;
296            } else {
297                result = extDiff < 0;
298            }
299            break;
300        case QDir::Size:
301            if (info1.uncompressedSize == info2.uncompressedSize) {
302                result = compareStrings(info1.name, info2.name) < 0;
303            } else {
304                result = info1.uncompressedSize < info2.uncompressedSize;
305            }
306            break;
307        case QDir::Time:
308            if (info1.dateTime == info2.dateTime) {
309                result = compareStrings(info1.name, info2.name) < 0;
310            } else {
311                result = info1.dateTime < info2.dateTime;
312            }
313            break;
314        default:
315            qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X",
316                    static_cast<unsigned>(sort));
317            return false;
318    }
319    return (sort & QDir::Reversed) ? !result : result;
320}
321
322template<typename TFileInfoList>
323bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, 
324    QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const
325{
326    QString basePath = simplePath();
327    if (!basePath.isEmpty())
328        basePath += "/";
329    int baseLength = basePath.length();
330    result.clear();
331    QuaZipDirRestoreCurrent saveCurrent(zip);
332    if (!zip->goToFirstFile()) {
333        return zip->getZipError() == UNZ_OK;
334    }
335    QDir::Filters fltr = filter;
336    if (fltr == QDir::NoFilter)
337        fltr = this->filter;
338    if (fltr == QDir::NoFilter)
339        fltr = QDir::AllEntries;
340    QStringList nmfltr = nameFilters;
341    if (nmfltr.isEmpty())
342        nmfltr = this->nameFilters;
343    QSet<QString> dirsFound;
344    QList<QuaZipFileInfo64> list;
345    do {
346        QString name = zip->getCurrentFileName();
347        if (!name.startsWith(basePath))
348            continue;
349        QString relativeName = name.mid(baseLength);
350        if (relativeName.isEmpty())
351            continue;
352        bool isDir = false;
353        bool isReal = true;
354        if (relativeName.contains('/')) {
355            int indexOfSlash = relativeName.indexOf('/');
356            // something like "subdir/"
357            isReal = indexOfSlash == relativeName.length() - 1;
358            relativeName = relativeName.left(indexOfSlash + 1);
359            if (dirsFound.contains(relativeName))
360                continue;
361            isDir = true;
362        }
363        dirsFound.insert(relativeName);
364        if ((fltr & QDir::Dirs) == 0 && isDir)
365            continue;
366        if ((fltr & QDir::Files) == 0 && !isDir)
367            continue;
368        if (!nmfltr.isEmpty() && !QDir::match(nmfltr, relativeName))
369            continue;
370        bool ok;
371        QuaZipFileInfo64 info = QuaZipDir_getFileInfo(zip, &ok, relativeName,
372            isReal);
373        if (!ok) {
374            return false;
375        }
376        list.append(info);
377    } while (zip->goToNextFile());
378    QDir::SortFlags srt = sort;
379    if (srt == QDir::NoSort)
380        srt = sorting;
381#ifdef QUAZIP_QUAZIPDIR_DEBUG
382    qDebug("QuaZipDirPrivate::entryInfoList(): before sort:");
383    foreach (QuaZipFileInfo64 info, list) {
384        qDebug("%s\t%s", info.name.toUtf8().constData(),
385                info.dateTime.toString(Qt::ISODate).toUtf8().constData());
386    }
387#endif
388    if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) {
389        if (QuaZip::convertCaseSensitivity(caseSensitivity)
390                == Qt::CaseInsensitive)
391            srt |= QDir::IgnoreCase;
392        QuaZipDirComparator lessThan(srt);
393        qSort(list.begin(), list.end(), lessThan);
394    }
395    QuaZipDir_convertInfoList(list, result);
396    return true;
397}
398
399/// \endcond
400
401QList<QuaZipFileInfo> QuaZipDir::entryInfoList(const QStringList &nameFilters,
402    QDir::Filters filters, QDir::SortFlags sort) const
403{
404    QList<QuaZipFileInfo> result;
405    if (d->entryInfoList(nameFilters, filters, sort, result))
406        return result;
407    else
408        return QList<QuaZipFileInfo>();
409}
410
411QList<QuaZipFileInfo> QuaZipDir::entryInfoList(QDir::Filters filters,
412    QDir::SortFlags sort) const
413{
414    return entryInfoList(QStringList(), filters, sort);
415}
416
417QList<QuaZipFileInfo64> QuaZipDir::entryInfoList64(const QStringList &nameFilters,
418    QDir::Filters filters, QDir::SortFlags sort) const
419{
420    QList<QuaZipFileInfo64> result;
421    if (d->entryInfoList(nameFilters, filters, sort, result))
422        return result;
423    else
424        return QList<QuaZipFileInfo64>();
425}
426
427QList<QuaZipFileInfo64> QuaZipDir::entryInfoList64(QDir::Filters filters,
428    QDir::SortFlags sort) const
429{
430    return entryInfoList64(QStringList(), filters, sort);
431}
432
433QStringList QuaZipDir::entryList(const QStringList &nameFilters,
434    QDir::Filters filters, QDir::SortFlags sort) const
435{
436    QStringList result;
437    if (d->entryInfoList(nameFilters, filters, sort, result))
438        return result;
439    else
440        return QStringList();
441}
442
443QStringList QuaZipDir::entryList(QDir::Filters filters,
444    QDir::SortFlags sort) const
445{
446    return entryList(QStringList(), filters, sort);
447}
448
449bool QuaZipDir::exists(const QString &filePath) const
450{
451    if (filePath == "/" || filePath.isEmpty())
452        return true;
453    QString fileName = filePath;
454    if (fileName.endsWith('/'))
455        fileName.chop(1);
456    if (fileName.contains('/')) {
457        QFileInfo fileInfo(fileName);
458#ifdef QUAZIP_QUAZIPDIR_DEBUG
459        qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, "
460                "fileInfo.path()=%s", fileName.toUtf8().constData(),
461                fileInfo.fileName().toUtf8().constData(),
462                fileInfo.path().toUtf8().constData());
463#endif
464        QuaZipDir dir(*this);
465        return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName());
466    } else {
467        if (fileName == "..") {
468            return !isRoot();
469        } else if (fileName == ".") {
470            return true;
471        } else {
472            QStringList entries = entryList(QDir::AllEntries, QDir::NoSort);
473#ifdef QUAZIP_QUAZIPDIR_DEBUG
474            qDebug("QuaZipDir::exists(): looking for %s",
475                    fileName.toUtf8().constData());
476            for (QStringList::const_iterator i = entries.constBegin();
477                    i != entries.constEnd();
478                    ++i) {
479                qDebug("QuaZipDir::exists(): entry: %s",
480                        i->toUtf8().constData());
481            }
482#endif
483            Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity(
484                    d->caseSensitivity);
485            if (filePath.endsWith('/')) {
486                return entries.contains(filePath, cs);
487            } else {
488                return entries.contains(fileName, cs)
489                    || entries.contains(fileName + "/", cs);
490            }
491        }
492    }
493}
494
495bool QuaZipDir::exists() const
496{
497    return QuaZipDir(d->zip).exists(d->dir);
498}
499
500QString QuaZipDir::filePath(const QString &fileName) const
501{
502    return QDir(d->dir).filePath(fileName);
503}
504
505QDir::Filters QuaZipDir::filter()
506{
507    return d->filter;
508}
509
510bool QuaZipDir::isRoot() const
511{
512    return d->simplePath().isEmpty();
513}
514
515QStringList QuaZipDir::nameFilters() const
516{
517    return d->nameFilters;
518}
519
520QString QuaZipDir::path() const
521{
522    return d->dir;
523}
524
525QString QuaZipDir::relativeFilePath(const QString &fileName) const
526{
527    return QDir("/" + d->dir).relativeFilePath(fileName);
528}
529
530void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity)
531{
532    d->caseSensitivity = caseSensitivity;
533}
534
535void QuaZipDir::setFilter(QDir::Filters filters)
536{
537    d->filter = filters;
538}
539
540void QuaZipDir::setNameFilters(const QStringList &nameFilters)
541{
542    d->nameFilters = nameFilters;
543}
544
545void QuaZipDir::setPath(const QString &path)
546{
547    QString newDir = path;
548    if (newDir == "/") {
549        d->dir = "";
550    } else {
551        if (newDir.endsWith('/'))
552            newDir.chop(1);
553        if (newDir.startsWith('/'))
554            newDir = newDir.mid(1);
555        d->dir = newDir;
556    }
557}
558
559void QuaZipDir::setSorting(QDir::SortFlags sort)
560{
561    d->sorting = sort;
562}
563
564QDir::SortFlags QuaZipDir::sorting() const
565{
566    return d->sorting;
567}
Note: See TracBrowser for help on using the repository browser.