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 }