Improve default book. Speed up book parsing. Simplify XML parsing.
authorAkos Polster <akos@pipacs.com>
Sun, 3 Oct 2010 20:18:19 +0000 (22:18 +0200)
committerAkos Polster <akos@pipacs.com>
Sun, 3 Oct 2010 20:18:19 +0000 (22:18 +0200)
12 files changed:
books/2BR02B.epub
dorian.pro
librarydialog.cpp
model/book.cpp
model/book.h
model/containerhandler.h
model/extractzip.cpp
model/extractzip.h
model/ncxhandler.h
model/opshandler.h
pkg/changelog
pkg/version.txt

index fb83a99..8c769fc 100644 (file)
Binary files a/books/2BR02B.epub and b/books/2BR02B.epub differ
index 538cdcc..72a6be6 100644 (file)
-QT += webkit xml\r
-\r
-INCLUDEPATH += $$PWD \\r
-    $$PWD/model \\r
-    $$PWD/widgets\r
-\r
-SOURCES += \\r
-    main.cpp \\r
-    mainwindow.cpp \\r
-    bookview.cpp \\r
-    model/unzip/unzip.c \\r
-    model/unzip/ioapi.c \\r
-    model/extractzip.cpp \\r
-    model/library.cpp \\r
-    model/book.cpp \\r
-    librarydialog.cpp \\r
-    devtools.cpp \\r
-    infodialog.cpp \\r
-    widgets/translucentbutton.cpp \\r
-    settingswindow.cpp \\r
-    model/settings.cpp \\r
-    bookmarksdialog.cpp \\r
-    model/sortedlibrary.cpp \\r
-    bookmarkinfodialog.cpp \\r
-    widgets/dyalog.cpp \\r
-    chaptersdialog.cpp \\r
-    widgets/fullscreenwindow.cpp \\r
-    trace.cpp \\r
-    widgets/toolbuttonbox.cpp \\r
-    model/bookfinder.cpp \\r
-    widgets/listwindow.cpp \\r
-    widgets/progress.cpp \\r
-    widgets/adopterwindow.cpp\r
-\r
-HEADERS += \\r
-    mainwindow.h \\r
-    bookview.h \\r
-    model/opshandler.h \\r
-    model/unzip/unzip.h \\r
-    model/unzip/ioapi.h \\r
-    model/extractzip.h \\r
-    model/library.h \\r
-    model/book.h \\r
-    librarydialog.h \\r
-    devtools.h \\r
-    infodialog.h \\r
-    widgets/translucentbutton.h \\r
-    settingswindow.h \\r
-    model/settings.h \\r
-    bookmarksdialog.h \\r
-    model/xmlerrorhandler.h \\r
-    model/containerhandler.h \\r
-    model/sortedlibrary.h \\r
-    model/ncxhandler.h \\r
-    bookmarkinfodialog.h \\r
-    widgets/dyalog.h \\r
-    chaptersdialog.h \\r
-    widgets/fullscreenwindow.h \\r
-    trace.h \\r
-    widgets/toolbuttonbox.h \\r
-    model/bookfinder.h \\r
-    widgets/listwindow.h \\r
-    widgets/progress.h \\r
-    widgets/adopterwindow.h \\r
-    widgets/listview.h\r
-\r
-RESOURCES += \\r
-    dorian.qrc\r
-\r
-OTHER_FILES += \\r
-    TODO.txt \\r
-    pkg/acknowledgements.txt \\r
-    pkg/maemo/postinst \\r
-    pkg/maemo/dorian.desktop \\r
-    pkg/maemo/control \\r
-    pkg/maemo/changelog \\r
-    pkg/maemo/build.sh \\r
-    styles/night.css \\r
-    pkg/changelog \\r
-    pkg/maemo/build-scratchbox.sh \\r
-    styles/sand.css \\r
-    styles/default.css \\r
-    pkg/version.txt \\r
-    styles/sand.js \\r
-    styles/night.js \\r
-    styles/default.js \\r
-    styles/day.js \\r
-    www/index.html \\r
-    pkg/maemo/autobuild.sh \\r
-    pkg/maemo/autobuild-scratchbox.sh \\r
-    LICENSE.txt \\r
-    pkg/symbian/book.svg\r
-\r
-DEFINES += \\r
-    USE_FILE32API \\r
-    DORIAN_TEST_MODEL\r
-\r
-include(model/modeltest/modeltest.pri)\r
-\r
-unix {\r
-    symbian {\r
-    } else {\r
-        LIBS += -lz\r
-    }\r
-}\r
-win32 {\r
-    DEFINES += ZLIB_WINAPI\r
-    INCLUDEPATH += $$PWD/model/zlib\r
-    LIBS += pkg/win32/zlibstat.lib\r
-}\r
-symbian {\r
-    ICON = $$PWD/pkg/symbian/book.svgt\r
-    TARGET.UID3 = 0xEA633557\r
-    # TARGET.CAPABILITY = ...\r
-    # FIXME: Add OpenC ZLIB?\r
-    INCLUDEPATH += C:/NokiaQtSDK/Symbian/SDK/src/3rdparty/zlib \\r
-        c:/Qt/4.7.0/src/3rdparty/zlib\r
-}\r
-maemo5 {\r
-    QT += maemo5 dbus\r
-    isEmpty(PREFIX) {\r
-        PREFIX = /usr\r
-    }\r
-    BINDIR = $$PREFIX/bin\r
-    DATADIR =$$PREFIX/share\r
-    DEFINES += DATADIR=\\\"$$DATADIR\\\" PKGDATADIR=\\\"$$PKGDATADIR\\\"\r
-\r
-    # For "make install"\r
-\r
-    INSTALLS += target desktop icon48 iconscalable\r
-\r
-    target.path = $$BINDIR\r
-\r
-    desktop.path = $$DATADIR/applications/hildon\r
-    desktop.files += pkg/maemo/dorian.desktop\r
-\r
-    icon48.path = $$DATADIR/icons/hicolor/48x48/hildon\r
-    icon48.files += pkg/maemo/icon-48/dorian.png\r
-\r
-    iconscalable.path = $$DATADIR/icons/hicolor/scalable/hildon\r
-    iconscalable.files += pkg/maemo/icon-scalable/dorian.png\r
-}\r
-macx {\r
-    CONFIG += x86\r
-}\r
+QT += webkit xml
+
+INCLUDEPATH += $$PWD \
+    $$PWD/model \
+    $$PWD/widgets
+
+SOURCES += \
+    main.cpp \
+    mainwindow.cpp \
+    bookview.cpp \
+    model/unzip/unzip.c \
+    model/unzip/ioapi.c \
+    model/extractzip.cpp \
+    model/library.cpp \
+    model/book.cpp \
+    librarydialog.cpp \
+    devtools.cpp \
+    infodialog.cpp \
+    widgets/translucentbutton.cpp \
+    settingswindow.cpp \
+    model/settings.cpp \
+    bookmarksdialog.cpp \
+    model/sortedlibrary.cpp \
+    bookmarkinfodialog.cpp \
+    widgets/dyalog.cpp \
+    chaptersdialog.cpp \
+    widgets/fullscreenwindow.cpp \
+    trace.cpp \
+    widgets/toolbuttonbox.cpp \
+    model/bookfinder.cpp \
+    widgets/listwindow.cpp \
+    widgets/progress.cpp \
+    widgets/adopterwindow.cpp
+
+HEADERS += \
+    mainwindow.h \
+    bookview.h \
+    model/opshandler.h \
+    model/unzip/unzip.h \
+    model/unzip/ioapi.h \
+    model/extractzip.h \
+    model/library.h \
+    model/book.h \
+    librarydialog.h \
+    devtools.h \
+    infodialog.h \
+    widgets/translucentbutton.h \
+    settingswindow.h \
+    model/settings.h \
+    bookmarksdialog.h \
+    model/xmlerrorhandler.h \
+    model/containerhandler.h \
+    model/sortedlibrary.h \
+    model/ncxhandler.h \
+    bookmarkinfodialog.h \
+    widgets/dyalog.h \
+    chaptersdialog.h \
+    widgets/fullscreenwindow.h \
+    trace.h \
+    widgets/toolbuttonbox.h \
+    model/bookfinder.h \
+    widgets/listwindow.h \
+    widgets/progress.h \
+    widgets/adopterwindow.h \
+    widgets/listview.h \
+    model/xmlhandler.h
+
+RESOURCES += \
+    dorian.qrc
+
+OTHER_FILES += \
+    TODO.txt \
+    pkg/acknowledgements.txt \
+    pkg/maemo/postinst \
+    pkg/maemo/dorian.desktop \
+    pkg/maemo/control \
+    pkg/maemo/changelog \
+    pkg/maemo/build.sh \
+    styles/night.css \
+    pkg/changelog \
+    pkg/maemo/build-scratchbox.sh \
+    styles/sand.css \
+    styles/default.css \
+    pkg/version.txt \
+    styles/sand.js \
+    styles/night.js \
+    styles/default.js \
+    styles/day.js \
+    www/index.html \
+    pkg/maemo/autobuild.sh \
+    pkg/maemo/autobuild-scratchbox.sh \
+    LICENSE.txt \
+    pkg/symbian/book.svg
+
+DEFINES += \
+    USE_FILE32API \
+    DORIAN_TEST_MODEL
+
+include(model/modeltest/modeltest.pri)
+
+unix {
+    symbian {
+    } else {
+        LIBS += -lz
+    }
+}
+win32 {
+    DEFINES += ZLIB_WINAPI
+    INCLUDEPATH += $$PWD/model/zlib
+    LIBS += pkg/win32/zlibstat.lib
+}
+symbian {
+    ICON = $$PWD/pkg/symbian/book.svgt
+    TARGET.UID3 = 0xEA633557
+    # TARGET.CAPABILITY = ...
+    # FIXME: Add OpenC ZLIB?
+    INCLUDEPATH += C:/NokiaQtSDK/Symbian/SDK/src/3rdparty/zlib \
+        c:/Qt/4.7.0/src/3rdparty/zlib
+}
+maemo5 {
+    QT += maemo5 dbus
+    isEmpty(PREFIX) {
+        PREFIX = /usr
+    }
+    BINDIR = $$PREFIX/bin
+    DATADIR =$$PREFIX/share
+    DEFINES += DATADIR=\\\"$$DATADIR\\\" PKGDATADIR=\\\"$$PKGDATADIR\\\"
+
+    # For "make install"
+
+    INSTALLS += target desktop icon48 iconscalable
+
+    target.path = $$BINDIR
+
+    desktop.path = $$DATADIR/applications/hildon
+    desktop.files += pkg/maemo/dorian.desktop
+
+    icon48.path = $$DATADIR/icons/hicolor/48x48/hildon
+    icon48.files += pkg/maemo/icon-48/dorian.png
+
+    iconscalable.path = $$DATADIR/icons/hicolor/scalable/hildon
+    iconscalable.files += pkg/maemo/icon-scalable/dorian.png
+}
+macx {
+    CONFIG += x86
+}
index 767667a..c08c4ae 100644 (file)
@@ -221,8 +221,8 @@ void LibraryDialog::onAddFromFolderDone(int added)
 
     switch (added) {
     case 0: msg = tr("No new books found"); break;
-    case 1: msg = tr("One new book added"); break;
-    default: msg = tr("%1 new books added").arg(added);
+    case 1: msg = tr("One book added"); break;
+    default: msg = tr("%1 books added").arg(added);
     }
 
     progress->reset();
