mobidocument.cpp 4.06 KB
Newer Older
1 2 3 4 5 6 7 8 9
/***************************************************************************
 *   Copyright (C) 2008 by Jakub Stachowski <qbast@go2.pl>                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/
#include "mobidocument.h"
Albert Astals Cid's avatar
Albert Astals Cid committed
10 11
#include <qmobipocket/mobipocket.h>
#include <qmobipocket/qfilestream.h>
Yuri Chornoivan's avatar
Yuri Chornoivan committed
12 13 14 15
#include <QColor>
#include <QFile>
#include <QRegExp>
#include <QDebug>
16 17
#include <QApplication> // Because of the HACK
#include <QPalette> // Because of the HACK
18 19 20 21 22 23 24 25 26 27

using namespace Mobi;

MobiDocument::MobiDocument(const QString &fileName) : QTextDocument() 
{
  file = new Mobipocket::QFileStream(fileName);
  doc = new Mobipocket::Document(file);
  if (doc->isValid()) {
      QString text=doc->text();
      QString header=text.left(1024);
28
      if (header.contains(QStringLiteral("<html>")) || header.contains(QStringLiteral("<HTML>"))) {
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
        // HACK BEGIN Get the links without CSS to be blue
        //            Remove if Qt ever gets fixed and the code in textdocumentgenerator.cpp works
        const QPalette orig = qApp->palette();
        QPalette p = orig;
        p.setColor(QPalette::Link, Qt::blue);
        qApp->setPalette(p);
        // HACK END

        setHtml(fixMobiMarkup(text));

        // HACK BEGIN
        qApp->setPalette(orig);
        // HACK END
      } else {
          setPlainText(text);
      }
45 46 47 48 49 50 51 52 53 54 55
  }
}

MobiDocument::~MobiDocument() 
{
    delete doc;
    delete file;
}
  
QVariant MobiDocument::loadResource(int type, const QUrl &name) 
{
56
  if (type!=QTextDocument::ImageResource || name.scheme()!=QString(QStringLiteral("pdbrec"))) return QVariant();
57
  bool ok;
Laurent Montel's avatar
Laurent Montel committed
58
  quint16 recnum=name.path().midRef(1).toUShort(&ok);
59 60 61 62 63 64 65 66 67 68 69 70 71
  if (!ok || recnum>=doc->imageCount()) return QVariant();
   
  QVariant resource;
  resource.setValue(doc->getImage(recnum-1));
  addResource(type, name, resource); 
    
  return resource;
}

// starting from 'pos', find position in the string that is not inside a tag
int outsideTag(const QString& data, int pos)
{
  for (int i=pos-1;i>=0;i--) {
72 73
    if (data[i]==QLatin1Char('>')) return pos;
    if (data[i]==QLatin1Char('<')) return i;
74 75 76 77 78 79 80 81
  }
  return pos;
}

QString MobiDocument::fixMobiMarkup(const QString& data) 
{
    QString ret=data;
    QMap<int,QString> anchorPositions;
82
    static QRegExp anchors(QStringLiteral("<a(?: href=\"[^\"]*\"){0,1}[\\s]+filepos=['\"]{0,1}([\\d]+)[\"']{0,1}"), Qt::CaseInsensitive);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    int pos=0;

    // find all link destinations
    while ( (pos=anchors.indexIn( data, pos ))!=-1) {
	int filepos=anchors.cap( 1 ).toUInt(  );
	if (filepos) anchorPositions[filepos]=anchors.cap(1);
	pos+=anchors.matchedLength();
    }

    // put HTML anchors in all link destinations
    int offset=0;
    QMapIterator<int,QString> it(anchorPositions);
    while (it.hasNext()) {
      it.next();
      // link pointing outside the document, ignore
      if ( (it.key()+offset) >= ret.size()) continue;
      int fixedpos=outsideTag(ret, it.key()+offset);
100
      ret.insert(fixedpos,QStringLiteral("<a name=\"")+it.value()+QStringLiteral("\">&nbsp;</a>"));
101 102 103 104 105
      // inserting anchor shifts all offsets after the anchor
      offset+=21+it.value().size();
    }

    // replace links referencing filepos with normal internal links
106
    ret.replace(anchors, QStringLiteral("<a href=\"#\\1\""));
107 108
    // Mobipocket uses strange variang of IMG tags: <img recindex="3232"> where recindex is number of 
    // record containing image
109
    static QRegExp imgs(QStringLiteral("<img.*recindex=\"([\\d]*)\".*>"), Qt::CaseInsensitive);
110 111
    
    imgs.setMinimal(true);
112 113
    ret.replace(imgs, QStringLiteral("<img src=\"pdbrec:/\\1\">"));
    ret.replace(QStringLiteral("<mbp:pagebreak/>"), QStringLiteral("<p style=\"page-break-after:always\"></p>"));
114 115 116
    
    return ret;
}