diff options
author | Michele Calgaro <[email protected]> | 2024-05-11 21:28:48 +0900 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2024-05-11 21:28:48 +0900 |
commit | 2462d03f322261bd616721c2b2065c4004b36c9c (patch) | |
tree | 239947a0737bb8386703a1497f12c09aebd3080a /fbreader/src/formats/oeb | |
download | tde-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.cpp | 131 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/NCXReader.h | 69 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBBookReader.cpp | 273 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBBookReader.h | 70 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBCoverReader.cpp | 136 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBCoverReader.h | 56 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBMetaInfoReader.cpp | 194 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBMetaInfoReader.h | 63 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBPlugin.cpp | 149 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBPlugin.h | 40 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBTextStream.cpp | 101 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/OEBTextStream.h | 43 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/XHTMLImageFinder.cpp | 54 | ||||
-rw-r--r-- | fbreader/src/formats/oeb/XHTMLImageFinder.h | 43 |
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__ */ |