index 92446f5..8fc6f69 100644 (file)
@@ -54,7 +54,7 @@ bool Book::open()
         title = "No book";
         return false;
     }
-    if (!extract()) {
+    if (!extract(QStringList())) {
         return false;
     }
     if (!parse()) {
@@ -101,7 +101,7 @@ QString Book::tmpDir() const
             absoluteFilePath(tmpName);
 }
 
-bool Book::extract()
+bool Book::extract(const QStringList &excludedExtensions)
 {
     Trace t("Book::extract");
     bool ret = false;
@@ -139,7 +139,7 @@ bool Book::extract()
         qCritical() << "Book::extract: Could not change to" << tmp;
         return false;
     }
-    ret = extractZip(bookPath);
+    ret = extractZip(bookPath, excludedExtensions);
     if (!ret) {
         qCritical() << "Book::extract: Extracting ZIP failed";
     }
@@ -172,15 +172,26 @@ bool Book::parse()
     chapters = parts;
 
     // Load cover image
+    QString coverPath;
     QStringList coverKeys;
     coverKeys << "cover-image" << "img-cover-jpeg" << "cover";
     foreach (QString key, coverKeys) {
         if (content.contains(key)) {
-            qDebug() << "Loading cover image from" << content[key].href;
-            cover = makeCover(QDir(rootPath()).absoluteFilePath(content[key].href));
+            coverPath = QDir(rootPath()).absoluteFilePath(content[key].href);
             break;
         }
     }
+    if (coverPath.isEmpty()) {
+        // Last resort
+        QString coverJpeg = QDir(rootPath()).absoluteFilePath("cover.jpg");
+        if (QFileInfo(coverJpeg).exists()) {
+            coverPath = coverJpeg;
+        }
+    }
+    if (!coverPath.isEmpty()) {
+        qDebug() << "Loading cover image from" << coverPath;
+        cover = makeCover(coverPath);
+    }
 
     // If there is an "ncx" item in content, parse it: That's the real table of
     // contents
@@ -482,6 +493,7 @@ qreal Book::getProgress(int part, qreal position)
 
 bool Book::extractMetaData()
 {
-    // FIXME
-    return extract();
+    QStringList excludedExtensions;
+    excludedExtensions << ".html" << ".xhtml" << ".xht" << ".htm";
+    return extract(excludedExtensions);
 }
index 5305220..0c8fa4f 100644 (file)
@@ -127,7 +127,7 @@ signals:
 
 protected:
     /** Extract EPUB as ZIP. */
-    bool extract();
+    bool extract(const QStringList &excludedExtensions);
 
     /** Extract metadata from EPUB. */
     bool extractMetaData();
index d952d53..1fda1a9 100644 (file)
@@ -1,25 +1,12 @@
 #ifndef CONTAINERHANDLER_H
 #define CONTAINERHANDLER_H
 
-#include <QXmlContentHandler>
-#include <QString>
+#include "xmlhandler.h"
 
 /** XML content handler for EPUB container format. */
-class ContainerHandler: public QXmlContentHandler
+class ContainerHandler: public XmlHandler
 {
 public:
-    bool endDocument() {return true;}
-    bool endPrefixMapping(const QString &) {return true;}
-    QString errorString() const {return "";}
-    bool ignorableWhitespace(const QString &) {return true;}
-    bool processingInstruction(const QString &, const QString &) {
-        return true;
-    }
-    void setDocumentLocator(QXmlLocator *) {}
-    bool skippedEntity(const QString &) {return true;}
-    bool startDocument() {return true;}
-    bool startPrefixMapping(const QString &, const QString &) {return true;}
-    bool characters(const QString &) {return true;}
     bool endElement(const QString &, const QString &, const QString &) {
         return true;
     }
index 904f9bf..6f5db8e 100644 (file)
@@ -1,6 +1,8 @@
 #include <QDebug>
 #include <QFile>
 #include <QDir>
+#include <QString>
+#include <QStringList>
 
 #include "extractzip.h"
 #include "unzip/unzip.h"
@@ -8,7 +10,7 @@
 #define WRITEBUFFERSIZE (8192)
 #define MAXFILENAME (256)
 
-int doExtractCurrentFile(unzFile uf)
+int doExtractCurrentFile(unzFile uf, const QStringList &excludedExtensions)
 {
     char fileNameInZip[MAXFILENAME];
     char *fileNameWithoutPath;
@@ -39,7 +41,7 @@ int doExtractCurrentFile(unzFile uf)
     p = fileNameWithoutPath = fileNameInZip;
     while ((*p) != '\0') {
         if (((*p) == '/') || ((*p) == '\\')) {
-            fileNameWithoutPath = p+1;
+            fileNameWithoutPath = p + 1;
         }
         p++;
     }
@@ -48,6 +50,15 @@ int doExtractCurrentFile(unzFile uf)
         dir.mkdir(fileNameInZip);
     }
     else {
+        QString name(fileNameInZip);
+        for (int i = 0; i < excludedExtensions.length(); i++) {
+            if (name.endsWith(excludedExtensions[i], Qt::CaseInsensitive)) {
+                qDebug() << "Skipping" << name;
+                free(buf);
+                return UNZ_OK;
+            }
+        }
+
         const char *writeFileName;
         int skip = 0;
 
@@ -104,7 +115,7 @@ int doExtractCurrentFile(unzFile uf)
             f->close();
         }
 
-        if (err== UNZ_OK) {
+        if (err == UNZ_OK) {
             err = unzCloseCurrentFile(uf);
             if (err != UNZ_OK) {
                 qDebug() << "doExtractCurrentFile: Error" << err
@@ -121,20 +132,20 @@ int doExtractCurrentFile(unzFile uf)
     return err;
 }
 
-bool doExtract(unzFile uf)
+bool doExtract(unzFile uf, const QStringList &excludedExtensions)
 {
     uLong i;
     unz_global_info64 gi;
     int err;
 
-    err = unzGetGlobalInfo64(uf,&gi);
+    err = unzGetGlobalInfo64(uf, &gi);
     if (err != UNZ_OK) {
         qDebug() << "doExtract: Error" << err << "in unzGetGlobalInfo";
         return false;
     }
 
     for (i = 0; i < gi.number_entry; i++) {
-        if (doExtractCurrentFile(uf) != UNZ_OK) {
+        if (doExtractCurrentFile(uf, excludedExtensions) != UNZ_OK) {
             return false;
         }
         if ((i + 1) < gi.number_entry) {
@@ -149,14 +160,14 @@ bool doExtract(unzFile uf)
     return true;
 }
 
-bool extractZip(const QString &zipFile)
+bool extractZip(const QString &zipFile, const QStringList &excludedExtensions)
 {
     unzFile uf;
     bool ret = false;
 
     uf = unzOpen64(zipFile.toUtf8().constData());
     if (uf) {
-        ret = doExtract(uf);
+        ret = doExtract(uf, excludedExtensions);
         unzClose(uf);
     }
     return ret;
index f5a3de3..872844d 100644 (file)
@@ -2,7 +2,17 @@
 #define EXTRACTZIP_H
 
 class QString;
+class QStringList;
 
-bool extractZip(const QString &path);
+/**
+ * Extract files from a ZIP archive.
+ *
+ * @param   path                ZIP file path.
+ * @param   excludedExtensions  Files in the ZIP with matching extensions will
+ *                              not be extracted. Items in this list are case
+ *                              insensitive, and start with ".".
+ * @return  True (succes) or false (failure).
+ */
+bool extractZip(const QString &path, const QStringList &excludedExtensions);
 
 #endif // EXTRACTZIP_H
index f04ade1..2da3633 100644 (file)
@@ -1,44 +1,27 @@
 #ifndef NCXHANDLER_H
 #define NCXHANDLER_H
 
-#include <QXmlContentHandler>
-
+#include "xmlhandler.h"
 #include "book.h"
 #include "trace.h"
 
 /** XML content handler for NCX format. */
-class NcxHandler: public QXmlContentHandler
+class NcxHandler: public XmlHandler
 {
 public:
-    bool endDocument() {return true;}
-    bool endPrefixMapping(const QString &) {return true;}
-    QString errorString() const {return "";}
-    bool ignorableWhitespace(const QString &) {return true;}
-    bool processingInstruction(const QString &, const QString &) {return true;}
-    void setDocumentLocator(QXmlLocator *) {}
-    bool skippedEntity(const QString &) {return true;}
-    bool startDocument() {return true;}
-    bool startPrefixMapping(const QString &, const QString &) {return true;}
-
     NcxHandler(Book &b): book(b) {
         book.chapters.clear();
     }
 
-    bool characters(const QString &ch) {
-        currentText += ch;
-        return true;
-    }
-
     bool endElement(const QString &namespaceUri, const QString &name,
                     const QString &qName) {
-        Trace t("NcxHandler::endElement " + name);
         (void)namespaceUri;
         (void)qName;
         if (name == "text") {
             contentTitle = currentText;
         } else if (name == "navPoint") {
-            qDebug() << "url" << contentUrl << "\ntitle" << contentTitle
-                    << "\nid" << contentId;
+            qDebug() << "BcxHander::endElement: url" << contentUrl << "title"
+                    << contentTitle << "id" << contentId;
             Book::ContentItem item;
             item.href = contentUrl;
             item.name = contentTitle;
@@ -63,7 +46,6 @@ public:
 
 private:
     Book &book;
-    QString currentText;
     QString contentId;
     QString contentUrl;
     QString contentTitle;
index 98d4ae1..8440afb 100644 (file)
@@ -1,32 +1,15 @@
 #ifndef OPSHANDLER_H
 #define OPSHANDLER_H
 
-#include <QXmlContentHandler>
-
+#include "xmlhandler.h"
 #include "book.h"
 #include "trace.h"
 
 /** XML content handler for OPS format. */
-class OpsHandler: public QXmlContentHandler
+class OpsHandler: public XmlHandler
 {
 public:
     OpsHandler(Book &b): book(b), partCount(0) {}
-    bool endDocument() {return true;}
-    bool endPrefixMapping(const QString &) {return true;}
-    QString errorString() const {return QString();}
-    bool ignorableWhitespace(const QString &) {return true;}
-    bool processingInstruction(const QString &, const QString &) {
-        return true;
-    }
-    void setDocumentLocator(QXmlLocator *) {}
-    bool skippedEntity(const QString &) {return true;}
-    bool startDocument() {return true;}
-    bool startPrefixMapping(const QString &, const QString &) {return true;}
-
-    bool characters(const QString &ch) {
-        currentText += ch;
-        return true;
-    }
 
     bool endElement(const QString &namespaceUri, const QString &name,
                     const QString &qName) {
@@ -52,7 +35,6 @@ public:
 
     bool startElement(const QString &namespaceUri, const QString &name,
                       const QString &qName, const QXmlAttributes &attrs) {
-        Trace t("OpsHandler::startElement " + name);
         (void)namespaceUri;
         (void)qName;
         currentText = "";
@@ -65,11 +47,11 @@ public:
             QString key = attrs.value("id");
             book.content[key] = item;
             partCount++;
-            qDebug() << "name:"<< item.name << "\nhref:"
-                    << attrs.value("href") << "id:" << key;
+            qDebug() << "OpsHandler::startElement: name" << item.name << "href"
+                    << attrs.value("href") << "id" << key;
         } else if (name == "itemref") {
-            qDebug() << "parts[" << book.parts.size() << "]:"
-                    << attrs.value("idref");
+            qDebug() << "OpsHandler::startElement: parts[" << book.parts.size()
+                    << "]" << attrs.value("idref");
             book.parts.append(attrs.value("idref"));
         }
         return true;
@@ -77,7 +59,6 @@ public:
 
 private:
     Book &book;
-    QString currentText;
     int partCount;
 };
 
index 8b088a6..7eee2bc 100644 (file)
@@ -1,3 +1,10 @@
+dorian (0.2.2-1) unstable; urgency=low
+
+  * Speed up book parsing
+  * Improve default book
+
+ -- Akos Polster <akos@pipacs.com>  Thu,  3 Oct 2010 02:00:00 +0200
+
 dorian (0.2.1-1) unstable; urgency=low
 
   * Fix TOC in "The Awakening" (and possibly other Google books) [#6318]
index fd32d72..92195dc 100644 (file)
@@ -1 +1 @@
-"0.2.1"
+"0.2.2"