summaryrefslogtreecommitdiffstats
path: root/fbreader/src/formats/oeb
diff options
context:
space:
mode:
authorMichele Calgaro <[email protected]>2024-05-11 21:28:48 +0900
committerMichele Calgaro <[email protected]>2024-05-11 21:28:48 +0900
commit2462d03f322261bd616721c2b2065c4004b36c9c (patch)
tree239947a0737bb8386703a1497f12c09aebd3080a /fbreader/src/formats/oeb
downloadtde-ebook-reader-2462d03f322261bd616721c2b2065c4004b36c9c.tar.gz
tde-ebook-reader-2462d03f322261bd616721c2b2065c4004b36c9c.zip
Initial import (as is) from Debian Snapshot's 'fbreader' source code (https://snapshot.debian.org/package/fbreader/0.99.4%2Bdfsg-6).
The Debian code is provided under GPL2 license. Signed-off-by: Michele Calgaro <[email protected]>
Diffstat (limited to 'fbreader/src/formats/oeb')
-rw-r--r--fbreader/src/formats/oeb/NCXReader.cpp131
-rw-r--r--fbreader/src/formats/oeb/NCXReader.h69
-rw-r--r--fbreader/src/formats/oeb/OEBBookReader.cpp273
-rw-r--r--fbreader/src/formats/oeb/OEBBookReader.h70
-rw-r--r--fbreader/src/formats/oeb/OEBCoverReader.cpp136
-rw-r--r--fbreader/src/formats/oeb/OEBCoverReader.h56
-rw-r--r--fbreader/src/formats/oeb/OEBMetaInfoReader.cpp194
-rw-r--r--fbreader/src/formats/oeb/OEBMetaInfoReader.h63
-rw-r--r--fbreader/src/formats/oeb/OEBPlugin.cpp149
-rw-r--r--fbreader/src/formats/oeb/OEBPlugin.h40
-rw-r--r--fbreader/src/formats/oeb/OEBTextStream.cpp101
-rw-r--r--fbreader/src/formats/oeb/OEBTextStream.h43
-rw-r--r--fbreader/src/formats/oeb/XHTMLImageFinder.cpp54
-rw-r--r--fbreader/src/formats/oeb/XHTMLImageFinder.h43
14 files changed, 1422 insertions, 0 deletions
diff --git a/fbreader/src/formats/oeb/NCXReader.cpp b/fbreader/src/formats/oeb/NCXReader.cpp
new file mode 100644
index 0000000..e824e16
--- /dev/null
+++ b/fbreader/src/formats/oeb/NCXReader.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <cstdlib>
+
+#include "NCXReader.h"
+#include "../util/MiscUtil.h"
+#include "../util/EntityFilesCollector.h"
+
+NCXReader::NCXReader(BookReader &modelReader) : myModelReader(modelReader), myReadState(READ_NONE), myPlayIndex(-65535) {
+}
+
+static const std::string TAG_NAVMAP = "navMap";
+static const std::string TAG_NAVPOINT = "navPoint";
+static const std::string TAG_NAVLABEL = "navLabel";
+static const std::string TAG_CONTENT = "content";
+static const std::string TAG_TEXT = "text";
+
+void NCXReader::startElementHandler(const char *fullTag, const char **attributes) {
+ std::string tag = fullTag;
+ const std::size_t index = tag.rfind(':');
+ if (index != std::string::npos) {
+ tag = tag.substr(index + 1);
+ }
+ switch (myReadState) {
+ case READ_NONE:
+ if (TAG_NAVMAP == tag) {
+ myReadState = READ_MAP;
+ }
+ break;
+ case READ_MAP:
+ if (TAG_NAVPOINT == tag) {
+ const char *order = attributeValue(attributes, "playOrder");
+ myPointStack.push_back(NavPoint(order != 0 ? std::atoi(order) : myPlayIndex++, myPointStack.size()));
+ myReadState = READ_POINT;
+ }
+ break;
+ case READ_POINT:
+ if (TAG_NAVPOINT == tag) {
+ const char *order = attributeValue(attributes, "playOrder");
+ myPointStack.push_back(NavPoint(order != 0 ? std::atoi(order) : myPlayIndex++, myPointStack.size()));
+ } else if (TAG_NAVLABEL == tag) {
+ myReadState = READ_LABEL;
+ } else if (TAG_CONTENT == tag) {
+ const char *src = attributeValue(attributes, "src");
+ if (src != 0) {
+ myPointStack.back().ContentHRef = MiscUtil::decodeHtmlURL(src);
+ }
+ }
+ break;
+ case READ_LABEL:
+ if (TAG_TEXT == tag) {
+ myReadState = READ_TEXT;
+ }
+ break;
+ case READ_TEXT:
+ break;
+ }
+}
+
+void NCXReader::endElementHandler(const char *fullTag) {
+ std::string tag = fullTag;
+ const std::size_t index = tag.rfind(':');
+ if (index != std::string::npos) {
+ tag = tag.substr(index + 1);
+ }
+ switch (myReadState) {
+ case READ_NONE:
+ break;
+ case READ_MAP:
+ if (TAG_NAVMAP == tag) {
+ myReadState = READ_NONE;
+ }
+ break;
+ case READ_POINT:
+ if (TAG_NAVPOINT == tag) {
+ if (myPointStack.back().Text.empty()) {
+ myPointStack.back().Text = "...";
+ }
+ myNavigationMap[myPointStack.back().Order] = myPointStack.back();
+ myPointStack.pop_back();
+ myReadState = myPointStack.empty() ? READ_MAP : READ_POINT;
+ }
+ case READ_LABEL:
+ if (TAG_NAVLABEL == tag) {
+ myReadState = READ_POINT;
+ }
+ break;
+ case READ_TEXT:
+ if (TAG_TEXT == tag) {
+ myReadState = READ_LABEL;
+ }
+ break;
+ }
+}
+
+void NCXReader::characterDataHandler(const char *text, std::size_t len) {
+ if (myReadState == READ_TEXT) {
+ myPointStack.back().Text.append(text, len);
+ }
+}
+
+const std::vector<std::string> &NCXReader::externalDTDs() const {
+ return EntityFilesCollector::Instance().externalDTDs("xhtml");
+}
+
+const std::map<int,NCXReader::NavPoint> &NCXReader::navigationMap() const {
+ return myNavigationMap;
+}
+
+NCXReader::NavPoint::NavPoint() {
+}
+
+NCXReader::NavPoint::NavPoint(int order, std::size_t level) : Order(order), Level(level) {
+}
diff --git a/fbreader/src/formats/oeb/NCXReader.h b/fbreader/src/formats/oeb/NCXReader.h
new file mode 100644
index 0000000..c10d2ab
--- /dev/null
+++ b/fbreader/src/formats/oeb/NCXReader.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __NCXREADER_H__
+#define __NCXREADER_H__
+
+#include <map>
+#include <vector>
+
+#include <ZLXMLReader.h>
+
+#include "../../bookmodel/BookReader.h"
+
+class NCXReader : public ZLXMLReader {
+
+public:
+ struct NavPoint {
+ NavPoint();
+ NavPoint(int order, std::size_t level);
+
+ int Order;
+ std::size_t Level;
+ std::string Text;
+ std::string ContentHRef;
+ };
+
+public:
+ NCXReader(BookReader &modelReader);
+ const std::map<int,NavPoint> &navigationMap() const;
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+ void characterDataHandler(const char *text, std::size_t len);
+ const std::vector<std::string> &externalDTDs() const;
+
+private:
+ BookReader &myModelReader;
+ std::map<int,NavPoint> myNavigationMap;
+ std::vector<NavPoint> myPointStack;
+
+ enum {
+ READ_NONE,
+ READ_MAP,
+ READ_POINT,
+ READ_LABEL,
+ READ_TEXT
+ } myReadState;
+
+ int myPlayIndex;
+};
+
+#endif /* __NCXREADER_H__ */
diff --git a/fbreader/src/formats/oeb/OEBBookReader.cpp b/fbreader/src/formats/oeb/OEBBookReader.cpp
new file mode 100644
index 0000000..c4234a7
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBBookReader.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <algorithm>
+
+#include <ZLStringUtil.h>
+#include <ZLUnicodeUtil.h>
+#include <ZLFile.h>
+#include <ZLFileImage.h>
+#include <ZLXMLNamespace.h>
+
+#include "OEBBookReader.h"
+#include "XHTMLImageFinder.h"
+#include "NCXReader.h"
+#include "../xhtml/XHTMLReader.h"
+#include "../util/MiscUtil.h"
+#include "../util/EntityFilesCollector.h"
+#include "../../bookmodel/BookModel.h"
+
+OEBBookReader::OEBBookReader(BookModel &model) : myModelReader(model) {
+}
+
+static const std::string MANIFEST = "manifest";
+static const std::string SPINE = "spine";
+static const std::string GUIDE = "guide";
+static const std::string TOUR = "tour";
+static const std::string SITE = "site";
+
+static const std::string ITEM = "item";
+static const std::string ITEMREF = "itemref";
+static const std::string REFERENCE = "reference";
+
+static const std::string COVER = "cover";
+static const std::string COVER_IMAGE = "other.ms-coverimage-standard";
+
+bool OEBBookReader::isOPFTag(const std::string &expected, const std::string &tag) const {
+ return expected == tag || testTag(ZLXMLNamespace::OpenPackagingFormat, expected, tag);
+}
+
+void OEBBookReader::startElementHandler(const char *tag, const char **xmlattributes) {
+ std::string tagString = ZLUnicodeUtil::toLower(tag);
+
+ switch (myState) {
+ case READ_NONE:
+ if (isOPFTag(MANIFEST, tagString)) {
+ myState = READ_MANIFEST;
+ } else if (isOPFTag(SPINE, tagString)) {
+ const char *toc = attributeValue(xmlattributes, "toc");
+ if (toc != 0) {
+ myNCXTOCFileName = myIdToHref[toc];
+ }
+ myState = READ_SPINE;
+ } else if (isOPFTag(GUIDE, tagString)) {
+ myState = READ_GUIDE;
+ } else if (isOPFTag(TOUR, tagString)) {
+ myState = READ_TOUR;
+ }
+ break;
+ case READ_MANIFEST:
+ if (isOPFTag(ITEM, tagString)) {
+ const char *href = attributeValue(xmlattributes, "href");
+ if (href != 0) {
+ const std::string sHref = MiscUtil::decodeHtmlURL(href);
+ const char *id = attributeValue(xmlattributes, "id");
+ const char *mediaType = attributeValue(xmlattributes, "media-type");
+ if (id != 0) {
+ myIdToHref[id] = sHref;
+ }
+ if (mediaType != 0) {
+ myHrefToMediatype[sHref] = mediaType;
+ }
+ }
+ }
+ break;
+ case READ_SPINE:
+ if (isOPFTag(ITEMREF, tagString)) {
+ const char *id = attributeValue(xmlattributes, "idref");
+ if (id != 0) {
+ const std::string &fileName = myIdToHref[id];
+ if (!fileName.empty()) {
+ myHtmlFileNames.push_back(fileName);
+ }
+ }
+ }
+ break;
+ case READ_GUIDE:
+ if (isOPFTag(REFERENCE, tagString)) {
+ const char *type = attributeValue(xmlattributes, "type");
+ const char *title = attributeValue(xmlattributes, "title");
+ const char *href = attributeValue(xmlattributes, "href");
+ if (href != 0) {
+ const std::string reference = MiscUtil::decodeHtmlURL(href);
+ if (title != 0) {
+ myGuideTOC.push_back(std::make_pair(std::string(title), reference));
+ }
+ if (type != 0) {
+ if (COVER == type) {
+ ZLFile imageFile(myFilePrefix + reference);
+ myCoverFileName = imageFile.path();
+ const std::map<std::string,std::string>::const_iterator it =
+ myHrefToMediatype.find(reference);
+ const std::string mimeType =
+ it != myHrefToMediatype.end() ? it->second : std::string();
+ shared_ptr<const ZLImage> image;
+ if (ZLStringUtil::stringStartsWith(mimeType, "image/")) {
+ image = new ZLFileImage(imageFile, 0);
+ } else {
+ image = XHTMLImageFinder().readImage(imageFile);
+ }
+ if (!image.isNull()) {
+ const std::string imageName = imageFile.name(false);
+ myModelReader.setMainTextModel();
+ myModelReader.addImageReference(imageName, 0);
+ myModelReader.addImage(imageName, image);
+ myModelReader.insertEndOfSectionParagraph();
+ } else {
+ myCoverFileName.erase();
+ }
+ } else if (COVER_IMAGE == type) {
+ ZLFile imageFile(myFilePrefix + reference);
+ myCoverFileName = imageFile.path();
+ const std::string imageName = imageFile.name(false);
+ myModelReader.setMainTextModel();
+ myModelReader.addImageReference(imageName, 0);
+ myModelReader.addImage(imageName, new ZLFileImage(imageFile, 0));
+ myModelReader.insertEndOfSectionParagraph();
+ }
+ }
+ }
+ }
+ break;
+ case READ_TOUR:
+ if (isOPFTag(SITE, tagString)) {
+ const char *title = attributeValue(xmlattributes, "title");
+ const char *href = attributeValue(xmlattributes, "href");
+ if ((title != 0) && (href != 0)) {
+ myTourTOC.push_back(std::make_pair(title, MiscUtil::decodeHtmlURL(href)));
+ }
+ }
+ break;
+ }
+}
+
+void OEBBookReader::endElementHandler(const char *tag) {
+ std::string tagString = ZLUnicodeUtil::toLower(tag);
+
+ switch (myState) {
+ case READ_MANIFEST:
+ if (isOPFTag(MANIFEST, tagString)) {
+ myState = READ_NONE;
+ }
+ break;
+ case READ_SPINE:
+ if (isOPFTag(SPINE, tagString)) {
+ myState = READ_NONE;
+ }
+ break;
+ case READ_GUIDE:
+ if (isOPFTag(GUIDE, tagString)) {
+ myState = READ_NONE;
+ }
+ break;
+ case READ_TOUR:
+ if (isOPFTag(TOUR, tagString)) {
+ myState = READ_NONE;
+ }
+ break;
+ case READ_NONE:
+ break;
+ }
+}
+
+bool OEBBookReader::readBook(const ZLFile &file) {
+ myFilePrefix = MiscUtil::htmlDirectoryPrefix(file.path());
+
+ myIdToHref.clear();
+ myHtmlFileNames.clear();
+ myNCXTOCFileName.erase();
+ myCoverFileName.erase();
+ myTourTOC.clear();
+ myGuideTOC.clear();
+ myState = READ_NONE;
+
+ if (!readDocument(file)) {
+ return false;
+ }
+
+ myModelReader.setMainTextModel();
+ myModelReader.pushKind(REGULAR);
+
+ XHTMLReader xhtmlReader(myModelReader);
+ bool firstFile = true;
+ for (std::vector<std::string>::const_iterator it = myHtmlFileNames.begin(); it != myHtmlFileNames.end(); ++it) {
+ const ZLFile xhtmlFile(myFilePrefix + *it);
+ if (firstFile && myCoverFileName == xhtmlFile.path()) {
+ continue;
+ }
+ if (!firstFile) {
+ myModelReader.insertEndOfSectionParagraph();
+ }
+ xhtmlReader.readFile(xhtmlFile, *it);
+ firstFile = false;
+ }
+
+ generateTOC(xhtmlReader);
+
+ return true;
+}
+
+void OEBBookReader::generateTOC(const XHTMLReader &xhtmlReader) {
+ if (!myNCXTOCFileName.empty()) {
+ NCXReader ncxReader(myModelReader);
+ if (ncxReader.readDocument(ZLFile(myFilePrefix + myNCXTOCFileName))) {
+ const std::map<int,NCXReader::NavPoint> navigationMap = ncxReader.navigationMap();
+ if (!navigationMap.empty()) {
+ std::size_t level = 0;
+ for (std::map<int,NCXReader::NavPoint>::const_iterator it = navigationMap.begin(); it != navigationMap.end(); ++it) {
+ const NCXReader::NavPoint &point = it->second;
+ int index = myModelReader.model().label(xhtmlReader.normalizedReference(point.ContentHRef)).ParagraphNumber;
+ while (level > point.Level) {
+ myModelReader.endContentsParagraph();
+ --level;
+ }
+ while (++level <= point.Level) {
+ myModelReader.beginContentsParagraph(-2);
+ myModelReader.addContentsData("...");
+ }
+ myModelReader.beginContentsParagraph(index);
+ myModelReader.addContentsData(point.Text);
+ }
+ while (level > 0) {
+ myModelReader.endContentsParagraph();
+ --level;
+ }
+ return;
+ }
+ }
+ }
+
+ std::vector<std::pair<std::string,std::string> > &toc = myTourTOC.empty() ? myGuideTOC : myTourTOC;
+ for (std::vector<std::pair<std::string,std::string> >::const_iterator it = toc.begin(); it != toc.end(); ++it) {
+ int index = myModelReader.model().label(it->second).ParagraphNumber;
+ if (index != -1) {
+ myModelReader.beginContentsParagraph(index);
+ myModelReader.addContentsData(it->first);
+ myModelReader.endContentsParagraph();
+ }
+ }
+}
+
+bool OEBBookReader::processNamespaces() const {
+ return true;
+}
+
+const std::vector<std::string> &OEBBookReader::externalDTDs() const {
+ return EntityFilesCollector::Instance().externalDTDs("xhtml");
+}
diff --git a/fbreader/src/formats/oeb/OEBBookReader.h b/fbreader/src/formats/oeb/OEBBookReader.h
new file mode 100644
index 0000000..092f269
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBBookReader.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __OEBBOOKREADER_H__
+#define __OEBBOOKREADER_H__
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include <ZLXMLReader.h>
+
+#include "../../bookmodel/BookReader.h"
+
+class XHTMLReader;
+
+class OEBBookReader : public ZLXMLReader {
+
+public:
+ OEBBookReader(BookModel &model);
+ bool readBook(const ZLFile &file);
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+ bool processNamespaces() const;
+ bool isOPFTag(const std::string &expected, const std::string &tag) const;
+ const std::vector<std::string> &externalDTDs() const;
+
+ void generateTOC(const XHTMLReader &xhtmlReader);
+
+private:
+ enum ReaderState {
+ READ_NONE,
+ READ_MANIFEST,
+ READ_SPINE,
+ READ_GUIDE,
+ READ_TOUR
+ };
+
+ BookReader myModelReader;
+ ReaderState myState;
+
+ std::string myFilePrefix;
+ std::map<std::string,std::string> myIdToHref;
+ std::map<std::string,std::string> myHrefToMediatype;
+ std::vector<std::string> myHtmlFileNames;
+ std::string myNCXTOCFileName;
+ std::string myCoverFileName;
+ std::vector<std::pair<std::string,std::string> > myTourTOC;
+ std::vector<std::pair<std::string,std::string> > myGuideTOC;
+};
+
+#endif /* __OEBBOOKREADER_H__ */
diff --git a/fbreader/src/formats/oeb/OEBCoverReader.cpp b/fbreader/src/formats/oeb/OEBCoverReader.cpp
new file mode 100644
index 0000000..842de30
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBCoverReader.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <ZLFile.h>
+#include <ZLFileImage.h>
+#include <ZLXMLNamespace.h>
+
+#include "OEBCoverReader.h"
+#include "XHTMLImageFinder.h"
+
+#include "../util/MiscUtil.h"
+
+OEBCoverReader::OEBCoverReader() {
+}
+
+shared_ptr<const ZLImage> OEBCoverReader::readCover(const ZLFile &file) {
+ myPathPrefix = MiscUtil::htmlDirectoryPrefix(file.path());
+ myReadState = READ_NOTHING;
+ myImage.reset();
+ myCoverXHTML.erase();
+ readDocument(file);
+ if (myImage.isNull() && !myCoverXHTML.empty()) {
+ const ZLFile coverFile(myCoverXHTML);
+ const std::string ext = coverFile.extension();
+ if (ext == "gif" || ext == "jpeg" || ext == "jpg") {
+ myImage = new ZLFileImage(coverFile, 0);
+ } else {
+ myImage = XHTMLImageFinder().readImage(coverFile);
+ }
+ }
+ return myImage;
+}
+
+static const std::string METADATA = "metadata";
+static const std::string META = "meta";
+static const std::string MANIFEST = "manifest";
+static const std::string ITEM = "item";
+static const std::string GUIDE = "guide";
+static const std::string REFERENCE = "reference";
+static const std::string COVER = "cover";
+static const std::string COVER_IMAGE = "other.ms-coverimage-standard";
+
+bool OEBCoverReader::processNamespaces() const {
+ return true;
+}
+
+void OEBCoverReader::startElementHandler(const char *tag, const char **attributes) {
+ switch (myReadState) {
+ case READ_NOTHING:
+ if (GUIDE == tag) {
+ myReadState = READ_GUIDE;
+ } else if (MANIFEST == tag && !myCoverId.empty()) {
+ myReadState = READ_MANIFEST;
+ } else if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tag)) {
+ myReadState = READ_METADATA;
+ }
+ break;
+ case READ_GUIDE:
+ if (REFERENCE == tag) {
+ const char *type = attributeValue(attributes, "type");
+ if (type != 0) {
+ if (COVER == type) {
+ const char *href = attributeValue(attributes, "href");
+ if (href != 0) {
+ myCoverXHTML = myPathPrefix + MiscUtil::decodeHtmlURL(href);
+ interrupt();
+ }
+ } else if (COVER_IMAGE == type) {
+ createImage(attributeValue(attributes, "href"));
+ }
+ }
+ }
+ break;
+ case READ_METADATA:
+ if (testTag(ZLXMLNamespace::OpenPackagingFormat, META, tag)) {
+ const char *name = attributeValue(attributes, "name");
+ if (name != 0 && COVER == name) {
+ myCoverId = attributeValue(attributes, "content");
+ }
+ }
+ break;
+ case READ_MANIFEST:
+ if (ITEM == tag) {
+ const char *id = attributeValue(attributes, "id");
+ if (id != 0 && myCoverId == id) {
+ createImage(attributeValue(attributes, "href"));
+ }
+ }
+ break;
+ }
+}
+
+void OEBCoverReader::createImage(const char *href) {
+ if (href != 0) {
+ myImage = new ZLFileImage(ZLFile(myPathPrefix + MiscUtil::decodeHtmlURL(href)), 0);
+ interrupt();
+ }
+}
+
+void OEBCoverReader::endElementHandler(const char *tag) {
+ switch (myReadState) {
+ case READ_NOTHING:
+ break;
+ case READ_GUIDE:
+ if (GUIDE == tag) {
+ myReadState = READ_NOTHING;
+ }
+ break;
+ case READ_METADATA:
+ if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tag)) {
+ myReadState = READ_NOTHING;
+ }
+ break;
+ case READ_MANIFEST:
+ if (MANIFEST == tag) {
+ myReadState = READ_NOTHING;
+ }
+ break;
+ }
+}
diff --git a/fbreader/src/formats/oeb/OEBCoverReader.h b/fbreader/src/formats/oeb/OEBCoverReader.h
new file mode 100644
index 0000000..e1f96b5
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBCoverReader.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __OEBCOVERREADER_H__
+#define __OEBCOVERREADER_H__
+
+#include <vector>
+
+#include <shared_ptr.h>
+#include <ZLXMLReader.h>
+
+class ZLImage;
+
+class OEBCoverReader : public ZLXMLReader {
+
+public:
+ OEBCoverReader();
+ shared_ptr<const ZLImage> readCover(const ZLFile &file);
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+ bool processNamespaces() const;
+
+ void createImage(const char *href);
+
+private:
+ shared_ptr<const ZLImage> myImage;
+ std::string myPathPrefix;
+ std::string myCoverXHTML;
+ std::string myCoverId;
+ enum {
+ READ_NOTHING,
+ READ_METADATA,
+ READ_MANIFEST,
+ READ_GUIDE
+ } myReadState;
+};
+
+#endif /* __OEBCOVERREADER_H__ */
diff --git a/fbreader/src/formats/oeb/OEBMetaInfoReader.cpp b/fbreader/src/formats/oeb/OEBMetaInfoReader.cpp
new file mode 100644
index 0000000..f9eb82d
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBMetaInfoReader.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <cstdlib>
+
+#include <ZLStringUtil.h>
+#include <ZLUnicodeUtil.h>
+#include <ZLLogger.h>
+#include <ZLXMLNamespace.h>
+
+#include "OEBMetaInfoReader.h"
+#include "../util/EntityFilesCollector.h"
+
+#include "../../library/Book.h"
+
+OEBMetaInfoReader::OEBMetaInfoReader(Book &book) : myBook(book) {
+ myBook.removeAllAuthors();
+ myBook.setTitle("");
+ myBook.removeAllTags();
+}
+
+static const std::string METADATA = "metadata";
+static const std::string DC_METADATA = "dc-metadata";
+static const std::string META = "meta";
+static const std::string AUTHOR_ROLE = "aut";
+
+void OEBMetaInfoReader::characterDataHandler(const char *text, std::size_t len) {
+ switch (myReadState) {
+ case READ_NONE:
+ case READ_METADATA:
+ break;
+ case READ_AUTHOR:
+ case READ_AUTHOR2:
+ case READ_SUBJECT:
+ case READ_LANGUAGE:
+ case READ_TITLE:
+ myBuffer.append(text, len);
+ break;
+ }
+}
+
+bool OEBMetaInfoReader::testDCTag(const std::string &name, const std::string &tag) const {
+ return
+ testTag(ZLXMLNamespace::DublinCore, name, tag) ||
+ testTag(ZLXMLNamespace::DublinCoreLegacy, name, tag);
+}
+
+bool OEBMetaInfoReader::isNSName(const std::string &fullName, const std::string &shortName, const std::string &fullNSId) const {
+ const int prefixLength = fullName.length() - shortName.length() - 1;
+ if (prefixLength <= 0 ||
+ fullName[prefixLength] != ':' ||
+ !ZLStringUtil::stringEndsWith(fullName, shortName)) {
+ return false;
+ }
+ const std::map<std::string,std::string> &namespaceMap = namespaces();
+ std::map<std::string,std::string>::const_iterator iter =
+ namespaceMap.find(fullName.substr(0, prefixLength));
+ return iter != namespaceMap.end() && iter->second == fullNSId;
+}
+
+void OEBMetaInfoReader::startElementHandler(const char *tag, const char **attributes) {
+ const std::string tagString = ZLUnicodeUtil::toLower(tag);
+ switch (myReadState) {
+ default:
+ break;
+ case READ_NONE:
+ if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tagString) ||
+ DC_METADATA == tagString) {
+ myReadState = READ_METADATA;
+ }
+ break;
+ case READ_METADATA:
+ if (testDCTag("title", tagString)) {
+ myReadState = READ_TITLE;
+ } else if (testDCTag("creator", tagString)) {
+ const char *role = attributeValue(attributes, "role");
+ if (role == 0) {
+ myReadState = READ_AUTHOR2;
+ } else if (AUTHOR_ROLE == role) {
+ myReadState = READ_AUTHOR;
+ }
+ } else if (testDCTag("subject", tagString)) {
+ myReadState = READ_SUBJECT;
+ } else if (testDCTag("language", tagString)) {
+ myReadState = READ_LANGUAGE;
+ } else if (testTag(ZLXMLNamespace::OpenPackagingFormat, META, tagString)) {
+ const char *name = attributeValue(attributes, "name");
+ const char *content = attributeValue(attributes, "content");
+ if (name != 0 && content != 0) {
+ std::string sName = name;
+ if (sName == "calibre:series" || isNSName(sName, "series", ZLXMLNamespace::CalibreMetadata)) {
+ myBook.setSeries(content, myBook.indexInSeries());
+ } else if (sName == "calibre:series_index" || isNSName(sName, "series_index", ZLXMLNamespace::CalibreMetadata)) {
+ myBook.setSeries(myBook.seriesTitle(), std::string(content));
+ }
+ }
+ }
+ break;
+ }
+}
+
+void OEBMetaInfoReader::endElementHandler(const char *tag) {
+ const std::string tagString = ZLUnicodeUtil::toLower(tag);
+ ZLUnicodeUtil::utf8Trim(myBuffer);
+ switch (myReadState) {
+ case READ_NONE:
+ break;
+ case READ_METADATA:
+ if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tagString) || DC_METADATA == tagString) {
+ interrupt();
+ myReadState = READ_NONE;
+ return;
+ }
+ break;
+ case READ_AUTHOR:
+ if (!myBuffer.empty()) {
+ myAuthorList.push_back(myBuffer);
+ }
+ break;
+ case READ_AUTHOR2:
+ if (!myBuffer.empty()) {
+ myAuthorList2.push_back(myBuffer);
+ }
+ break;
+ case READ_SUBJECT:
+ if (!myBuffer.empty()) {
+ myBook.addTag(myBuffer);
+ }
+ break;
+ case READ_TITLE:
+ if (!myBuffer.empty()) {
+ myBook.setTitle(myBuffer);
+ }
+ break;
+ case READ_LANGUAGE:
+ if (!myBuffer.empty()) {
+ int index = myBuffer.find('-');
+ if (index >= 0) {
+ myBuffer = myBuffer.substr(0, index);
+ }
+ index = myBuffer.find('_');
+ if (index >= 0) {
+ myBuffer = myBuffer.substr(0, index);
+ }
+ myBook.setLanguage(myBuffer);
+ }
+ break;
+ }
+ myBuffer.erase();
+ myReadState = READ_METADATA;
+}
+
+bool OEBMetaInfoReader::processNamespaces() const {
+ return true;
+}
+
+bool OEBMetaInfoReader::readMetaInfo(const ZLFile &file) {
+ myReadState = READ_NONE;
+ if (!readDocument(file)) {
+ ZLLogger::Instance().println("epub", "Failure while reading info from " + file.path());
+ return false;
+ }
+
+ if (!myAuthorList.empty()) {
+ for (std::vector<std::string>::const_iterator it = myAuthorList.begin(); it != myAuthorList.end(); ++it) {
+ myBook.addAuthor(*it);
+ }
+ } else {
+ for (std::vector<std::string>::const_iterator it = myAuthorList2.begin(); it != myAuthorList2.end(); ++it) {
+ myBook.addAuthor(*it);
+ }
+ }
+ return true;
+}
+
+const std::vector<std::string> &OEBMetaInfoReader::externalDTDs() const {
+ return EntityFilesCollector::Instance().externalDTDs("xhtml");
+}
diff --git a/fbreader/src/formats/oeb/OEBMetaInfoReader.h b/fbreader/src/formats/oeb/OEBMetaInfoReader.h
new file mode 100644
index 0000000..2337c50
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBMetaInfoReader.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __OEBMETAINFOREADER_H__
+#define __OEBMETAINFOREADER_H__
+
+#include <vector>
+
+#include <ZLXMLReader.h>
+
+class Book;
+
+class OEBMetaInfoReader : public ZLXMLReader {
+
+public:
+ OEBMetaInfoReader(Book &book);
+ bool readMetaInfo(const ZLFile &file);
+
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+ void characterDataHandler(const char *text, std::size_t len);
+ bool processNamespaces() const;
+ const std::vector<std::string> &externalDTDs() const;
+
+private:
+ bool testDCTag(const std::string &name, const std::string &tag) const;
+ bool isNSName(const std::string &fullName, const std::string &shortName, const std::string &fullNSId) const;
+
+private:
+ Book &myBook;
+
+ enum {
+ READ_NONE,
+ READ_METADATA,
+ READ_AUTHOR,
+ READ_AUTHOR2,
+ READ_TITLE,
+ READ_SUBJECT,
+ READ_LANGUAGE,
+ } myReadState;
+
+ std::string myBuffer;
+ std::vector<std::string> myAuthorList;
+ std::vector<std::string> myAuthorList2;
+};
+
+#endif /* __OEBMETAINFOREADER_H__ */
diff --git a/fbreader/src/formats/oeb/OEBPlugin.cpp b/fbreader/src/formats/oeb/OEBPlugin.cpp
new file mode 100644
index 0000000..96970c1
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBPlugin.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <ZLFile.h>
+#include <ZLImage.h>
+#include <ZLStringUtil.h>
+#include <ZLUnicodeUtil.h>
+#include <ZLDir.h>
+#include <ZLInputStream.h>
+#include <ZLLogger.h>
+#include <ZLMimeType.h>
+
+#include "OEBPlugin.h"
+#include "OEBMetaInfoReader.h"
+#include "OEBBookReader.h"
+#include "OEBCoverReader.h"
+#include "OEBTextStream.h"
+#include "../../bookmodel/BookModel.h"
+#include "../../library/Book.h"
+
+static const std::string OPF = "opf";
+static const std::string OEBZIP = "oebzip";
+static const std::string EPUB = "epub";
+
+class ContainerFileReader : public ZLXMLReader {
+
+public:
+ const std::string &rootPath() const;
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+
+private:
+ std::string myRootPath;
+};
+
+const std::string &ContainerFileReader::rootPath() const {
+ return myRootPath;
+}
+
+void ContainerFileReader::startElementHandler(const char *tag, const char **attributes) {
+ const std::string tagString = ZLUnicodeUtil::toLower(tag);
+ if (tagString == "rootfile") {
+ const char *path = attributeValue(attributes, "full-path");
+ if (path != 0) {
+ myRootPath = path;
+ interrupt();
+ }
+ }
+}
+
+OEBPlugin::~OEBPlugin() {
+}
+
+bool OEBPlugin::providesMetaInfo() const {
+ return true;
+}
+
+bool OEBPlugin::acceptsFile(const ZLFile &file) const {
+ shared_ptr<ZLMimeType> mimeType = file.mimeType();
+ const std::string &extension = file.extension();
+ if (!mimeType.isNull() && mimeType != ZLMimeType::EMPTY) {
+ return
+ mimeType == ZLMimeType::APPLICATION_EPUB_ZIP ||
+ (mimeType == ZLMimeType::APPLICATION_XML && extension == OPF) ||
+ (mimeType == ZLMimeType::APPLICATION_ZIP && extension == OEBZIP);
+ }
+ return extension == OPF || extension == OEBZIP || extension == EPUB;
+}
+
+ZLFile OEBPlugin::opfFile(const ZLFile &oebFile) {
+ //ZLLogger::Instance().registerClass("epub");
+
+ if (oebFile.extension() == OPF) {
+ return oebFile;
+ }
+
+ ZLLogger::Instance().println("epub", "Looking for opf file in " + oebFile.path());
+
+ shared_ptr<ZLDir> oebDir = oebFile.directory();
+ if (!oebDir.isNull()) {
+ const ZLFile containerInfoFile(oebDir->itemPath("META-INF/container.xml"));
+ if (containerInfoFile.exists()) {
+ ZLLogger::Instance().println("epub", "Found container file " + containerInfoFile.path());
+ ContainerFileReader reader;
+ reader.readDocument(containerInfoFile);
+ const std::string &opfPath = reader.rootPath();
+ ZLLogger::Instance().println("epub", "opf path = " + opfPath);
+ if (!opfPath.empty()) {
+ return ZLFile(oebDir->itemPath(opfPath));
+ }
+ }
+ }
+
+ oebFile.forceArchiveType(ZLFile::ZIP);
+ shared_ptr<ZLDir> zipDir = oebFile.directory(false);
+ if (zipDir.isNull()) {
+ ZLLogger::Instance().println("epub", "Couldn't open zip archive");
+ return ZLFile::NO_FILE;
+ }
+ std::vector<std::string> fileNames;
+ zipDir->collectFiles(fileNames, false);
+ for (std::vector<std::string>::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
+ ZLLogger::Instance().println("epub", "Item: " + *it);
+ if (ZLStringUtil::stringEndsWith(*it, ".opf")) {
+ return ZLFile(zipDir->itemPath(*it));
+ }
+ }
+ ZLLogger::Instance().println("epub", "Opf file not found");
+ return ZLFile::NO_FILE;
+}
+
+bool OEBPlugin::readMetaInfo(Book &book) const {
+ const ZLFile &file = book.file();
+ return OEBMetaInfoReader(book).readMetaInfo(opfFile(file));
+}
+
+bool OEBPlugin::readModel(BookModel &model) const {
+ const ZLFile &file = model.book()->file();
+ return OEBBookReader(model).readBook(opfFile(file));
+}
+
+shared_ptr<const ZLImage> OEBPlugin::coverImage(const ZLFile &file) const {
+ return OEBCoverReader().readCover(opfFile(file));
+}
+
+bool OEBPlugin::readLanguageAndEncoding(Book &book) const {
+ if (book.language().empty()) {
+ shared_ptr<ZLInputStream> oebStream = new OEBTextStream(opfFile(book.file()));
+ detectLanguage(book, *oebStream, book.encoding());
+ }
+ return true;
+}
diff --git a/fbreader/src/formats/oeb/OEBPlugin.h b/fbreader/src/formats/oeb/OEBPlugin.h
new file mode 100644
index 0000000..a515208
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBPlugin.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __OEBPLUGIN_H__
+#define __OEBPLUGIN_H__
+
+#include "../FormatPlugin.h"
+
+class OEBPlugin : public FormatPlugin {
+
+public:
+ static ZLFile opfFile(const ZLFile &oebFile);
+
+public:
+ ~OEBPlugin();
+ bool providesMetaInfo() const;
+ bool acceptsFile(const ZLFile &file) const;
+ bool readMetaInfo(Book &book) const;
+ bool readLanguageAndEncoding(Book &book) const;
+ bool readModel(BookModel &model) const;
+ shared_ptr<const ZLImage> coverImage(const ZLFile &file) const;
+};
+
+#endif /* __OEBPLUGIN_H__ */
diff --git a/fbreader/src/formats/oeb/OEBTextStream.cpp b/fbreader/src/formats/oeb/OEBTextStream.cpp
new file mode 100644
index 0000000..4dbfa47
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBTextStream.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <map>
+
+#include <ZLFile.h>
+#include <ZLXMLReader.h>
+#include <ZLUnicodeUtil.h>
+
+#include "OEBTextStream.h"
+#include "../util/MiscUtil.h"
+#include "../util/XMLTextStream.h"
+
+class XHTMLFilesCollector : public ZLXMLReader {
+
+public:
+ XHTMLFilesCollector(std::vector<std::string> &xhtmlFileNames);
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+
+private:
+ std::vector<std::string> &myXHTMLFileNames;
+ std::map<std::string,std::string> myIdToHref;
+ enum {
+ READ_NONE,
+ READ_MANIFEST,
+ READ_SPINE
+ } myState;
+};
+
+XHTMLFilesCollector::XHTMLFilesCollector(std::vector<std::string> &xhtmlFileNames) : myXHTMLFileNames(xhtmlFileNames), myState(READ_NONE) {
+}
+
+static const std::string MANIFEST = "manifest";
+static const std::string SPINE = "spine";
+static const std::string ITEM = "item";
+static const std::string ITEMREF = "itemref";
+
+void XHTMLFilesCollector::startElementHandler(const char *tag, const char **xmlattributes) {
+ const std::string tagString = ZLUnicodeUtil::toLower(tag);
+ if (MANIFEST == tagString) {
+ myState = READ_MANIFEST;
+ } else if (SPINE == tagString) {
+ myState = READ_SPINE;
+ } else if ((myState == READ_MANIFEST) && (ITEM == tagString)) {
+ const char *id = attributeValue(xmlattributes, "id");
+ const char *href = attributeValue(xmlattributes, "href");
+ if ((id != 0) && (href != 0)) {
+ myIdToHref[id] = href;
+ }
+ } else if ((myState == READ_SPINE) && (ITEMREF == tagString)) {
+ const char *id = attributeValue(xmlattributes, "idref");
+ if (id != 0) {
+ const std::string &fileName = myIdToHref[id];
+ if (!fileName.empty()) {
+ myXHTMLFileNames.push_back(fileName);
+ }
+ }
+ }
+}
+
+void XHTMLFilesCollector::endElementHandler(const char *tag) {
+ if (SPINE == ZLUnicodeUtil::toLower(tag)) {
+ interrupt();
+ }
+}
+
+OEBTextStream::OEBTextStream(const ZLFile &opfFile) {
+ myFilePrefix = MiscUtil::htmlDirectoryPrefix(opfFile.path());
+ XHTMLFilesCollector(myXHTMLFileNames).readDocument(opfFile);
+}
+
+void OEBTextStream::resetToStart() {
+ myIndex = 0;
+}
+
+shared_ptr<ZLInputStream> OEBTextStream::nextStream() {
+ if (myIndex >= myXHTMLFileNames.size()) {
+ return 0;
+ }
+ ZLFile xhtmlFile(myFilePrefix + myXHTMLFileNames[myIndex++]);
+ return new XMLTextStream(xhtmlFile.inputStream(), "body");
+}
diff --git a/fbreader/src/formats/oeb/OEBTextStream.h b/fbreader/src/formats/oeb/OEBTextStream.h
new file mode 100644
index 0000000..6ddd2c9
--- /dev/null
+++ b/fbreader/src/formats/oeb/OEBTextStream.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __OEBTEXTSTREAM_H__
+#define __OEBTEXTSTREAM_H__
+
+#include <vector>
+#include <string>
+
+#include "../util/MergedStream.h"
+
+class OEBTextStream : public MergedStream {
+
+public:
+ OEBTextStream(const ZLFile &opfFile);
+
+private:
+ void resetToStart();
+ shared_ptr<ZLInputStream> nextStream();
+
+private:
+ std::string myFilePrefix;
+ std::vector<std::string> myXHTMLFileNames;
+ std::size_t myIndex;
+};
+
+#endif /* __OEBTEXTSTREAM_H__ */
diff --git a/fbreader/src/formats/oeb/XHTMLImageFinder.cpp b/fbreader/src/formats/oeb/XHTMLImageFinder.cpp
new file mode 100644
index 0000000..6a449c9
--- /dev/null
+++ b/fbreader/src/formats/oeb/XHTMLImageFinder.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <ZLFile.h>
+#include <ZLFileImage.h>
+#include <ZLXMLNamespace.h>
+
+#include "XHTMLImageFinder.h"
+#include "../util/MiscUtil.h"
+
+static const std::string TAG_IMG = "img";
+static const std::string TAG_IMAGE = "image";
+
+shared_ptr<const ZLImage> XHTMLImageFinder::readImage(const ZLFile &file) {
+ myImage.reset();
+ myPathPrefix = MiscUtil::htmlDirectoryPrefix(file.path());
+ readDocument(file);
+ return myImage;
+}
+
+bool XHTMLImageFinder::processNamespaces() const {
+ return true;
+}
+
+void XHTMLImageFinder::startElementHandler(const char *tag, const char **attributes) {
+ const char *reference = 0;
+ if (TAG_IMG == tag) {
+ reference = attributeValue(attributes, "src");
+ } else if (TAG_IMAGE == tag) {
+ reference = attributeValue(
+ attributes, NamespaceAttributeNamePredicate(ZLXMLNamespace::XLink, "href")
+ );
+ }
+ if (reference != 0) {
+ myImage = new ZLFileImage(ZLFile(myPathPrefix + reference), 0);
+ interrupt();
+ }
+}
diff --git a/fbreader/src/formats/oeb/XHTMLImageFinder.h b/fbreader/src/formats/oeb/XHTMLImageFinder.h
new file mode 100644
index 0000000..28e53f2
--- /dev/null
+++ b/fbreader/src/formats/oeb/XHTMLImageFinder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __XHTMLIMAGEFINDER_H__
+#define __XHTMLIMAGEFINDER_H__
+
+#include <shared_ptr.h>
+#include <ZLXMLReader.h>
+
+class ZLFile;
+class ZLImage;
+
+class XHTMLImageFinder : public ZLXMLReader {
+
+public:
+ shared_ptr<const ZLImage> readImage(const ZLFile &file);
+
+private:
+ bool processNamespaces() const;
+ void startElementHandler(const char *tag, const char **attributes);
+
+private:
+ std::string myPathPrefix;
+ shared_ptr<const ZLImage> myImage;
+};
+
+#endif /* __XHTMLIMAGEFINDER_H__ */