File indexing completed on 2025-01-26 04:24:56

0001 /* Copyright 2015 Robert Schroll
0002  *
0003  * This file is part of Beru and is distributed under the terms of
0004  * the GPL. See the file COPYING for full details.
0005  */
0006 
0007 #include "cbzreader.h"
0008 #include <QJsonObject>
0009 #include <QJsonArray>
0010 #include <QJsonDocument>
0011 #include <QtGui/QImage>
0012 #include <QBuffer>
0013 #include <QDir>
0014 #include <QCryptographicHash>
0015 #include "quazip/quazip.h"
0016 #include "quazip/quazipfile.h"
0017 #include "../qhttpserver/qhttpresponse.h"
0018 
0019 QString guessMimeType(const QString &filename);
0020 
0021 CBZReader::CBZReader(QObject *parent) :
0022     QObject(parent)
0023 {
0024     this->zip = NULL;
0025 }
0026 
0027 bool CBZReader::load(const QString &filename)
0028 {
0029     if (this->zip != NULL) {
0030         delete this->zip;
0031         this->zip = NULL;
0032     }
0033     this->_hash = "";
0034     this->spine.clear();
0035 
0036     this->zip = new QuaZip(filename);
0037     if (!this->zip->open(QuaZip::mdUnzip)) {
0038         delete this->zip;
0039         this->zip = NULL;
0040         return false;
0041     }
0042     if (!this->parse()) {
0043         delete this->zip;
0044         this->zip = NULL;
0045         return false;
0046     }
0047     return true;
0048 }
0049 
0050 bool CBZReader::parse() {
0051     QList<QuaZipFileInfo> fileList = this->zip->getFileInfoList();
0052     foreach (const QuaZipFileInfo info, fileList) {
0053         if (info.uncompressedSize > 0)
0054             this->spine.append(info.name);
0055     }
0056     return true;
0057 }
0058 
0059 QString CBZReader::hash() {
0060     if (this->_hash != "")
0061         return this->_hash;
0062 
0063     if (!this->zip || !this->zip->isOpen())
0064         return this->_hash;
0065 
0066     QByteArray CRCarray;
0067     QDataStream CRCstream(&CRCarray, QIODevice::WriteOnly);
0068     QList<QuaZipFileInfo> fileList = this->zip->getFileInfoList();
0069     foreach (const QuaZipFileInfo info, fileList) {
0070         CRCstream << info.crc;
0071     }
0072     this->_hash = QCryptographicHash::hash(CRCarray, QCryptographicHash::Md5).toHex();
0073     return this->_hash;
0074 }
0075 
0076 QString CBZReader::title() {
0077     return "";
0078 }
0079 
0080 void CBZReader::serveComponent(const QString &filename, QHttpResponse *response)
0081 {
0082     if (!this->zip || !this->zip->isOpen()) {
0083         response->writeHead(500);
0084         response->end("Epub file not open for reading");
0085         return;
0086     }
0087 
0088     this->zip->setCurrentFile(filename);
0089     QuaZipFile zfile(this->zip);
0090     if (!zfile.open(QIODevice::ReadOnly)) {
0091         response->writeHead(404);
0092         response->end("Could not find \"" + filename + "\" in epub file");
0093         return;
0094     }
0095 
0096     response->setHeader("Content-Type", guessMimeType(filename));
0097     response->writeHead(200);
0098     // Important -- use write instead of end, so binary data doesn't get messed up!
0099     response->write(zfile.readAll());
0100     response->end();
0101     zfile.close();
0102 }
0103 
0104 QVariantList CBZReader::getContents()
0105 {
0106     QVariantList res;
0107     for (int i=0; i<this->spine.length(); i++) {
0108         QVariantMap entry;
0109         entry["title"] = "%PAGE% " + QString::number(i + 1);
0110         entry["src"] = this->spine[i];
0111         res.append(entry);
0112     }
0113     Q_EMIT contentsReady(res);
0114     return res;
0115 }
0116 
0117 void CBZReader::serveBookData(QHttpResponse *response)
0118 {
0119     if (!this->zip || !this->zip->isOpen()) {
0120         response->writeHead(500);
0121         response->end("Epub file not open for reading");
0122         return;
0123     }
0124 
0125     response->setHeader("Content-Type", guessMimeType("js"));
0126     response->writeHead(200);
0127     QJsonDocument spine(QJsonArray::fromStringList(this->spine));
0128     QJsonDocument contents(QJsonArray::fromVariantList(this->getContents()));
0129     QString res = "var bookData = {" \
0130             "getComponents: function () { return %1; }, " \
0131             "getContents:   function () { return %2; }, " \
0132             "getComponent:  function (component) { return " \
0133             "\"<img style='display: block; margin: auto; max-height: 100% !important' src='\"" \
0134             "+ component.replace(/\"/g, \"&#34;\").replace(/'/g, \"&#39;\") + \"' />\"; }, " \
0135             "getMetaData:   function (key) { return ''; } }";
0136     response->write(res.arg(QString(spine.toJson()), QString(contents.toJson())));
0137     response->end();
0138 }
0139 
0140 QVariantMap CBZReader::getCoverInfo(int thumbsize, int fullsize)
0141 {
0142     QVariantMap res;
0143     if (!this->zip || !this->zip->isOpen())
0144         return res;
0145 
0146     res["title"] = "ZZZnone";
0147     res["author"] = "";
0148     res["authorsort"] = "zzznone";
0149     res["cover"] = "ZZZnone";
0150 
0151     this->zip->setCurrentFile(this->spine[0]);
0152     QuaZipFile zfile(this->zip);
0153     if (!zfile.open(QIODevice::ReadOnly))
0154         return res;
0155 
0156     QImage coverimg;
0157     if (!coverimg.loadFromData(zfile.readAll())) {
0158         zfile.close();
0159         return res;
0160     }
0161     zfile.close();
0162     QByteArray byteArray;
0163     QBuffer buffer(&byteArray);
0164     coverimg.scaledToWidth(thumbsize, Qt::SmoothTransformation).save(&buffer, "PNG");
0165     res["cover"] = "data:image/png;base64," + QString(byteArray.toBase64());
0166     QByteArray byteArrayf;
0167     QBuffer bufferf(&byteArrayf);
0168     coverimg.scaledToWidth(fullsize, Qt::SmoothTransformation).save(&bufferf, "PNG");
0169     res["fullcover"] = "data:image/png;base64," + QString(byteArrayf.toBase64());
0170     return res;
0171 }