File indexing completed on 2024-11-24 04:18:34

0001 #include "compressedfile.h"
0002 
0003 #include <KArchive/KTar>
0004 #include <KArchive/KZip>
0005 #include <KArchive/kcompressiondevice.h>
0006 #include <KArchive/kfilterdev.h>
0007 
0008 #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID
0009 #include <KArchive/k7zip.h>
0010 #endif
0011 
0012 #include <KArchive/kar.h>
0013 
0014 #include <QDirIterator>
0015 #include <QDebug>
0016 
0017 #include <MauiKit3/FileBrowsing/fmstatic.h>
0018 
0019 #include "temporaryfile.h"
0020 
0021 
0022 CompressedFile::CompressedFile(QObject *parent)
0023     : QObject(parent)
0024     , m_model(new CompressedFileModel(this))
0025 {
0026 }
0027 
0028 CompressedFileModel::CompressedFileModel(QObject *parent)
0029     : MauiList(parent)
0030     ,m_archive(nullptr)
0031 {
0032 }
0033 
0034 CompressedFileModel::~CompressedFileModel()
0035 {
0036     qDeleteAll(m_previews);
0037 }
0038 
0039 const FMH::MODEL_LIST &CompressedFileModel::items() const
0040 {
0041     return m_list;
0042 }
0043 
0044 void CompressedFileModel::setUrl(const QUrl &url)
0045 {
0046     if(m_url == url)
0047     {
0048         return;
0049     }
0050 
0051     m_url = url;
0052 
0053     m_fileName = QFileInfo(url.toLocalFile()).baseName();
0054     Q_EMIT fileNameChanged(m_fileName);
0055 
0056     open();
0057     openDir(m_currentPath);
0058 }
0059 
0060 QString CompressedFileModel::currentPath() const
0061 {
0062     return m_currentPath;
0063 }
0064 
0065 QString CompressedFileModel::fileName() const
0066 {
0067     return m_fileName;
0068 }
0069 
0070 bool CompressedFileModel::canGoUp() const
0071 {
0072     return m_canGoUp;
0073 }
0074 
0075 bool CompressedFileModel::opened() const
0076 {
0077     return m_opened;
0078 }
0079 
0080 void CompressedFileModel::refresh()
0081 {
0082     openDir(m_currentPath);
0083 }
0084 
0085 const KArchiveFile *CompressedFileModel::getFile(const QString &path)
0086 {
0087     if(!m_archive)
0088     {
0089         return nullptr;
0090     }
0091 
0092     if(m_archive->isOpen())
0093     {
0094         return m_archive->directory()->file(path);
0095     }
0096 
0097     return nullptr;
0098 }
0099 
0100 void CompressedFileModel::openDir(const QString &path)
0101 {
0102     if(m_url.isEmpty() || path.isEmpty())
0103     {
0104         return;
0105     }
0106 
0107            //                            if(m_currentPath == path)
0108            //            {
0109            //                            return;
0110            //        }
0111 
0112     if(m_archive->isOpen())
0113     {
0114 
0115         auto root = m_archive->directory();
0116         auto entry = root->entry(path);
0117 
0118         if(entry)
0119         {
0120             if(entry->isDirectory())
0121             {
0122                 const KArchiveDirectory* subDir = static_cast<const KArchiveDirectory*>(entry);
0123                 setCurrentPath(path);
0124 
0125                 m_list.clear();
0126                 Q_EMIT this->preListChanged();
0127 
0128                 for(const auto file : subDir->entries())
0129                 {
0130                     const auto e = subDir->entry(file);
0131                     this->m_list << FMH::MODEL{{FMH::MODEL_KEY::IS_DIR, e->isDirectory() ? "true" : "false"}, {FMH::MODEL_KEY::LABEL, e->name()}, {FMH::MODEL_KEY::ICON, e->isDirectory() ? "folder" : FMStatic::getIconName(e->name())}, {FMH::MODEL_KEY::DATE, e->date().toString()}, {FMH::MODEL_KEY::PATH, QString(path+"%1/").arg(e->name())}, {FMH::MODEL_KEY::USER, e->user()}};
0132 
0133                 }
0134 
0135                 Q_EMIT this->postListChanged();
0136                 Q_EMIT this->countChanged ();
0137             }
0138         }
0139     }
0140 
0141 }
0142 
0143 void CompressedFileModel::goUp()
0144 {
0145     this->openDir(QUrl(m_currentPath).resolved(QUrl("..")).toString());
0146 }
0147 
0148 void CompressedFileModel::goToRoot()
0149 {
0150     this->openDir("/");
0151 }
0152 
0153 void CompressedFileModel::close()
0154 {
0155 
0156 }
0157 
0158 void CompressedFileModel::open()
0159 {
0160     m_archive = CompressedFile::getKArchiveObject(m_url);
0161 
0162     m_archive->open(QIODevice::ReadOnly);
0163 
0164 
0165     assert(m_archive->isOpen() == true);
0166 
0167     m_opened = m_archive->isOpen();
0168     Q_EMIT openedChanged(m_opened);
0169 
0170 }
0171 
0172 QString CompressedFileModel::temporaryFile(const QString &path)
0173 {
0174     if(m_previews.contains(path))
0175     {
0176         return m_previews.value(path)->url();
0177     }
0178 
0179     auto preview = new TemporaryFile;
0180     m_previews.insert(path, preview);
0181 
0182     auto file = getFile(path);
0183     preview->setData(file->data(), file->name());
0184     return preview->url();
0185 
0186 }
0187 
0188 bool CompressedFileModel::addFiles(const QStringList &urls, const QString &path)
0189 {
0190     if(urls.isEmpty() || path.isEmpty())
0191     {
0192         return false;
0193     }
0194 
0195     bool success = false;
0196 
0197 
0198     m_archive->close();
0199     m_archive->open(QIODevice::ReadWrite);
0200 
0201 
0202     for(const auto &url : urls)
0203     {
0204         success = addFile(url, path);
0205     }
0206 
0207     m_archive->close();
0208     m_archive->open(QIODevice::ReadOnly);
0209     refresh();
0210 
0211     return success;
0212 }
0213 
0214 bool CompressedFileModel::addFile(const QString &url, const QString &path)
0215 {
0216 
0217 
0218     auto localUrl = QUrl(url).toLocalFile();
0219     QFileInfo file(localUrl);
0220 
0221     if(!file.exists())
0222     {
0223         return false;
0224     }
0225 
0226     if(file.isDir())
0227     {
0228         return m_archive->addLocalDirectory(localUrl, path+file.fileName());
0229     }
0230 
0231 
0232     if(m_archive->addLocalFile(localUrl, path+file.fileName()))
0233     {
0234         qDebug() << "Trying to insert file to archive"<< url << localUrl << path << path+file.fileName();
0235         return true;
0236 
0237     }
0238 
0239 
0240     return false;
0241 
0242 }
0243 
0244 bool CompressedFileModel::extractFiles(const QStringList &urls, const QString &where)
0245 {
0246     return false;
0247 
0248 }
0249 
0250 bool CompressedFileModel::extractFile(const QString &url, const QString &where)
0251 {
0252     return false;
0253 
0254 }
0255 
0256 void CompressedFileModel::setCurrentPath(QString currentPath)
0257 {
0258     if (m_currentPath == currentPath)
0259         return;
0260 
0261     m_currentPath = currentPath;
0262     Q_EMIT currentPathChanged(m_currentPath);
0263 
0264     m_canGoUp = m_currentPath != "/";
0265     Q_EMIT canGoUpChanged(m_canGoUp);
0266 }
0267 
0268 void CompressedFile::extract(const QUrl &where, const QString &directory)
0269 {
0270     if (!m_url.isLocalFile())
0271         return;
0272 
0273     qDebug() << "@gadominguez File:fm.cpp Funcion: extractFile  "
0274              << "URL: " << m_url << "WHERE: " << where.toString() << " DIR: " << directory;
0275 
0276     QString where_ = where.toLocalFile() + "/" + directory;
0277 
0278     auto kArch = CompressedFile::getKArchiveObject(m_url);
0279     kArch->open(QIODevice::ReadOnly);
0280 
0281     qDebug() << "@gadominguez File:fm.cpp Funcion: extractFile  " << kArch->directory()->entries();
0282 
0283     assert(kArch->isOpen() == true);
0284 
0285     bool ok = false;
0286     if (kArch->isOpen())
0287     {
0288         ok = kArch->directory()->copyTo(where_, true);
0289         kArch->close ();
0290 
0291     }
0292     delete kArch;
0293 
0294     Q_EMIT this->extractionFinished (where.toString(), ok);
0295 }
0296 
0297 /*
0298  *
0299  *  CompressTypeSelected is an integer and has to be acorrding with order in Dialog.qml
0300  *
0301  */
0302 bool CompressedFile::compress(const QStringList &files, const QUrl &where, const QString &fileName, const int &compressTypeSelected)
0303 {
0304     auto fileWriter = [&where](KArchive *archive, QFile &file) -> bool
0305     {
0306         if(!archive)
0307             return false;
0308 
0309         return archive->writeFile(file.fileName().remove(where.toLocalFile(), Qt::CaseSensitivity::CaseSensitive), // Mirror file path in compressed file from current directory
0310                                   file.readAll(),
0311                                   0100775,
0312                                   QFileInfo(file).owner(),
0313                                   QFileInfo(file).group(),
0314                                   QDateTime(),
0315                                   QDateTime(),
0316                                   QDateTime());
0317     };
0318 
0319     auto dirWriter = [&fileWriter](KArchive *archive, QDirIterator &dir, bool &error)
0320     {
0321         if(!archive)
0322             return;
0323 
0324         while (dir.hasNext())
0325         {
0326             auto entrie = dir.next();
0327 
0328             if (QFileInfo(entrie).isFile())
0329             {
0330                 auto file = QFile(entrie);
0331                 file.open(QIODevice::ReadOnly);
0332 
0333                 if (!file.isOpen())
0334                 {
0335                     qDebug() << "ERROR. CURRENT USER DOES NOT HAVE PEMRISSION FOR WRITE IN THE CURRENT DIRECTORY.";
0336                     error = true;
0337                     continue;
0338                 }
0339 
0340                 error = fileWriter(archive, file);
0341 
0342                        // WriteFile returns if the file was written or not,
0343                        // but this function returns if some error occurs so for this reason it is needed to toggle the value
0344                 error = !error;
0345             }
0346         }
0347     };
0348 
0349     auto url = [&where, &fileName](const int &type) -> QString
0350     {
0351         QString format;
0352         switch(type)
0353         {
0354         case 0: format = ".zip"; break;
0355         case 1: format = ".tar"; break;
0356         case 2: format = ".7zip"; break;
0357         case 3: format = ".ar"; break;
0358         }
0359 
0360         return QUrl(where.toString() + "/" + fileName + format).toLocalFile();
0361     };
0362 
0363     auto openCheck = [](KArchive *archive)
0364     {
0365         archive->open(QIODevice::ReadWrite);
0366         assert(archive->isOpen() == true);
0367     };
0368 
0369     bool error = true;
0370     const QString fileUrl = url(compressTypeSelected);
0371 
0372     assert(compressTypeSelected >= 0 && compressTypeSelected <= 8);
0373 
0374     for (const auto &uri : files)
0375     {
0376         qDebug() << "@gadominguez File:fm.cpp Funcion: compress  " << QUrl(uri).toLocalFile() << " " << fileName;
0377 
0378         if (!QFileInfo(QUrl(uri).toLocalFile()).isDir())
0379         {
0380             auto file = QFile(QUrl(uri).toLocalFile());
0381             file.open(QIODevice::ReadWrite);
0382 
0383             if (!file.isOpen())
0384             {
0385                 qDebug() << "ERROR. CURRENT USER DOES NOT HAVE PEMRISSION FOR WRITE IN THE CURRENT DIRECTORY.";
0386                 error = true;
0387                 continue;
0388             }
0389 
0390                 switch (compressTypeSelected)
0391                 {
0392                 case 0: //.ZIP
0393                 {
0394                     auto kzip = new KZip(fileUrl);
0395                     openCheck(kzip);
0396 
0397                     error = fileWriter(kzip, file);
0398 
0399                     (void)kzip->close();
0400                     // WriteFile returns if the file was written or not,
0401                     // but this function returns if some error occurs so for this reason it is needed to toggle the value
0402                     error = !error;
0403                     break;
0404                 }
0405                 case 1: // .TAR
0406                 {
0407                     auto ktar = new KTar(fileUrl);
0408                     openCheck(ktar);
0409 
0410                     error = fileWriter(ktar, file);
0411 
0412                     (void)ktar->close();
0413                     break;
0414                 }
0415                 case 2: //.7ZIP
0416                 {
0417 #ifdef K7ZIP_H
0418 
0419                            // TODO: KArchive no permite comprimir ficheros del mismo modo que con TAR o ZIP. Hay que hacerlo de otra forma y requiere disponer de una libreria actualizada de KArchive.
0420                     auto k7zip = new K7Zip(fileUrl);
0421                     openCheck(k7zip);
0422 
0423                     error = fileWriter(k7zip, file);
0424 
0425                     k7zip->close();
0426                     // WriteFile returns if the file was written or not,
0427                     // but this function returns if some error occurs so for this reason it is needed to toggle the value
0428                     error = !error;
0429 #endif
0430                     break;
0431                 }
0432                 case 3: //.AR
0433                 {
0434                     // TODO: KArchive no permite comprimir ficheros del mismo modo que con TAR o ZIP. Hay que hacerlo de otra forma y requiere disponer de una libreria actualizada de KArchive.
0435                     auto kar = new KAr(fileUrl);
0436                     openCheck(kar);
0437 
0438                     error = fileWriter(kar, file);
0439 
0440                     (void)kar->close();
0441                     // WriteFile returns if the file was written or not,
0442                     // but this function returns if some error occurs so for this reason it is needed to toggle the value
0443                     error = !error;
0444                     break;
0445                 }
0446                 default:
0447                     qDebug() << "ERROR. COMPRESSED TYPE SELECTED NOT COMPATIBLE";
0448                     break;
0449                 }
0450 
0451 
0452         } else
0453         {
0454             qDebug() << "Dir: " << QUrl(uri).toLocalFile();
0455             auto dir = QDirIterator(QUrl(uri).toLocalFile(), QDirIterator::Subdirectories);
0456 
0457             switch (compressTypeSelected)
0458             {
0459             case 0: //.ZIP
0460             {
0461                 auto kzip = new KZip(fileUrl);
0462                 openCheck(kzip);
0463 
0464                 dirWriter(kzip, dir, error);
0465 
0466                 (void)kzip->close();
0467                 break;
0468             }
0469             case 1: // .TAR
0470             {
0471                 auto ktar = new KTar(fileUrl);
0472                 openCheck(ktar);
0473 
0474                 dirWriter(ktar, dir, error);
0475 
0476                 (void)ktar->close();
0477                 break;
0478             }
0479             case 2: //.7ZIP
0480             {
0481 #ifdef K7ZIP_H
0482 
0483                 auto k7zip = new K7Zip(fileUrl);
0484                 openCheck(k7zip);
0485 
0486                 dirWriter(k7zip, dir, error);
0487 
0488                 (void)k7zip->close();
0489 #endif
0490                 break;
0491             }
0492             case 3: //.AR
0493             {
0494                 auto kAr = new KAr(fileUrl);
0495                 openCheck(kAr);
0496 
0497                 dirWriter(kAr, dir, error);
0498 
0499                 (void)kAr->close();
0500                 break;
0501             }
0502             default:
0503                 qDebug() << "ERROR. COMPRESSED TYPE SELECTED NOT COMPATIBLE";
0504                 break;
0505             }
0506         }
0507     }
0508 
0509            // kzip->prepareWriting("Hello00000.txt", "gabridc", "gabridc", 1024, 0100777, QDateTime(), QDateTime(), QDateTime());
0510            // kzip->writeData("Hello", sizeof("Hello"));
0511            // kzip->finishingWriting();
0512 
0513     if(!error)
0514     {
0515         this->setUrl(QUrl::fromLocalFile(fileUrl));
0516     }
0517 
0518     Q_EMIT compressionFinished(fileUrl, !error);
0519     return error;
0520 }
0521 
0522 KArchive *CompressedFile::getKArchiveObject(const QUrl &url)
0523 {
0524     KArchive *kArch = nullptr;
0525 
0526     /*
0527      * This checks depends on type COMPRESSED_MIMETYPES in file fmh.h
0528      */
0529     qDebug() << "@gadominguez File: fmstatic.cpp Func: getKArchiveObject MimeType: " << FMStatic::getMime(url);
0530 
0531     auto mime = FMStatic::getMime(url);
0532 
0533     if (mime.contains("application/x-tar") || mime.contains("application/x-compressed-tar"))
0534     {
0535         kArch = new KTar(url.toLocalFile());
0536     } else if (mime.contains("application/zip"))
0537     {
0538         kArch = new KZip(url.toLocalFile());
0539 
0540     } else if (mime.contains("application/x-7z-compressed"))
0541     {
0542 #ifdef K7ZIP_H
0543         kArch = new K7Zip(url.toLocalFile());
0544 #endif
0545     } else
0546     {
0547         qDebug() << "ERROR. COMPRESSED FILE TYPE UNKOWN " << url.toString();
0548     }
0549 
0550     return kArch;
0551 }
0552 
0553 void CompressedFile::setUrl(const QUrl &url)
0554 {
0555     if (m_url == url)
0556         return;
0557 
0558     m_url = url;
0559     Q_EMIT this->urlChanged();
0560 
0561     if(!FMStatic::fileExists(url))
0562     {
0563         qWarning()<< "File does not exists and can not be opened.";
0564         return;
0565     }
0566 
0567     m_model->setUrl(m_url);
0568 }
0569 
0570 QUrl CompressedFile::url() const
0571 {
0572     return m_url;
0573 }
0574 
0575 CompressedFileModel *CompressedFile::model() const
0576 {
0577     return m_model;
0578 }
0579