File indexing completed on 2025-01-26 04:14:57
0001 /* 0002 * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) version 3, or any 0008 * later version accepted by the membership of KDE e.V. (or its 0009 * successor approved by the membership of KDE e.V.), which shall 0010 * act as a proxy defined in Section 6 of version 3 of the license. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Lesser General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Lesser General Public 0018 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 0019 * 0020 */ 0021 0022 #include "KRar.h" 0023 #include "KRarFileEntry.h" 0024 0025 #include <QtCore/QDir> 0026 #include <QtCore/QFile> 0027 #include <QtCore/QIODevice> 0028 #include <QDebug> 0029 0030 extern "C" 0031 { 0032 #include <unarr.h> 0033 } 0034 0035 class KRar::Private { 0036 public: 0037 Private() 0038 : archive(nullptr) 0039 , stream(nullptr) 0040 {} 0041 ar_archive* archive; 0042 ar_stream* stream; 0043 QList<KRarFileEntry*> files; 0044 }; 0045 0046 KRar::KRar(const QString& filename) 0047 : KArchive(filename) 0048 , d(new Private) 0049 { 0050 } 0051 0052 KRar::KRar(QIODevice* dev) 0053 : KArchive(dev) 0054 , d(new Private) 0055 { 0056 } 0057 0058 KRar::~KRar() 0059 { 0060 if (isOpen()) { 0061 close(); 0062 } 0063 delete d; 0064 } 0065 0066 bool KRar::doPrepareWriting(const QString& /*name*/, const QString& /*user*/, const QString& /*group*/, qint64 /*size*/, mode_t /*perm*/, const QDateTime& /*atime*/, const QDateTime& /*mtime*/, const QDateTime& /*ctime*/) 0067 { 0068 return false; 0069 } 0070 0071 bool KRar::doFinishWriting(qint64 /*size*/) 0072 { 0073 return false; 0074 } 0075 0076 bool KRar::doWriteDir(const QString& /*name*/, const QString& /*user*/, const QString& /*group*/, mode_t /*perm*/, const QDateTime& /*atime*/, const QDateTime& /*mtime*/, const QDateTime& /*ctime*/) 0077 { 0078 return false; 0079 } 0080 0081 bool KRar::doWriteSymLink(const QString& /*name*/, const QString& /*target*/, const QString& /*user*/, const QString& /*group*/, mode_t /*perm*/, const QDateTime& /*atime*/, const QDateTime& /*mtime*/, const QDateTime& /*ctime*/) 0082 { 0083 return false; 0084 } 0085 0086 bool KRar::openArchive(QIODevice::OpenMode mode) 0087 { 0088 // First clear the file list, because we don't like leftovers 0089 if(d->archive) 0090 { 0091 closeArchive(); 0092 } 0093 // Open archive 0094 0095 if (mode == QIODevice::WriteOnly) { 0096 return true; 0097 } 0098 if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) { 0099 //qWarning() << "Unsupported mode " << mode; 0100 return false; 0101 } 0102 0103 QIODevice *dev = device(); 0104 if (!dev) { 0105 return false; 0106 } 0107 0108 d->stream = ar_open_file(fileName().toLocal8Bit()); 0109 if (!d->stream) 0110 { 0111 qDebug() << "Failed to open" << fileName() << "into a stream for unarr"; 0112 return false; 0113 } 0114 0115 d->archive = ar_open_rar_archive(d->stream); 0116 if (!d->archive) 0117 { 0118 qDebug() << "Failed to open" << fileName() << "as a rar archive. Are we sure this is a rar archive?"; 0119 return false; 0120 } 0121 0122 // Iterate through all entries and get a KRarFileEntry out of them 0123 while (ar_parse_entry(d->archive)) { 0124 QString pathname(ar_entry_get_name(d->archive)); 0125 int splitPos = pathname.lastIndexOf("/"); 0126 QString path = pathname.left(splitPos); 0127 QString name = pathname.mid(splitPos + 1); 0128 QDateTime mtime = QDateTime::fromTime_t(ar_entry_get_filetime(d->archive)); 0129 quint64 start = ar_entry_get_offset(d->archive); 0130 quint64 size = ar_entry_get_size(d->archive); 0131 // So, funny thing - unarr ignores directory entries in rar files entirely (see unarr/rar/rar.c:65) 0132 // Leaving the code in, in case we feel like reintroducing this at a later point in time 0133 // bool isDir = size < 1;//archive_entry_filetype(entry) == AE_IFDIR; 0134 0135 KArchiveEntry* kaentry = nullptr; 0136 // if(isDir) 0137 // { 0138 // QString path = QDir::cleanPath(pathname); 0139 // const KArchiveEntry *ent = rootDir()->entry(path); 0140 // if (ent && ent->isDirectory()) { 0141 // qDebug() << "Directory already exists, NOT going to add it again"; 0142 // kaentry = 0; 0143 // } else { 0144 // kaentry = new KArchiveDirectory(this, name, 0755, mtime, rootDir()->user(), rootDir()->group(), QString()); 0145 // qDebug() << "KArchiveDirectory created, name=" << name; 0146 // } 0147 // } 0148 // else 0149 // { 0150 KRarFileEntry* fileEntry = new KRarFileEntry(this, name, 0100644, mtime, rootDir()->user(), rootDir()->group(), "", path, start, size, d->archive); 0151 kaentry = fileEntry; 0152 d->files.append(fileEntry); 0153 // } 0154 0155 if(kaentry) 0156 { 0157 if(splitPos > 0) 0158 { 0159 // Ensure container directory exists, create otherwise 0160 KArchiveDirectory *tdir = findOrCreate(path); 0161 tdir->addEntry(kaentry); 0162 } 0163 else 0164 { 0165 rootDir()->addEntry(kaentry); 0166 } 0167 } 0168 } 0169 0170 return true; 0171 } 0172 0173 bool KRar::closeArchive() 0174 { 0175 ar_close_archive(d->archive); 0176 ar_close(d->stream); 0177 d->archive = nullptr; 0178 d->stream = nullptr; 0179 qDeleteAll(d->files); 0180 d->files.clear(); 0181 return true; 0182 } 0183 0184 void KRar::virtual_hook(int id, void* data) 0185 { 0186 KArchive::virtual_hook(id, data); 0187 }