File indexing completed on 2024-05-12 05:09:50

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->isNull()) {
0076     myLog() << "image found but null:" << (path() + id_);
0077     delete img;
0078     return nullptr;
0079   }
0080   return img;
0081 }
0082 
0083 bool ImageDirectory::writeImage(const Data::Image& img_) {
0084   const QString path = this->path(); // virtual function, so don't assume m_path is correct
0085   if(!m_pathExists) {
0086     if(path.isEmpty()) {
0087       // an empty path means the file hasn't been saved yet
0088       if(!m_dir) {
0089         m_dir = new QTemporaryDir(); // default is to auto-delete, aka autoRemove()
0090         // in KDE4, the way this worked included the final slash.
0091         ImageDirectory::setPath(m_dir->path() + QLatin1Char('/'));
0092       }
0093       return writeImage(img_);
0094     }
0095     QDir dir(path);
0096     if(dir.mkdir(path)) {
0097 //      myLog() << "created" << path;
0098     } else {
0099       myWarning() << "unable to create dir:" << path;
0100     }
0101     m_pathExists = true;
0102   }
0103   QUrl target = QUrl::fromLocalFile(path);
0104   target.setPath(target.path() + img_.id());
0105   return FileHandler::writeDataURL(target, img_.byteArray(), true /* force */);
0106 }
0107 
0108 bool ImageDirectory::removeImage(const QString& id_) {
0109   return m_pathExists && QFile::remove(path() + id_);
0110 }
0111 
0112 TemporaryImageDirectory::TemporaryImageDirectory() : ImageDirectory(), m_dir(nullptr) {
0113 }
0114 
0115 TemporaryImageDirectory::~TemporaryImageDirectory() {
0116   purge();
0117 }
0118 
0119 void TemporaryImageDirectory::purge() {
0120   delete m_dir;
0121   m_dir = nullptr;
0122 }
0123 
0124 QString TemporaryImageDirectory::path() {
0125   if(!m_dir) {
0126     m_dir = new QTemporaryDir(); // default is to auto-delete, aka autoRemove()
0127     // in KDE4, the way this worked included the final slash.
0128     ImageDirectory::setPath(m_dir->path() + QLatin1Char('/'));
0129   }
0130   return ImageDirectory::path();
0131 }
0132 
0133 void TemporaryImageDirectory::setPath(const QString& path) {
0134   Q_UNUSED(path);
0135   Q_ASSERT(path.isEmpty()); // should never be called, that's why it's private
0136 }
0137 
0138 ImageZipArchive::ImageZipArchive() : ImageStorage(), m_imgDir(nullptr) {
0139 }
0140 
0141 ImageZipArchive::~ImageZipArchive() {
0142 }
0143 
0144 void ImageZipArchive::setZip(std::unique_ptr<KZip> zip_) {
0145   m_images.clear();
0146   m_zip = std::move(zip_);
0147   m_imgDir = nullptr;
0148 
0149   const KArchiveDirectory* dir = m_zip->directory();
0150   if(!dir) {
0151     m_zip.reset();
0152     return;
0153   }
0154   const KArchiveEntry* imgDirEntry = dir->entry(QStringLiteral("images"));
0155   if(!imgDirEntry || !imgDirEntry->isDirectory()) {
0156     m_zip.reset();
0157     return;
0158   }
0159   m_imgDir = static_cast<const KArchiveDirectory*>(imgDirEntry);
0160   m_images.add(m_imgDir->entries());
0161 }
0162 
0163 bool ImageZipArchive::hasImage(const QString& id_) {
0164   return m_images.has(id_);
0165 }
0166 
0167 Tellico::Data::Image* ImageZipArchive::imageById(const QString& id_) {
0168   if(!hasImage(id_)) {
0169     return nullptr;
0170   }
0171   Data::Image* img = nullptr;
0172   const KArchiveEntry* file = m_imgDir->entry(id_);
0173   if(file && file->isFile()) {
0174     img = new Data::Image(static_cast<const KArchiveFile*>(file)->data(),
0175                           id_.section(QLatin1Char('.'), -1).toUpper(), id_);
0176   }
0177   // might be unexpected behavior, but in order to delete the zip object after
0178   // all images are read, we need to consider the image gone now
0179   m_images.remove(id_);
0180   if(m_images.isEmpty()) {
0181     m_zip.reset();
0182     m_imgDir = nullptr;
0183   }
0184   if(!img) {
0185     myLog() << "image not found:" << id_;
0186     return nullptr;
0187   }
0188   if(img->isNull()) {
0189     myLog() << "image found but null:" << id_;
0190     delete img;
0191     return nullptr;
0192   }
0193   return img;
0194 }