Commit 3b0f1744 authored by Jakub Stachowski's avatar Jakub Stachowski

Strigi analyzer form mobipocket format.


svn path=/trunk/playground/graphics/okular/mobipocket/; revision=883893
parent dfcc6820
......@@ -6,8 +6,10 @@ project(okular-mobi-generator)
ENABLE_TESTING()
find_package(KDE4 REQUIRED)
find_package(Strigi REQUIRED)
include_directories(${KDE4_INCLUDES} ${QT_INCLUDES}
${CMAKE_CURRENT_SOURCE_DIR}
${STRIGI_INCLUDE_DIR}
)
########### next target ###############
......@@ -29,18 +31,33 @@ set(mobithumbnail_SRCS
mobithumbnail.cpp
)
set(mobianalyzer_SRCS
mobipocket.cpp
decompressor.cpp
mobiendanalyzer.cpp
)
kde4_add_plugin(okularGenerator_mobi ${okularGenerator_mobi_PART_SRCS})
kde4_add_plugin(mobithumbnail ${mobithumbnail_SRCS})
kde4_add_library(mobi MODULE ${mobianalyzer_SRCS})
# FIXME: remove QtGui dependency on analyzer
target_link_libraries(mobi ${STRIGI_STREAMS_LIBRARY} ${STRIGI_STREAMANALYZER_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
target_link_libraries(okularGenerator_mobi okularcore ${mobi_LIBRARIES} ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY})
target_link_libraries(mobithumbnail ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${QT_QTGUI_LIBRARY} )
install(TARGETS mobithumbnail okularGenerator_mobi DESTINATION ${PLUGIN_INSTALL_DIR})
# install the module in the right directory so it is picked up
set_target_properties(mobi PROPERTIES PREFIX ${STRIGI_LINE_ANALYZER_PREFIX})
########### install files ###############
install( FILES mobithumbnail.desktop libokularGenerator_mobi.desktop okularMobi.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
install( FILES okularApplication_mobi.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install(TARGETS mobi LIBRARY DESTINATION ${LIB_INSTALL_DIR}/strigi)
install(
FILES x-mobipocket.xml
......
- better error handling
- tests for Mobipocket classes
- anchors (a filepos=)
- decryption for DRMed files (may be impossible and/or illegal)
- strigi analyzer
......@@ -82,7 +82,7 @@ QTextDocument* Converter::convert( const QString &fileName )
QPair<int,int>(frag.position(), frag.position()+frag.length());
if (!format.anchorNames().isEmpty()) {
// link targets
Q_FOREACH(QString name, format.anchorNames())
Q_FOREACH(const QString& name, format.anchorNames())
targets["#"+name]=it;
}
}
......
......@@ -8,6 +8,7 @@
***************************************************************************/
#include "mobidocument.h"
#include "mobipocket.h"
#include "qfilestream.h"
#include <QtCore/QFile>
#include <QtCore/QRegExp>
#include <kdebug.h>
......@@ -16,8 +17,7 @@ using namespace Mobi;
MobiDocument::MobiDocument(const QString &fileName) : QTextDocument()
{
file = new QFile(fileName);
file->open(QIODevice::ReadOnly);
file = new Mobipocket::QFileStream(fileName);
doc = new Mobipocket::Document(file);
if (doc->isValid()) setHtml(fixMobiMarkup(doc->text()));
}
......
......@@ -16,6 +16,7 @@
class QFile;
namespace Mobipocket {
class Document;
class QFileStream;
}
namespace Mobi {
......@@ -34,7 +35,7 @@ namespace Mobi {
private:
QString fixMobiMarkup(const QString& data);
Mobipocket::Document *doc;
QFile* file;
Mobipocket::QFileStream* file;
};
}
......
/***************************************************************************
* 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 "mobiendanalyzer.h"
#define STRIGI_IMPORT_API
#include <strigi/strigiconfig.h>
#include <strigi/analysisresult.h>
#include <strigi/fieldtypes.h>
#include <strigi/streamendanalyzer.h>
#include <strigi/analyzerplugin.h>
#include <list>
#include "mobipocket.h"
using namespace Strigi;
class StrigiStream : public Mobipocket::Stream
{
public:
StrigiStream(InputStream* str) : d(str) {}
int read(char* buf, int len) {
const char* b2;
int l=d->read(b2, len,len);
memcpy(buf,b2,len);
return l;
}
void seek(int pos) { d->reset(pos); }
private:
InputStream *d;
};
void
MobiEndAnalyzerFactory::registerFields(FieldRegister& reg) {
subjectField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#subject");
titleField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#title");
authorField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#author");
descriptionField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#description");
copyrightField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#copyright");
encryptedField = reg.registerField(
"http://freedesktop.org/standards/xesam/1.0/core#isContentEncrypted");
// typeField = reg.typeField;
//FIXME: check other fields - for example encryption
/* add the fields to the internal list of fields */
addField(subjectField);
addField(titleField);
addField(authorField);
addField(descriptionField);
addField(copyrightField);
addField(encryptedField);
// addField(typeField);
}
MobiEndAnalyzer::MobiEndAnalyzer(const MobiEndAnalyzerFactory* f) :factory(f) {
}
bool
MobiEndAnalyzer::checkHeader(const char* header, int32_t headersize) const {
static const char magic1[] = "TEXtREAd";
static const char magic2[] = "BOOKMOBI";
return headersize >= 67 && (!memcmp(header+60, magic1, 8) || !memcmp(header+60, magic2, 8));
}
signed char
MobiEndAnalyzer::analyze(AnalysisResult& as, InputStream* in) {
StrigiStream str(in);
Mobipocket::Document doc(&str);
if (!doc.isValid()) return -1;
// as.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Document");
as.addValue(factory->encryptedField, doc.hasDRM());
QMapIterator<Mobipocket::Document::MetaKey,QString> it(doc.metadata());
while (it.hasNext()) {
it.next();
switch (it.key()) {
case Mobipocket::Document::Title: as.addValue(factory->titleField, it.value().toUtf8().data() ); break;
case Mobipocket::Document::Author: as.addValue(factory->authorField, it.value().toUtf8().data() ); break;
case Mobipocket::Document::Description: as.addValue(factory->descriptionField, it.value().toUtf8().data() ); break;
case Mobipocket::Document::Subject: as.addValue(factory->subjectField, it.value().toUtf8().data() ); break;
case Mobipocket::Document::Copyright: as.addValue(factory->copyrightField, it.value().toUtf8().data() ); break;
}
}
return 0;
}
class Factory : public AnalyzerFactoryFactory
{
public:
std::list<StreamEndAnalyzerFactory*>
streamEndAnalyzerFactories() const {
std::list<StreamEndAnalyzerFactory*> af;
af.push_back(new MobiEndAnalyzerFactory());
return af;
}
};
STRIGI_ANALYZER_FACTORY(Factory)
/***************************************************************************
* 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. *
***************************************************************************/
#ifndef MOBIENDANALYZER
#define MOBIENDANALYZER
#include <strigi/streamendanalyzer.h>
#include <strigi/streambase.h>
class MobiEndAnalyzerFactory;
class MobiEndAnalyzer : public Strigi::StreamEndAnalyzer {
private:
const MobiEndAnalyzerFactory* factory;
bool checkHeader(const char* header, int32_t headersize) const;
signed char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
const char* name() const { return "MobiEndAnalyzer"; }
public:
MobiEndAnalyzer(const MobiEndAnalyzerFactory* f);
};
class MobiEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
friend class MobiEndAnalyzer;
private:
const Strigi::RegisteredField* titleField;
const Strigi::RegisteredField* authorField;
const Strigi::RegisteredField* copyrightField;
const Strigi::RegisteredField* subjectField;
const Strigi::RegisteredField* descriptionField;
const Strigi::RegisteredField* encryptedField;
// const Strigi::RegisteredField* typeField;
const char* name() const {
return "MobiEndAnalyzer";
}
Strigi::StreamEndAnalyzer* newInstance() const {
return new MobiEndAnalyzer(this);
}
void registerFields(Strigi::FieldRegister&);
};
#endif
......@@ -18,11 +18,29 @@
namespace Mobipocket {
QByteArray Stream::read(int len)
{
QByteArray ret;
ret.resize(len);
len=read(ret.data(),len);
if (len<0) len=0;
ret.resize(len);
return ret;
}
QByteArray Stream::readAll()
{
QByteArray ret, bit;
while (!(bit=read(4096)).isEmpty()) ret+=bit;
return ret;
}
struct PDBPrivate {
QList<quint32> recordOffsets;
QIODevice* device;
Stream* device;
QString fileType;
QString name;
quint16 nrecords;
bool valid;
......@@ -34,8 +52,6 @@ void PDBPrivate::init()
valid=true;
quint16 word;
quint32 dword;
device->seek(0);
name=QString::fromLatin1(device->read(32));
device->seek(0x3c);
fileType=QString::fromLatin1(device->read(8));
......@@ -50,7 +66,7 @@ void PDBPrivate::init()
}
}
PDB::PDB(QIODevice* dev) : d(new PDBPrivate)
PDB::PDB(Stream* dev) : d(new PDBPrivate)
{
d->device=dev;
d->init();
......@@ -61,16 +77,9 @@ QByteArray PDB::getRecord(int i) const
if (i>=d->nrecords) return QByteArray();
quint32 offset=d->recordOffsets[i];
bool last=(i==(d->nrecords-1));
quint32 size=0;
if (last) size=d->device->size()-offset;
else size=d->recordOffsets[i+1]-offset;
d->device->seek(offset);
return d->device->read(size);
}
QString PDB::name() const
{
return d->name;
if (last) return d->device->readAll();
return d->device->read(d->recordOffsets[i+1]-offset);
}
bool PDB::isValid() const
......@@ -86,7 +95,7 @@ int PDB::recordCount() const
////////////////////////////////////////////
struct DocumentPrivate
{
DocumentPrivate(QIODevice* d) : pdb(d), valid(true), firstImageRecord(0), isUtf(false),
DocumentPrivate(Stream* d) : pdb(d), valid(true), firstImageRecord(0), isUtf(false),
drm(false), thumbnailIndex(0) {}
PDB pdb;
Decompressor* dec;
......@@ -224,7 +233,7 @@ void DocumentPrivate::parseEXTH(const QByteArray& data)
}
Document::Document(QIODevice* dev) : d(new DocumentPrivate(dev))
Document::Document(Stream* dev) : d(new DocumentPrivate(dev))
{
d->init();
}
......
......@@ -19,15 +19,27 @@ class QIODevice;
namespace Mobipocket {
struct PDBPrivate;
/**
Minimalistic stream abstraction. It is supposed to allow mobipocket document classes to be
used with both QIODevice (for Okular generator) and InputStream for Strigi analyzer.
*/
class Stream {
public:
virtual int read(char* buf, int size)=0;
virtual void seek(int pos)=0;
QByteArray readAll();
QByteArray read(int len);
virtual ~Stream() {}
};
struct PDBPrivate;
class PDB {
public:
PDB(QIODevice* dev);
PDB(Stream* s);
QString fileType() const;
int recordCount() const;
QByteArray getRecord(int i) const;
QString name() const;
bool isValid() const;
private:
PDBPrivate* const d;
......@@ -37,7 +49,7 @@ struct DocumentPrivate;
class Document {
public:
enum MetaKey { Title, Author, Copyright, Description, Subject };
Document(QIODevice* dev);
Document(Stream* s);
QMap<MetaKey,QString> metadata() const;
QString text() const;
int imageCount() const;
......
......@@ -9,6 +9,7 @@
#include "mobithumbnail.h"
#include "mobipocket.h"
#include "qfilestream.h"
#include <QtCore/QFile>
......@@ -22,8 +23,7 @@ extern "C"
bool MobiThumbnail::create(const QString &path, int width, int height, QImage &img)
{
QFile f(path);
f.open(QIODevice::ReadOnly);
Mobipocket::QFileStream f(path);
Mobipocket::Document doc(&f);
if (!doc.isValid()) return false;
img=doc.thumbnail();
......
/***************************************************************************
* 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. *
***************************************************************************/
#ifndef QFILESTREAM_H
#define QFILESTREAM_H
#include <QtCore/QFile>
#include "mobipocket.h"
namespace Mobipocket {
class QFileStream : public Stream
{
public:
QFileStream(const QString& name) : d(name) { d.open(QIODevice::ReadOnly); }
int read(char* buf, int size) { return d.read(buf,size); }
void seek(int pos) { d.seek(pos); }
private:
QFile d;
};
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment