File indexing completed on 2024-05-12 16:46:08

0001 /***************************************************************************
0002     Copyright (C) 2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "imagedirectory.h"
0026 #include "image.h"
0027 #include "../core/filehandler.h"
0028 #include "../tellico_debug.h"
0029 
0030 #include <KZip>
0031 
0032 #include <QFile>
0033 #include <QDir>
0034 #include <QUrl>
0035 #include <QTemporaryDir>
0036 
0037 using namespace Tellico;
0038 using Tellico::ImageStorage;
0039 using Tellico::ImageDirectory;
0040 using Tellico::TemporaryImageDirectory;
0041 using Tellico::ImageZipArchive;
0042 
0043 ImageDirectory::ImageDirectory() : ImageStorage(), m_pathExists(false), m_dir(nullptr) {
0044 }
0045 
0046 ImageDirectory::ImageDirectory(const QString& path_) : ImageStorage() , m_dir(nullptr) {
0047   setPath(path_);
0048 }
0049 
0050 ImageDirectory::~ImageDirectory() {
0051   delete m_dir;
0052   m_dir = nullptr;
0053 }
0054 
0055 QString ImageDirectory::path() {
0056   return m_path;
0057 }
0058 
0059 void ImageDirectory::setPath(const QString& path_) {
0060   m_path = path_;
0061   QDir dir(m_path);
0062   m_pathExists = dir.exists();
0063 }
0064 
0065 bool ImageDirectory::hasImage(const QString& id_) {
0066   return m_pathExists && QFile::exists(path() + id_);
0067 }
0068 
0069 Tellico::Data::Image* ImageDirectory::imageById(const QString& id_) {
0070   if(!hasImage(id_)) {
0071     return nullptr;
0072   }
0073 
0074   Data::Image* img = new Data::Image(path() + id_, id_);
0075   if(!img) {
0076     myLog() << "image not found:" << (path() + id_);
0077     return nullptr;
0078   }
0079   if(img->isNull()) {
0080     myLog() << "image found but null:" << (path() + id_);
0081     delete img;
0082     return nullptr;
0083   }
0084   return img;
0085 }
0086 
0087 bool ImageDirectory::writeImage(const Data::Image& img_) {
0088   const QString path = this->path(); // virtual function, so don't assume m_path is correct
0089   if(!m_pathExists) {
0090     if(path.isEmpty()) {
0091       // an empty path means the file hasn't been saved yet
0092       if(!m_dir) {
0093         m_dir = new QTemporaryDir(); // default is to auto-delete, aka autoRemove()
0094         // in KDE4, the way this worked included the final slash.
0095         ImageDirectory::setPath(m_dir->path() + QLatin1Char('/'));
0096       }
0097       return writeImage(img_);
0098     }
0099     QDir dir(path);
0100     if(dir.mkdir(path)) {
0101 //      myLog() << "created" << path;
0102     } else {
0103       myWarning() << "unable to create dir:" << path;
0104     }
0105     m_pathExists = true;
0106   }
0107   QUrl target = QUrl::fromLocalFile(path);
0108   target.setPath(target.path() + img_.id());
0109   return FileHandler::writeDataURL(target, img_.byteArray(), true /* force */);
0110 }
0111 
0112 bool ImageDirectory::removeImage(const QString& id_) {
0113   return m_pathExists && QFile::remove(path() + id_);
0114 }
0115 
0116 TemporaryImageDirectory::TemporaryImageDirectory() : ImageDirectory(), m_dir(nullptr) {
0117 }
0118 
0119 TemporaryImageDirectory::~TemporaryImageDirectory() {
0120   purge();
0121 }
0122 
0123 void TemporaryImageDirectory::purge() {
0124   delete m_dir;
0125   m_dir = nullptr;
0126 }
0127 
0128 QString TemporaryImageDirectory::path() {
0129   if(!m_dir) {
0130     m_dir = new QTemporaryDir(); // default is to auto-delete, aka autoRemove()
0131     // in KDE4, the way this worked included the final slash.
0132     ImageDirectory::setPath(m_dir->path() + QLatin1Char('/'));
0133   }
0134   return ImageDirectory::path();
0135 }
0136 
0137 void TemporaryImageDirectory::setPath(const QString& path) {
0138   Q_UNUSED(path);
0139   Q_ASSERT(path.isEmpty()); // should never be called, that's why it's private
0140 }
0141 
0142 ImageZipArchive::ImageZipArchive() : ImageStorage(), m_imgDir(nullptr) {
0143 }
0144 
0145 ImageZipArchive::~ImageZipArchive() {
0146 }
0147 
0148 void ImageZipArchive::setZip(std::unique_ptr<KZip> zip_) {
0149   m_images.clear();
0150   m_zip = std::move(zip_);
0151   m_imgDir = nullptr;
0152 
0153   const KArchiveDirectory* dir = m_zip->directory();
0154   if(!dir) {
0155     m_zip.reset();
0156     return;
0157   }
0158   const KArchiveEntry* imgDirEntry = dir->entry(QStringLiteral("images"));
0159   if(!imgDirEntry || !imgDirEntry->isDirectory()) {
0160     m_zip.reset();
0161     return;
0162   }
0163   m_imgDir = static_cast<const KArchiveDirectory*>(imgDirEntry);
0164   m_images.add(m_imgDir->entries());
0165 }
0166 
0167 bool ImageZipArchive::hasImage(const QString& id_) {
0168   return m_images.has(id_);
0169 }
0170 
0171 Tellico::Data::Image* ImageZipArchive::imageById(const QString& id_) {
0172   if(!hasImage(id_)) {
0173     return nullptr;
0174   }
0175   Data::Image* img = nullptr;
0176   const KArchiveEntry* file = m_imgDir->entry(id_);
0177   if(file && file->isFile()) {
0178     img = new Data::Image(static_cast<const KArchiveFile*>(file)->data(),
0179                           id_.section(QLatin1Char('.'), -1).toUpper(), id_);
0180   }
0181   // might be unexpected behavior, but in order to delete the zip object after
0182   // all images are read, we need to consider the image gone now
0183   m_images.remove(id_);
0184   if(m_images.isEmpty()) {
0185     m_zip.reset();
0186     m_imgDir = nullptr;
0187   }
0188   if(!img) {
0189     myLog() << "image not found:" << id_;
0190     return nullptr;
0191   }
0192   if(img->isNull()) {
0193     myLog() << "image found but null:" << id_;
0194     delete img;
0195     return nullptr;
0196   }
0197   return img;
0198 }