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