summaryrefslogtreecommitdiffstats
path: root/reader/src/network/opds
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2024-06-07 23:30:05 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2024-06-07 23:30:05 +0900
commit17b259df9cb6b28779d4881b2b6c805ee2e48eea (patch)
tree5ed61937459cb7081089111b0242c01ec178f1f3 /reader/src/network/opds
parent1cba8bce178eb2d6719c6f7f21e2c9352c5513a6 (diff)
downloadtde-ebook-reader-17b259df9cb6b28779d4881b2b6c805ee2e48eea.tar.gz
tde-ebook-reader-17b259df9cb6b28779d4881b2b6c805ee2e48eea.zip
Rename to tde-ebook-reader
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'reader/src/network/opds')
-rw-r--r--reader/src/network/opds/NetworkOPDSFeedReader.cpp198
-rw-r--r--reader/src/network/opds/NetworkOPDSFeedReader.h60
-rw-r--r--reader/src/network/opds/OPDSBookItem.cpp310
-rw-r--r--reader/src/network/opds/OPDSBookItem.h88
-rw-r--r--reader/src/network/opds/OPDSCatalogItem.cpp81
-rw-r--r--reader/src/network/opds/OPDSCatalogItem.h51
-rw-r--r--reader/src/network/opds/OPDSFeedReader.h40
-rw-r--r--reader/src/network/opds/OPDSLink.cpp216
-rw-r--r--reader/src/network/opds/OPDSLink.h112
-rw-r--r--reader/src/network/opds/OPDSLink_AdvancedSearch.h72
-rw-r--r--reader/src/network/opds/OPDSLink_GenericFeedReader.cpp134
-rw-r--r--reader/src/network/opds/OPDSLink_GenericFeedReader.h61
-rw-r--r--reader/src/network/opds/OPDSLink_GenericXMLParser.cpp109
-rw-r--r--reader/src/network/opds/OPDSLink_GenericXMLParser.h35
-rw-r--r--reader/src/network/opds/OPDSMetadata.cpp89
-rw-r--r--reader/src/network/opds/OPDSMetadata.h139
-rw-r--r--reader/src/network/opds/OPDSXMLParser.cpp554
-rw-r--r--reader/src/network/opds/OPDSXMLParser.h79
-rw-r--r--reader/src/network/opds/OpenSearchXMLReader.cpp49
-rw-r--r--reader/src/network/opds/OpenSearchXMLReader.h42
-rw-r--r--reader/src/network/opds/URLRewritingRule.cpp77
-rw-r--r--reader/src/network/opds/URLRewritingRule.h50
22 files changed, 2646 insertions, 0 deletions
diff --git a/reader/src/network/opds/NetworkOPDSFeedReader.cpp b/reader/src/network/opds/NetworkOPDSFeedReader.cpp
new file mode 100644
index 0000000..3c1ad0a
--- /dev/null
+++ b/reader/src/network/opds/NetworkOPDSFeedReader.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkUtil.h>
+#include <ZLMimeType.h>
+
+#include "NetworkOPDSFeedReader.h"
+#include "OPDSCatalogItem.h"
+#include "OPDSXMLParser.h"
+
+#include "../NetworkOperationData.h"
+#include "../NetworkItems.h"
+#include "../BookReference.h"
+#include "OPDSBookItem.h"
+
+#include "../litres/LitResUtil.h"
+
+
+NetworkOPDSFeedReader::NetworkOPDSFeedReader(
+ const OPDSLink &link,
+ const std::string &baseURL,
+ NetworkOperationData &result
+) :
+ myLink(link),
+ myBaseURL(baseURL),
+ myData(result),
+ myIndex(0),
+ myOpenSearchStartIndex(0) {
+}
+
+void NetworkOPDSFeedReader::processFeedStart() {
+}
+
+void NetworkOPDSFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) {
+ for (std::size_t i = 0; i < feed->links().size(); ++i) {
+ ATOMLink &link = *(feed->links()[i]);
+ const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href());
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ const std::string &rel = myLink.relation(link.rel(), link.type());
+ if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) {
+ if (rel == "self") {
+ } else if (rel == "next") {
+ myData.ResumeURI = href;
+ }
+ }
+ }
+ myOpenSearchStartIndex = feed->getOpensearchStartIndex() - 1;
+}
+
+
+void NetworkOPDSFeedReader::processFeedEnd() {
+ for (std::size_t i = 0; i < myData.Items.size(); ++i) {
+ NetworkItem &item = *myData.Items[i];
+ if (!item.isInstanceOf(NetworkBookItem::TYPE_ID)) {
+ continue;
+ }
+ NetworkBookItem &book = (NetworkBookItem&) item;
+ book.Index += myOpenSearchStartIndex;
+ }
+}
+
+void NetworkOPDSFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) {
+ if (entry.isNull()) {
+ return;
+ }
+
+ std::map<std::string,OPDSLink::FeedCondition>::const_iterator it = myLink.myFeedConditions.find(entry->id()->uri());
+ if (it != myLink.myFeedConditions.end() && it->second == OPDSLink::CONDITION_NEVER) {
+ return;
+ }
+ OPDSEntry &e = *entry;
+ bool hasBookLink = false;
+ for (std::size_t i = 0; i < e.links().size(); ++i) {
+ ATOMLink &link = *(e.links()[i]);
+ const std::string &type = link.type();
+ const std::string &rel = myLink.relation(link.rel(), type);
+ if (rel == OPDSConstants::REL_ACQUISITION ||
+ rel == OPDSConstants::REL_ACQUISITION_OPEN ||
+ rel == OPDSConstants::REL_ACQUISITION_SAMPLE ||
+ rel == OPDSConstants::REL_ACQUISITION_BUY ||
+ rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL ||
+ rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL ||
+ (rel.empty() && OPDSBookItem::formatByZLMimeType(type) != BookReference::NONE)) {
+ hasBookLink = true;
+ break;
+ }
+ }
+
+ shared_ptr<NetworkItem> item;
+ if (hasBookLink) {
+ item = new OPDSBookItem(myLink, e, myBaseURL, myIndex++);
+ } else {
+ item = readCatalogItem(e);
+ }
+ if (!item.isNull()) {
+ myData.Items.push_back(item);
+ }
+}
+
+shared_ptr<NetworkItem> NetworkOPDSFeedReader::readCatalogItem(OPDSEntry &entry) {
+ std::string coverURL;
+ std::string url;
+ bool urlIsAlternate = false;
+ std::string htmlURL;
+ std::string litresRel;
+ shared_ptr<ZLMimeType> litresMimeType;
+ int catalogFlags = NetworkCatalogItem::FLAGS_DEFAULT;
+ for (std::size_t i = 0; i < entry.links().size(); ++i) {
+ ATOMLink &link = *(entry.links()[i]);
+ const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href());
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ const std::string &rel = myLink.relation(link.rel(), link.type());
+ if (ZLMimeType::isImage(type)) {
+ if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) {
+ coverURL = href;
+ } else if (coverURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) {
+ coverURL = href;
+ }
+ } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) {
+ if (rel == ATOMConstants::REL_ALTERNATE) {
+ if (url.empty()) {
+ url = href;
+ urlIsAlternate = true;
+ }
+ } else {
+ url = href;
+ urlIsAlternate = false;
+ if (rel == OPDSConstants::REL_CATALOG_AUTHOR) {
+ catalogFlags &= !NetworkCatalogItem::FLAG_SHOW_AUTHOR;
+ }
+ }
+ } else if (type->weakEquals(*ZLMimeType::TEXT_HTML)) {
+ if (rel == OPDSConstants::REL_ACQUISITION ||
+ rel == ATOMConstants::REL_ALTERNATE ||
+ rel.empty()) {
+ htmlURL = href;
+ }
+ } else if (type->weakEquals(*ZLMimeType::APPLICATION_LITRES_XML)) {
+ url = href;
+ litresRel = rel;
+ litresMimeType = type;
+ }
+ }
+
+ if (url.empty() && htmlURL.empty()) {
+ return 0;
+ }
+
+ if (!url.empty() && !urlIsAlternate) {
+ htmlURL.erase();
+ }
+
+ std::map<std::string,OPDSLink::FeedCondition>::const_iterator it =
+ myLink.myFeedConditions.find(entry.id()->uri());
+ bool dependsOnAccount =
+ it != myLink.myFeedConditions.end() &&
+ it->second == OPDSLink::CONDITION_SIGNED_IN;
+
+ std::string annotation = entry.summary();
+ annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x09), annotation.end());
+ annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x0A), annotation.end());
+ NetworkItem::UrlInfoCollection urlMap;
+ urlMap[NetworkItem::URL_COVER] = coverURL;
+ urlMap[NetworkItem::URL_CATALOG] = url;
+ urlMap[NetworkItem::URL_HTML_PAGE] = htmlURL;
+
+ if (!litresMimeType.isNull()) {
+ return LitResUtil::createLitResNode(litresMimeType, litresRel, myData.Link, entry.title(), annotation, urlMap, dependsOnAccount);
+ }
+ return new OPDSCatalogItem(
+ (OPDSLink&)myData.Link,
+ entry.title(),
+ annotation,
+ urlMap,
+ dependsOnAccount ? NetworkCatalogItem::SIGNED_IN : NetworkCatalogItem::ALWAYS,
+ catalogFlags
+ );
+}
diff --git a/reader/src/network/opds/NetworkOPDSFeedReader.h b/reader/src/network/opds/NetworkOPDSFeedReader.h
new file mode 100644
index 0000000..f51b1bf
--- /dev/null
+++ b/reader/src/network/opds/NetworkOPDSFeedReader.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __NETWORKOPDSFEEDREADER_H__
+#define __NETWORKOPDSFEEDREADER_H__
+
+#include <map>
+#include <string>
+
+#include "OPDSFeedReader.h"
+#include "OPDSLink.h"
+
+class NetworkOperationData;
+
+class NetworkItem;
+
+class NetworkOPDSFeedReader : public OPDSFeedReader {
+
+public:
+ NetworkOPDSFeedReader(
+ const OPDSLink &link,
+ const std::string &baseURL,
+ NetworkOperationData &result
+ );
+
+public:
+ void processFeedEntry(shared_ptr<OPDSEntry> entry);
+ void processFeedStart();
+ void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed);
+ void processFeedEnd();
+
+private:
+ shared_ptr<NetworkItem> readCatalogItem(OPDSEntry &entry);
+
+private:
+ const OPDSLink &myLink;
+ const std::string myBaseURL;
+ NetworkOperationData &myData;
+ unsigned int myIndex;
+ unsigned int myOpenSearchStartIndex;
+};
+
+
+#endif /* __NETWORKOPDSFEEDREADER_H__ */
diff --git a/reader/src/network/opds/OPDSBookItem.cpp b/reader/src/network/opds/OPDSBookItem.cpp
new file mode 100644
index 0000000..6899afa
--- /dev/null
+++ b/reader/src/network/opds/OPDSBookItem.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkManager.h>
+#include <ZLNetworkUtil.h>
+#include <ZLUnicodeUtil.h>
+#include <ZLStringUtil.h>
+
+#include "../NetworkLink.h"
+#include "OPDSXMLParser.h"
+
+#include "OPDSBookItem.h"
+#include "OPDSCatalogItem.h"
+
+#include "../tree/NetworkTreeFactory.h"
+
+OPDSBookItem::OPDSBookItem(const OPDSLink &link, OPDSEntry &entry, std::string baseUrl, unsigned int index) :
+ NetworkBookItem(
+ link,
+ entry.id()->uri(),
+ index,
+ entry.title(),
+ getAnnotation(entry),
+ entry.dcLanguage(),
+ getDate(entry),
+ getAuthors(entry),
+ getTags(entry),
+ entry.seriesTitle(),
+ entry.seriesIndex(),
+ getUrls(link, entry, baseUrl),
+ getReferences(link, entry, baseUrl)
+ ) {
+ myRelatedInfos = getRelatedUrls(link, entry, baseUrl);
+ myInformationIsFull = false;
+}
+
+bool OPDSBookItem::isFullyLoaded() const {
+ return myInformationIsFull || URLByType.find(URL_SINGLE_ENTRY) == URLByType.end();
+}
+
+class OPDSBookItemFullInfoLoader : public ZLNetworkRequest::Listener {
+public:
+ OPDSBookItemFullInfoLoader(OPDSBookItem &item, shared_ptr<ZLNetworkRequest> request, shared_ptr<ZLNetworkRequest::Listener> listener) :
+ myItem(item), myListener(listener) {
+ request->setListener(this);
+ ZLNetworkManager::Instance().performAsync(request);
+ }
+
+ void finished(const std::string &error) {
+ if (error.empty()) {
+ myItem.myInformationIsFull = true;
+ }
+ myListener->finished(error);
+ }
+private:
+ OPDSBookItem &myItem;
+ shared_ptr<ZLNetworkRequest::Listener> myListener;
+};
+
+void OPDSBookItem::loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener) {
+ if (myInformationIsFull) {
+ listener->finished();
+ return;
+ }
+
+ if (URLByType.find(URL_SINGLE_ENTRY) == URLByType.end()) {
+ myInformationIsFull = true;
+ listener->finished();
+ return;
+ }
+
+ std::string url = URLByType[URL_SINGLE_ENTRY];
+ shared_ptr<ZLNetworkRequest> request = ZLNetworkManager::Instance().createXMLParserRequest(
+ url, new OPDSXMLParser(new FullEntryReader(*this, (const OPDSLink&)Link, url), true)
+ );
+
+ new OPDSBookItemFullInfoLoader(*this, request, listener);
+}
+
+std::vector<shared_ptr<NetworkItem> > OPDSBookItem::getRelatedCatalogsItems() const {
+ std::vector<shared_ptr<NetworkItem> > items;
+ for (std::size_t i = 0; i < myRelatedInfos.size(); ++i) {
+ shared_ptr<RelatedUrlInfo> urlInfo = myRelatedInfos.at(i);
+ if (!urlInfo->MimeType->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) {
+ continue;
+ //TODO implement items for loading link in browser
+ }
+ UrlInfoCollection urlByType = URLByType;
+ urlByType[URL_CATALOG] = urlInfo->Url;
+ OPDSCatalogItem *item = new OPDSCatalogItem(static_cast<const OPDSLink&>(Link), urlInfo->Title, std::string(), urlByType);
+ items.push_back(item);
+ }
+ return items;
+}
+
+std::string OPDSBookItem::getAnnotation(OPDSEntry &entry) {
+ //TODO implement ATOMContent support (and return content)
+ return entry.summary();
+}
+
+std::string OPDSBookItem::getDate(OPDSEntry &entry) {
+ std::string date;
+ if (!entry.dcIssued().isNull()) {
+ date = entry.dcIssued()->getDateTime(true);
+ }
+ return date;
+}
+
+std::vector<NetworkBookItem::AuthorData> OPDSBookItem::getAuthors(OPDSEntry &entry) {
+ std::vector<NetworkBookItem::AuthorData> authors;
+ for (std::size_t i = 0; i < entry.authors().size(); ++i) {
+ ATOMAuthor &author = *(entry.authors()[i]);
+ NetworkBookItem::AuthorData authorData;
+ std::string name = author.name();
+ std::string lowerCased = ZLUnicodeUtil::toLower(name);
+ static const std::string authorPrefix = "author:";
+ std::size_t index = lowerCased.find(authorPrefix);
+ if (index != std::string::npos) {
+ name = name.substr(index + authorPrefix.size());
+ } else {
+ static const std::string authorsPrefix = "authors:";
+ index = lowerCased.find(authorsPrefix);
+ if (index != std::string::npos) {
+ name = name.substr(index + authorsPrefix.size());
+ }
+ }
+ index = name.find(',');
+ if (index != std::string::npos) {
+ std::string before = name.substr(0, index);
+ std::string after = name.substr(index + 1);
+ ZLUnicodeUtil::utf8Trim(before);
+ ZLUnicodeUtil::utf8Trim(after);
+ authorData.SortKey = before;
+ authorData.DisplayName = after + ' ' + before;
+ } else {
+ ZLUnicodeUtil::utf8Trim(name);
+ index = name.rfind(' ');
+ authorData.SortKey = name.substr(index + 1);
+ authorData.DisplayName = name;
+ }
+ authors.push_back(authorData);
+ }
+ return authors;
+}
+
+std::vector<std::string> OPDSBookItem::getTags(OPDSEntry &entry) {
+ std::vector<std::string> tags;
+ for (std::size_t i = 0; i < entry.categories().size(); ++i) {
+ ATOMCategory &category = *(entry.categories()[i]);
+ tags.push_back(category.label());
+ }
+ return tags;
+}
+
+NetworkItem::UrlInfoCollection OPDSBookItem::getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) {
+ //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ
+ NetworkItem::UrlInfoCollection urlMap;
+ for (std::size_t i = 0; i < entry.links().size(); ++i) {
+ ATOMLink &link = *(entry.links()[i]);
+ const std::string href = ZLNetworkUtil::url(baseUrl, link.href());
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ const std::string &rel = networkLink.relation(link.rel(), link.type());
+ if (ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX) || rel == OPDSConstants::REL_COVER) {
+ if (urlMap[NetworkItem::URL_COVER].empty() && ZLMimeType::isImage(type)) {
+ urlMap[NetworkItem::URL_COVER] = href;
+ }
+ } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) {
+ if (ZLMimeType::isImage(type)) {
+ urlMap[NetworkItem::URL_COVER] = href;
+ }
+ } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML) &&
+ rel == ATOMConstants::REL_ALTERNATE &&
+ type->getParameter("type") == "entry") {
+ urlMap[NetworkItem::URL_SINGLE_ENTRY] = href;
+ }
+ }
+ return urlMap;
+}
+
+OPDSBookItem::RelatedUrlsList OPDSBookItem::getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) {
+ OPDSBookItem::RelatedUrlsList relatedUrlList;
+ for (std::size_t i = 0; i < entry.links().size(); ++i) {
+ ATOMLink &link = *(entry.links()[i]);
+ const std::string href = ZLNetworkUtil::url(baseUrl, link.href());
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ const std::string &rel = networkLink.relation(link.rel(), link.type());
+ if (rel == ATOMConstants::REL_RELATED) {
+ relatedUrlList.push_back(new RelatedUrlInfo(link.title(), type, href));
+ }
+ }
+ return relatedUrlList;
+}
+
+std::vector<shared_ptr<BookReference> > OPDSBookItem::getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) {
+ //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ
+ std::vector<shared_ptr<BookReference> > references;
+ for (std::size_t i = 0; i < entry.links().size(); ++i) {
+ ATOMLink &link = *(entry.links()[i]);
+ const std::string href = ZLNetworkUtil::url(baseUrl, link.href());
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ const std::string &rel = networkLink.relation(link.rel(), link.type());
+ const BookReference::Type referenceType = typeByRelation(rel);
+ if (referenceType == BookReference::BUY) {
+ std::string price = BuyBookReference::price(
+ link.userData(OPDSXMLParser::KEY_PRICE),
+ link.userData(OPDSXMLParser::KEY_CURRENCY)
+ );
+ if (price.empty()) {
+ price = BuyBookReference::price(
+ entry.userData(OPDSXMLParser::KEY_PRICE),
+ entry.userData(OPDSXMLParser::KEY_CURRENCY)
+ );
+ }
+ if (type == ZLMimeType::TEXT_HTML) {
+ references.push_back(new BuyBookReference(
+ href, BookReference::NONE, BookReference::BUY_IN_BROWSER, price
+ ));
+ } else {
+ BookReference::Format format = formatByZLMimeType(link.userData(OPDSXMLParser::KEY_FORMAT));
+ if (format != BookReference::NONE) {
+ references.push_back(new BuyBookReference(
+ href, format, BookReference::BUY, price
+ ));
+ }
+ }
+ } else if (referenceType != BookReference::UNKNOWN) {
+ BookReference::Format format = formatByZLMimeType(link.type());
+ if (format != BookReference::NONE) {
+ references.push_back(new BookReference(href, format, referenceType));
+ }
+ }
+ }
+ return references;
+}
+
+BookReference::Format OPDSBookItem::formatByZLMimeType(const std::string &mimeType) {
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(mimeType);
+ if (type == ZLMimeType::APPLICATION_FB2_ZIP) {
+ return BookReference::FB2_ZIP;
+ } else if (type == ZLMimeType::APPLICATION_EPUB_ZIP) {
+ return BookReference::EPUB;
+ } else if (type == ZLMimeType::APPLICATION_MOBIPOCKET_EBOOK) {
+ return BookReference::MOBIPOCKET;
+ }
+ return BookReference::NONE;
+}
+
+BookReference::Type OPDSBookItem::typeByRelation(const std::string &rel) {
+ if (rel == OPDSConstants::REL_ACQUISITION || rel == OPDSConstants::REL_ACQUISITION_OPEN || rel.empty()) {
+ return BookReference::DOWNLOAD_FULL;
+ } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE) {
+ return BookReference::DOWNLOAD_DEMO;
+ } else if (rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL) {
+ return BookReference::DOWNLOAD_FULL_CONDITIONAL;
+ } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL) {
+ return BookReference::DOWNLOAD_FULL_OR_DEMO;
+ } else if (rel == OPDSConstants::REL_ACQUISITION_BUY) {
+ return BookReference::BUY;
+ } else {
+ return BookReference::UNKNOWN;
+ }
+}
+
+OPDSBookItem::FullEntryReader::FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url) :
+ myItem(item), myLink(link), myUrl(url) {
+}
+
+void OPDSBookItem::FullEntryReader::processFeedEntry(shared_ptr<OPDSEntry> entry) {
+ NetworkItem::UrlInfoCollection urlMap = OPDSBookItem::getUrls(myLink, *entry, myUrl);
+ std::vector<shared_ptr<BookReference> > references = OPDSBookItem::getReferences(myLink, *entry, myUrl);
+ for (NetworkItem::UrlInfoCollection::iterator it = urlMap.begin(); it != urlMap.end(); ++it) {
+ myItem.URLByType[(*it).first] = (*it).second;
+ }
+ myItem.updateReferences(references);
+ std::string summary = OPDSBookItem::getAnnotation(*entry);
+ if (!summary.empty()) {
+ myItem.Summary = summary;
+ }
+ myItem.myRelatedInfos = OPDSBookItem::getRelatedUrls(myLink, *entry, myUrl);
+}
+
+void OPDSBookItem::FullEntryReader::processFeedStart() {
+}
+
+void OPDSBookItem::FullEntryReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> /*feed*/) {
+}
+
+void OPDSBookItem::FullEntryReader::processFeedEnd() {
+}
+
+OPDSBookItem::RelatedUrlInfo::RelatedUrlInfo(const std::string &title, shared_ptr<ZLMimeType> mimeType, const std::string url) :
+ Title(title), MimeType(mimeType), Url(url) { }
+
+
diff --git a/reader/src/network/opds/OPDSBookItem.h b/reader/src/network/opds/OPDSBookItem.h
new file mode 100644
index 0000000..8b3ddbd
--- /dev/null
+++ b/reader/src/network/opds/OPDSBookItem.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSBOOKITEM_H__
+#define __OPDSBOOKITEM_H__
+
+#include "OPDSLink.h"
+#include "OPDSMetadata.h"
+#include "OPDSFeedReader.h"
+
+class OPDSBookItem : public NetworkBookItem {
+
+public:
+ OPDSBookItem(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl, unsigned int index);
+
+public:
+ bool isFullyLoaded() const;
+ void loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener);
+ std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const;
+
+public:
+ static BookReference::Format formatByZLMimeType(const std::string &mimeType);
+ static BookReference::Type typeByRelation(const std::string &rel);
+
+protected:
+ static std::string getAnnotation(OPDSEntry &entry);
+ static std::string getDate(OPDSEntry &entry);
+ static std::vector<AuthorData> getAuthors(OPDSEntry &entry);
+ static std::vector<std::string> getTags(OPDSEntry &entry);
+ static UrlInfoCollection getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl);
+ //TODO implement one UrlInfoCollection to not duplicate similar methods
+ static std::vector<shared_ptr<BookReference> > getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl);
+
+private:
+ class FullEntryReader : public OPDSFeedReader {
+
+ public:
+ FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url);
+
+ public:
+ void processFeedEntry(shared_ptr<OPDSEntry> entry);
+ void processFeedStart();
+ void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed);
+ void processFeedEnd();
+
+ private:
+ OPDSBookItem &myItem;
+ const OPDSLink &myLink;
+ std::string myUrl;
+ };
+
+ class RelatedUrlInfo {
+ public:
+ RelatedUrlInfo(const std::string& title, shared_ptr<ZLMimeType> mimeType, const std::string url);
+
+ std::string Title;
+ shared_ptr<ZLMimeType> MimeType;
+ std::string Url;
+ };
+
+ typedef std::vector<shared_ptr<RelatedUrlInfo> > RelatedUrlsList;
+ RelatedUrlsList myRelatedInfos;
+protected:
+ static RelatedUrlsList getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl);
+private:
+ bool myInformationIsFull;
+
+friend class OPDSBookItemFullInfoLoader;
+
+};
+
+#endif /* __OPDSBOOKITEM_H__ */
diff --git a/reader/src/network/opds/OPDSCatalogItem.cpp b/reader/src/network/opds/OPDSCatalogItem.cpp
new file mode 100644
index 0000000..853bc4c
--- /dev/null
+++ b/reader/src/network/opds/OPDSCatalogItem.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkRequest.h>
+#include <ZLNetworkManager.h>
+
+#include "OPDSCatalogItem.h"
+#include "OPDSLink.h"
+#include "OPDSXMLParser.h"
+#include "NetworkOPDSFeedReader.h"
+
+#include "../NetworkOperationData.h"
+
+OPDSCatalogItem::OPDSCatalogItem(
+ const OPDSLink &link,
+ const std::string &title,
+ const std::string &summary,
+ const UrlInfoCollection &urlByType,
+ AccessibilityType accessibility,
+ int flags
+ ) : NetworkCatalogItem(link, title, summary, urlByType, accessibility, flags), myLoadingState(Link) {
+}
+
+class OPDSCatalogItemRunnable : public ZLNetworkRequest::Listener {
+public:
+ OPDSCatalogItemRunnable(shared_ptr<ZLNetworkRequest> request, NetworkItem::List &children, NetworkOperationData &data, shared_ptr<ZLNetworkRequest::Listener> listener) :
+ myChildren(children), myLoadingData(data), myListener(listener) {
+ request->setListener(this);
+ ZLNetworkManager::Instance().performAsync(request);
+ }
+ void finished(const std::string &error) {
+ myChildren.insert(myChildren.end(), myLoadingData.Items.begin(), myLoadingData.Items.end());
+ myListener->finished(error);
+ }
+ void setUIStatus(bool enabled) {
+ myListener->setUIStatus(enabled); //to hide refreshing while authentication dialog
+ }
+
+private:
+ NetworkItem::List &myChildren;
+ NetworkOperationData &myLoadingData;
+ shared_ptr<ZLNetworkRequest::Listener> myListener;
+};
+
+
+std::string OPDSCatalogItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) {
+ myLoadingState.clear();
+ shared_ptr<ZLNetworkRequest> request = ((OPDSLink&)Link).createNetworkRequest(getCatalogUrl(), myLoadingState);
+ new OPDSCatalogItemRunnable(request, children, myLoadingState, listener);
+ return std::string();
+}
+
+bool OPDSCatalogItem::supportsResumeLoading() {
+ return true;
+}
+
+std::string OPDSCatalogItem::resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) {
+ shared_ptr<ZLNetworkRequest> request = myLoadingState.resume();
+ if (request.isNull()) {
+ listener->finished();
+ return std::string();
+ }
+ new OPDSCatalogItemRunnable(request, children, myLoadingState, listener);
+ return std::string();
+}
diff --git a/reader/src/network/opds/OPDSCatalogItem.h b/reader/src/network/opds/OPDSCatalogItem.h
new file mode 100644
index 0000000..e2bc787
--- /dev/null
+++ b/reader/src/network/opds/OPDSCatalogItem.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSCATALOGITEM_H__
+#define __OPDSCATALOGITEM_H__
+
+#include <ZLExecutionUtil.h>
+
+#include "../NetworkItems.h"
+#include "../NetworkOperationData.h"
+
+class OPDSLink;
+
+class OPDSCatalogItem : public NetworkCatalogItem {
+
+public:
+ OPDSCatalogItem(
+ const OPDSLink &link,
+ const std::string &title,
+ const std::string &summary,
+ const UrlInfoCollection &urlByType,
+ AccessibilityType accessibility = ALWAYS,
+ int flags = FLAGS_DEFAULT
+ );
+
+public:
+ std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0);
+ bool supportsResumeLoading();
+ std::string resumeLoading(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0);
+
+private:
+ NetworkOperationData myLoadingState;
+};
+
+#endif /* __OPDSCATALOGITEM_H__ */
diff --git a/reader/src/network/opds/OPDSFeedReader.h b/reader/src/network/opds/OPDSFeedReader.h
new file mode 100644
index 0000000..a842f41
--- /dev/null
+++ b/reader/src/network/opds/OPDSFeedReader.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSFEEDREADER_H__
+#define __OPDSFEEDREADER_H__
+
+#include "OPDSMetadata.h"
+
+
+class OPDSFeedReader {
+
+public:
+ OPDSFeedReader() {}
+ virtual ~OPDSFeedReader() {}
+
+public:
+ virtual void processFeedEntry(shared_ptr<OPDSEntry> entry) = 0;
+ virtual void processFeedStart() = 0;
+ virtual void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) = 0;
+ virtual void processFeedEnd() = 0;
+};
+
+
+#endif /* __OPDSFEEDREADER_H__ */
diff --git a/reader/src/network/opds/OPDSLink.cpp b/reader/src/network/opds/OPDSLink.cpp
new file mode 100644
index 0000000..f682b7d
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkUtil.h>
+#include <ZLNetworkManager.h>
+
+#include "OPDSLink.h"
+#include "OPDSLink_AdvancedSearch.h"
+#include "OPDSCatalogItem.h"
+#include "OPDSXMLParser.h"
+#include "NetworkOPDSFeedReader.h"
+
+#include "../NetworkOperationData.h"
+#include "../authentication/NetworkAuthenticationManager.h"
+#include "../authentication/litres/LitResAuthenticationManager.h"
+
+#include "URLRewritingRule.h"
+
+OPDSLink::AdvancedSearch::AdvancedSearch(
+ const std::string &type,
+ const std::string &titleParameter,
+ const std::string &authorParameter,
+ const std::string &tagParameter,
+ const std::string &annotationParameter
+) : myType(type), myTitleParameter(titleParameter), myAuthorParameter(authorParameter), myTagParameter(tagParameter), myAnnotationParameter(annotationParameter) {
+}
+
+void OPDSLink::AdvancedSearch::addSubQuery(std::string &query, const std::string &name, const std::string &value) const {
+ if (value.empty()) {
+ return;
+ }
+
+ if (myType == "separateWords") {
+ std::size_t start = 0, end;
+ do {
+ end = value.find(' ', start);
+ std::string ss = value.substr(start, end - start);
+ ZLUnicodeUtil::utf8Trim(ss);
+ if (!ss.empty()) {
+ if (!query.empty()) {
+ query.append("+");
+ }
+ query.append(name + ':');
+ query.append(ZLNetworkUtil::htmlEncode(ss));
+ }
+ start = end + 1;
+ } while (end != std::string::npos);
+ } else if (myType == "quoted") {
+ std::string encodedValue = value;
+ ZLUnicodeUtil::utf8Trim(encodedValue);
+
+ if (encodedValue.empty()) {
+ return;
+ }
+ encodedValue = '"' + encodedValue + '"';
+ std::replace(encodedValue.begin(), encodedValue.end(), ' ', '+');
+
+ if (!query.empty()) {
+ query += '+';
+ }
+ query += name + ':' + ZLNetworkUtil::htmlEncode(encodedValue);
+ }
+}
+
+std::string OPDSLink::AdvancedSearch::query(
+ const std::string &titleOrSeries,
+ const std::string &author,
+ const std::string &tag,
+ const std::string &annotation
+) const {
+ std::string query;
+ addSubQuery(query, myTitleParameter, titleOrSeries);
+ addSubQuery(query, myAuthorParameter, author);
+ addSubQuery(query, myTagParameter, tag);
+ addSubQuery(query, myAnnotationParameter, annotation);
+ return query;
+}
+
+//shared_ptr<NetworkLink> OPDSLink::read(const ZLFile &file) {
+// Reader reader;
+// reader.readDocument(file);
+// return reader.link();
+//}
+
+shared_ptr<ZLNetworkRequest> OPDSLink::createNetworkRequest(const std::string &url, NetworkOperationData &result) const {
+ if (url.empty()) {
+ return 0;
+ }
+ std::string modifiedUrl(url);
+ rewriteUrl(modifiedUrl);
+ return ZLNetworkManager::Instance().createXMLParserRequest(modifiedUrl, new OPDSXMLParser(new NetworkOPDSFeedReader(*this, url, result)) );
+}
+
+OPDSLink::OPDSLink(
+ const std::string &siteName
+) : NetworkLink(siteName) {
+}
+
+OPDSLink::~OPDSLink() {
+}
+
+shared_ptr<NetworkItem> OPDSLink::libraryItem() const {
+ NetworkItem::UrlInfoCollection urlMap;
+ urlMap[NetworkItem::URL_COVER] = getIcon();
+ urlMap[NetworkItem::URL_CATALOG] = url(URL_MAIN);
+ return new OPDSCatalogItem(*this, getTitle(), getSummary(), urlMap);
+}
+
+const std::string OPDSLink::searchURL(const std::string &query) const {
+ return ZLStringUtil::printf(url(URL_SEARCH), query);
+}
+
+shared_ptr<ZLNetworkRequest> OPDSLink::simpleSearchData(NetworkOperationData &result, const std::string &pattern) const {
+ return createNetworkRequest(
+ searchURL(ZLNetworkUtil::htmlEncode(pattern)),
+ result
+ );
+}
+
+shared_ptr<ZLNetworkRequest> OPDSLink::advancedSearchData(
+ NetworkOperationData &result,
+ const std::string &titleAndSeries,
+ const std::string &author,
+ const std::string &tag,
+ const std::string &annotation
+) const {
+ if (myAdvancedSearch.isNull()) {
+ return 0;
+ }
+ std::string query = myAdvancedSearch->query(
+ titleAndSeries, author, tag, annotation
+ );
+ return query.empty() ? 0 : createNetworkRequest(searchURL(query), result);
+}
+
+shared_ptr<ZLNetworkRequest> OPDSLink::resume(NetworkOperationData &data) const {
+ const std::string url = data.ResumeURI;
+ return createNetworkRequest(url, data);
+}
+
+shared_ptr<NetworkAuthenticationManager> OPDSLink::authenticationManager() const {
+ return myAuthenticationManager;
+}
+
+void OPDSLink::setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules) {
+ myUrlRewritingRules = rules;
+}
+
+void OPDSLink::setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager) {
+ myAuthenticationManager = manager;
+}
+
+void OPDSLink::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) {
+ myAdvancedSearch = advancedSearch;
+}
+
+void OPDSLink::setRelationAliases(std::map<RelationAlias, std::string> relationAliases) {
+ myRelationAliases = relationAliases;
+}
+
+void OPDSLink::rewriteUrl(std::string &url, bool isUrlExternal) const {
+ URLRewritingRule::RuleApply apply = isUrlExternal ? URLRewritingRule::EXTERNAL : URLRewritingRule::INTERNAL;
+ for (std::vector<shared_ptr<URLRewritingRule> >::const_iterator it = myUrlRewritingRules.begin(); it != myUrlRewritingRules.end(); ++it) {
+ const URLRewritingRule &rule = **it;
+ if (rule.whereToApply() == apply) {
+ url = rule.apply(url);
+ }
+ }
+}
+
+OPDSLink::RelationAlias::RelationAlias(const std::string &alias, const std::string &type) : Alias(alias), Type(type) {
+}
+
+bool OPDSLink::RelationAlias::operator < (const RelationAlias &alias) const {
+ int cmp = Alias.compare(alias.Alias);
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ return Type < alias.Type;
+}
+
+const std::string &OPDSLink::relation(const std::string &rel, const std::string &type) const {
+ RelationAlias alias(rel, type);
+ std::map<RelationAlias,std::string>::const_iterator it = myRelationAliases.find(alias);
+ if (it != myRelationAliases.end()) {
+ return it->second;
+ }
+ if (!type.empty()) {
+ alias.Type.erase();
+ it = myRelationAliases.find(alias);
+ if (it != myRelationAliases.end()) {
+ return it->second;
+ }
+ }
+ return rel;
+}
diff --git a/reader/src/network/opds/OPDSLink.h b/reader/src/network/opds/OPDSLink.h
new file mode 100644
index 0000000..d6fd87e
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSLINK_H__
+#define __OPDSLINK_H__
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "../NetworkLink.h"
+
+class ZLFile;
+
+class NetworkAuthenticationManager;
+struct URLRewritingRule;
+
+class OPDSLink : public NetworkLink {
+
+public:
+ enum FeedCondition {
+ CONDITION_NEVER,
+ CONDITION_SIGNED_IN,
+ };
+
+private:
+ class AdvancedSearch;
+
+public:
+ class GenericReader;
+ class FeedReader;
+ class GenericFeedReader;
+ class GenericXMLParser;
+
+ OPDSLink(
+ const std::string &siteName
+ );
+
+public:
+ ~OPDSLink();
+
+private:
+ struct RelationAlias;
+
+public:
+ void setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules);
+ void setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager);
+ void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch);
+ void setRelationAliases(std::map<RelationAlias, std::string> relationAliases);
+
+private:
+ const std::string searchURL(const std::string &pattern) const;
+
+ shared_ptr<ZLNetworkRequest> createNetworkRequest(const std::string &url, NetworkOperationData &result) const;
+
+ shared_ptr<ZLNetworkRequest> simpleSearchData(
+ NetworkOperationData &result,
+ const std::string &pattern) const;
+ shared_ptr<ZLNetworkRequest> advancedSearchData(
+ NetworkOperationData &result,
+ const std::string &titleAndSeries,
+ const std::string &author,
+ const std::string &tag,
+ const std::string &annotation) const;
+ shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &result) const;
+
+ shared_ptr<NetworkItem> libraryItem() const;
+ shared_ptr<NetworkAuthenticationManager> authenticationManager() const;
+
+ void rewriteUrl(std::string &url, bool isUrlExternal = false) const;
+
+ const std::string &relation(const std::string &rel, const std::string &type) const;
+
+private:
+ shared_ptr<AdvancedSearch> myAdvancedSearch;
+
+ struct RelationAlias {
+ std::string Alias;
+ std::string Type;
+
+ RelationAlias(const std::string &alias, const std::string &type);
+ bool operator < (const RelationAlias &other) const;
+ };
+ std::map<RelationAlias, std::string> myRelationAliases;
+
+ std::map<std::string,FeedCondition> myFeedConditions;
+ std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules;
+
+ shared_ptr<NetworkAuthenticationManager> myAuthenticationManager;
+
+friend class NetworkOPDSFeedReader;
+friend class OPDSCatalogItem;
+friend class OPDSBookItem;
+};
+
+#endif /* __OPDSLINK_H__ */
diff --git a/reader/src/network/opds/OPDSLink_AdvancedSearch.h b/reader/src/network/opds/OPDSLink_AdvancedSearch.h
new file mode 100644
index 0000000..76519c9
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink_AdvancedSearch.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSLINK_ADVANCEDSEARCH_H__
+#define __OPDSLINK_ADVANCEDSEARCH_H__
+
+#include <string>
+/*
+#include <algorithm>
+
+#include <ZLStringUtil.h>
+#include <ZLNetworkUtil.h>
+#include <ZLNetworkManager.h>
+
+#include "OPDSLink.h"
+#include "OPDSLinkReader.h"
+#include "OPDSCatalogItem.h"
+#include "OPDSXMLParser.h"
+#include "NetworkOPDSFeedReader.h"
+
+#include "../NetworkOperationData.h"
+#include "../authentication/NetworkAuthenticationManager.h"
+
+#include "URLRewritingRule.h"
+*/
+
+class OPDSLink::AdvancedSearch {
+
+public:
+ AdvancedSearch(
+ const std::string &type,
+ const std::string &titleParameter,
+ const std::string &authorParameter,
+ const std::string &tagParameter,
+ const std::string &annotationParameter
+ );
+
+ std::string query(
+ const std::string &titleOrSeries,
+ const std::string &author,
+ const std::string &tag,
+ const std::string &annotation
+ ) const;
+
+private:
+ void addSubQuery(std::string &query, const std::string &name, const std::string &value) const;
+
+private:
+ const std::string myType;
+ const std::string myTitleParameter;
+ const std::string myAuthorParameter;
+ const std::string myTagParameter;
+ const std::string myAnnotationParameter;
+};
+
+#endif /* __OPDSLINK_ADVANCEDSEARCH_H__ */
diff --git a/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp b/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp
new file mode 100644
index 0000000..5389f2d
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkUtil.h>
+#include <ZLStringUtil.h>
+#include <ZLMimeType.h>
+#include <ZLNetworkRequest.h>
+#include <ZLNetworkManager.h>
+
+#include "../authentication/litres/LitResAuthenticationManager.h"
+
+#include "OPDSLink_GenericFeedReader.h"
+#include "OpenSearchXMLReader.h"
+
+OPDSLink::GenericFeedReader::GenericFeedReader(
+ std::vector<shared_ptr<NetworkLink> >& links
+) :
+ myLinks(links) {
+}
+
+void OPDSLink::GenericFeedReader::processFeedStart() {
+}
+
+void OPDSLink::GenericFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata>) {
+
+}
+
+
+void OPDSLink::GenericFeedReader::processFeedEnd() {
+}
+
+void OPDSLink::GenericFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) {
+ std::map<std::string,std::string> links;
+ std::string iconURL;
+ for (std::size_t i = 0; i < entry->links().size(); ++i) {
+ ATOMLink &link = *(entry->links()[i]);
+ const std::string &href = link.href();
+ const std::string &rel = link.rel();
+ shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type());
+ if (rel == NetworkLink::URL_SEARCH) {
+ links[rel] = OpenSearchXMLReader::convertOpenSearchURL(href);
+ } else if (rel == "") {
+ links[NetworkLink::URL_MAIN] = href;
+ } else if (rel == OPDSConstants::REL_LINK_SIGN_IN) {
+ links[NetworkLink::URL_SIGN_IN] = href;
+ } else if (rel == OPDSConstants::REL_LINK_SIGN_OUT) {
+ links[NetworkLink::URL_SIGN_OUT] = href;
+ } else if (rel == OPDSConstants::REL_LINK_SIGN_UP) {
+ links[NetworkLink::URL_SIGN_UP] = href;
+ } else if (rel == OPDSConstants::REL_LINK_TOPUP) {
+ links[NetworkLink::URL_TOPUP] = href;
+ } else if (rel == OPDSConstants::REL_LINK_RECOVER_PASSWORD) {
+ links[NetworkLink::URL_RECOVER_PASSWORD] = href;
+ } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) {
+ if (ZLMimeType::isImage(type)) {
+ iconURL = href;
+ }
+ } else if (iconURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) {
+ if (ZLMimeType::isImage(type)) {
+ iconURL = href;
+ }
+ } else {
+ links[rel] = href;
+ }
+ }
+ if (entry->title().empty() || links[NetworkLink::URL_MAIN].empty()) {
+ return;
+ }
+ if (entry->id() == 0) {
+ return;
+ }
+ std::string id = entry->id()->uri();
+ std::string summary = entry->summary();
+ std::string language = entry->dcLanguage();
+
+ shared_ptr<NetworkLink> link = new OPDSLink(id.substr(25)); //why just 25 symbols?
+ link->setTitle(entry->title());
+ link->setSummary(summary);
+ link->setLanguage(language);
+ link->setIcon(iconURL);
+ link->setLinks(links);
+ link->setPredefinedId(id);
+ link->setUpdated(entry->updated());
+
+ OPDSLink &opdsLink = static_cast<OPDSLink&>(*link);
+ opdsLink.setUrlRewritingRules(myUrlRewritingRules);
+ if (!myAdvancedSearch.isNull()) {
+ opdsLink.setAdvancedSearch(myAdvancedSearch);
+ }
+ opdsLink.setRelationAliases(myRelationAliases);
+ if (myAuthenticationType == "litres") {
+ opdsLink.setAuthenticationManager(new LitResAuthenticationManager(*link));
+ }
+ myLinks.push_back(link);
+}
+
+void OPDSLink::GenericFeedReader::clear() {
+ myAuthenticationType.clear();
+ myUrlRewritingRules.clear();
+ myAdvancedSearch.reset();
+ myRelationAliases.clear();
+}
+
+void OPDSLink::GenericFeedReader::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) {
+ myAdvancedSearch = advancedSearch;
+}
+
+void OPDSLink::GenericFeedReader::setAuthenticationType(std::string type) {
+ myAuthenticationType = type;
+}
+
+void OPDSLink::GenericFeedReader::addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule) {
+ myUrlRewritingRules.push_back(rewritingRule);
+}
+
+void OPDSLink::GenericFeedReader::addRelationAlias(const OPDSLink::RelationAlias& alias, std::string name) {
+ myRelationAliases[alias] = name;
+}
diff --git a/reader/src/network/opds/OPDSLink_GenericFeedReader.h b/reader/src/network/opds/OPDSLink_GenericFeedReader.h
new file mode 100644
index 0000000..15ffe38
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink_GenericFeedReader.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSLINK_GENERICFEEDREADER_H__
+#define __OPDSLINK_GENERICFEEDREADER_H__
+
+#include <map>
+#include <string>
+
+#include "URLRewritingRule.h"
+#include "OPDSFeedReader.h"
+#include "OPDSLink.h"
+#include "OPDSLink_AdvancedSearch.h"
+
+class OPDSLink::GenericFeedReader : public OPDSFeedReader {
+
+public:
+ GenericFeedReader(
+ std::vector<shared_ptr<NetworkLink> >& links
+ );
+
+public:
+ void processFeedEntry(shared_ptr<OPDSEntry> entry);
+ void processFeedStart();
+ void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed);
+ void processFeedEnd();
+
+public:
+ void clear();
+ void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch);
+ void setAuthenticationType(std::string type);
+ void addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule);
+ void addRelationAlias(const OPDSLink::RelationAlias&, std::string name);
+
+private:
+ std::vector<shared_ptr<NetworkLink> >& myLinks;
+
+private:
+ std::string myAuthenticationType;
+ std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules;
+ shared_ptr<OPDSLink::AdvancedSearch> myAdvancedSearch;
+ std::map<OPDSLink::RelationAlias,std::string> myRelationAliases;
+};
+
+#endif /* __OPDSLINK_GENERICFEEDREADER_H__ */
diff --git a/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp b/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp
new file mode 100644
index 0000000..af5d866
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLXMLNamespace.h>
+
+#include "OPDSLink_GenericXMLParser.h"
+#include "URLRewritingRule.h"
+#include "OPDSLink_AdvancedSearch.h"
+
+static const std::string TAG_ENTRY = "entry";
+static const std::string READER_ADVANCED_SEARCH = "advancedSearch";
+static const std::string READER_AUTHENTICATION = "authentication";
+static const std::string READER_REWRITING_RULE = "urlRewritingRule";
+static const std::string READER_RELATION_ALIAS = "relationAlias";
+static const std::string READER_EXTRA = "extra";
+
+OPDSLink::GenericXMLParser::GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader) :
+ OPDSXMLParser(feedReader) {
+}
+
+OPDSLink::GenericFeedReader &OPDSLink::GenericXMLParser::getFeedReader() const {
+ return static_cast<OPDSLink::GenericFeedReader&>(*myFeedReader);
+}
+
+void OPDSLink::GenericXMLParser::startElementHandler(const char *tag, const char **attributes) {
+ switch (myState) {
+ case FEED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) {
+ getFeedReader().clear();
+ }
+ break;
+ case F_ENTRY:
+ if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_ADVANCED_SEARCH, tag)) {
+ const char *style = attributeValue(attributes, "style");
+ const char *author = attributeValue(attributes, "author");
+ const char *titleOrSeries = attributeValue(attributes, "titleOrSeries");
+ const char *tag = attributeValue(attributes, "tag");
+ const char *annotation = attributeValue(attributes, "annotation");
+ if (style != 0 && author != 0 && titleOrSeries != 0 && tag != 0 && annotation != 0) {
+ getFeedReader().setAdvancedSearch(new OPDSLink::AdvancedSearch(style, titleOrSeries, author, tag, annotation));
+ }
+ return;
+ } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_AUTHENTICATION, tag)) {
+ const char *type = attributeValue(attributes, "type");
+ if (type != 0) {
+ getFeedReader().setAuthenticationType(type);
+ }
+ return;
+ } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_RELATION_ALIAS, tag)) {
+ const char *name = attributeValue(attributes, "name");
+ const char *type = attributeValue(attributes, "type");
+ const char *alias = attributeValue(attributes, "alias");
+ if (name != 0 && alias != 0) {
+ getFeedReader().addRelationAlias(OPDSLink::RelationAlias(alias, (type != 0) ? type : std::string()), name);
+ }
+ } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_REWRITING_RULE, tag)) {
+
+ getFeedReader().addUrlRewritingRule(new URLRewritingRule(getAttributesMap(attributes)));
+
+// const char *type = attributeValue(attributes, "type");
+// const char *apply = attributeValue(attributes, "apply");
+// const char *name = attributeValue(attributes, "name");
+// const char *value = attributeValue(attributes, "value");
+
+// //TODO add rewrite type of 'rewriting rules'
+// URLRewritingRule::RuleApply ruleApply = URLRewritingRule::ALWAYS;
+// if (apply != 0) {
+// const std::string applyStr = apply;
+// if (applyStr == "external") {
+// ruleApply = URLRewritingRule::EXTERNAL;
+// } else if (applyStr == "internal") {
+// ruleApply = URLRewritingRule::INTERNAL;
+// } else if (applyStr != "always") {
+// type = 0;
+// }
+// }
+
+// if (type != 0 && name != 0 && value != 0) {
+// std::string typeStr = type;
+// if (typeStr == "addUrlParameter") {
+// getFeedReader().addUrlRewritingRule(new URLRewritingRule(URLRewritingRule::ADD_URL_PARAMETER, ruleApply, name, value));
+// }
+// }
+
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ OPDSXMLParser::startElementHandler(tag, attributes);
+}
+
diff --git a/reader/src/network/opds/OPDSLink_GenericXMLParser.h b/reader/src/network/opds/OPDSLink_GenericXMLParser.h
new file mode 100644
index 0000000..9bdf9d6
--- /dev/null
+++ b/reader/src/network/opds/OPDSLink_GenericXMLParser.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSLINK_GENERICXMLPARSER_H__
+#define __OPDSLINK_GENERICXMLPARSER_H__
+
+#include "OPDSXMLParser.h"
+#include "OPDSLink_GenericFeedReader.h"
+
+class OPDSLink::GenericXMLParser : public OPDSXMLParser {
+public:
+ GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader);
+
+protected:
+ void startElementHandler(const char *tag, const char **attributes);
+ OPDSLink::GenericFeedReader &getFeedReader() const;
+};
+
+#endif /* __OPDSLINK_GENERICXMLPARSER_H__ */
diff --git a/reader/src/network/opds/OPDSMetadata.cpp b/reader/src/network/opds/OPDSMetadata.cpp
new file mode 100644
index 0000000..6595e05
--- /dev/null
+++ b/reader/src/network/opds/OPDSMetadata.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 "OPDSMetadata.h"
+
+// Feed level
+const std::string OPDSConstants::REL_BOOKSHELF = "http://data.fbreader.org/rel/bookshelf";
+const std::string OPDSConstants::REL_RECOMMENDATIONS = "http://data.fbreader.org/rel/recommendations";
+
+//const std::string OPDSConstants::REL_SUBSCRIPTIONS = "http://opds-spec.org/subscriptions";
+
+const std::string OPDSConstants::REL_CATALOG_AUTHOR = "http://data.fbreader.org/catalog/author";
+const std::string OPDSConstants::REL_ACQUISITION = "http://opds-spec.org/acquisition";
+const std::string OPDSConstants::REL_ACQUISITION_OPEN = "http://opds-spec.org/acquisition/open-access";
+const std::string OPDSConstants::REL_ACQUISITION_BUY = "http://opds-spec.org/acquisition/buy";
+//const std::string OPDSConstants::REL_ACQUISITION_BORROW = "http://opds-spec.org/acquisition/borrow";
+//const std::string OPDSConstants::REL_ACQUISITION_SUBSCRIBE = "http://opds-spec.org/acquisition/subscribe";
+const std::string OPDSConstants::REL_ACQUISITION_SAMPLE = "http://opds-spec.org/acquisition/sample";
+const std::string OPDSConstants::REL_ACQUISITION_CONDITIONAL = "http://data.fbreader.org/acquisition/conditional";
+const std::string OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL = "http://data.fbreader.org/acquisition/sampleOrFull";
+
+// Entry level / other
+const std::string OPDSConstants::REL_IMAGE_PREFIX = "http://opds-spec.org/image";
+//const std::string OPDSConstants::REL_IMAGE = "http://opds-spec.org/image";
+const std::string OPDSConstants::REL_IMAGE_THUMBNAIL = "http://opds-spec.org/image/thumbnail";
+// FIXME: This relations have been removed from OPDS-1.0 standard. Use RelationAlias instead???
+const std::string OPDSConstants::REL_COVER = "http://opds-spec.org/cover";
+const std::string OPDSConstants::REL_THUMBNAIL = "http://opds-spec.org/thumbnail";
+
+// Entry level / OPDS Link Relations
+const std::string OPDSConstants::REL_LINK_SIGN_IN = "http://data.fbreader.org/catalog/sign-in";
+const std::string OPDSConstants::REL_LINK_SIGN_OUT = "http://data.fbreader.org/catalog/sign-out";
+const std::string OPDSConstants::REL_LINK_SIGN_UP = "http://data.fbreader.org/catalog/sign-up";
+const std::string OPDSConstants::REL_LINK_TOPUP = "http://data.fbreader.org/catalog/refill-account";
+const std::string OPDSConstants::REL_LINK_RECOVER_PASSWORD = "http://data.fbreader.org/catalog/recover-password";
+
+DCDate::DCDate() :
+ ATOMDateConstruct(0) {
+}
+
+DCDate::DCDate(int year) :
+ ATOMDateConstruct(year) {
+}
+
+DCDate::DCDate(int year, int month, int day) :
+ ATOMDateConstruct(year, month, day) {
+}
+
+DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds) :
+ ATOMDateConstruct(year, month, day, hour, minutes, seconds) {
+}
+
+DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract) :
+ ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) {
+}
+
+DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) :
+ ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) {
+}
+
+OPDSEntry::OPDSEntry() {
+}
+
+OPDSEntry::OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) :
+ ATOMEntry(id, title, updated) {
+}
+
+OPDSFeedMetadata::OPDSFeedMetadata() : myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) {
+}
+
+OPDSFeedMetadata::OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) :
+ ATOMFeedMetadata(id, title, updated), myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) {
+}
diff --git a/reader/src/network/opds/OPDSMetadata.h b/reader/src/network/opds/OPDSMetadata.h
new file mode 100644
index 0000000..51554dd
--- /dev/null
+++ b/reader/src/network/opds/OPDSMetadata.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSMETADATA_H__
+#define __OPDSMETADATA_H__
+
+#include <map>
+
+#include "../atom/ATOMContainers.h"
+
+
+class OPDSConstants {
+
+private:
+ OPDSConstants();
+
+public:
+
+ //TODO get other relations from FBReaderJ
+
+ // Feed level
+ static const std::string REL_BOOKSHELF;
+ static const std::string REL_RECOMMENDATIONS;
+
+ //static const std::string REL_SUBSCRIPTIONS;
+
+ // Entry level / catalog types
+ static const std::string REL_CATALOG_AUTHOR;
+
+ // Entry level / acquisition links
+ static const std::string REL_ACQUISITION;
+ static const std::string REL_ACQUISITION_OPEN;
+ static const std::string REL_ACQUISITION_BUY;
+// static const std::string REL_ACQUISITION_BORROW;
+// static const std::string REL_ACQUISITION_SUBSCRIBE;
+ static const std::string REL_ACQUISITION_SAMPLE;
+ static const std::string REL_ACQUISITION_CONDITIONAL;
+ static const std::string REL_ACQUISITION_SAMPLE_OR_FULL;
+
+ // Entry level / other
+ static const std::string REL_IMAGE_PREFIX;
+ //static const std::string REL_IMAGE;
+ static const std::string REL_IMAGE_THUMBNAIL;
+ static const std::string REL_COVER;
+ static const std::string REL_THUMBNAIL;
+
+ // Entry level / OPDS Link Relations
+ static const std::string REL_LINK_SIGN_IN;
+ static const std::string REL_LINK_SIGN_OUT;
+ static const std::string REL_LINK_SIGN_UP;
+ static const std::string REL_LINK_TOPUP;
+ static const std::string REL_LINK_RECOVER_PASSWORD;
+};
+
+
+class DCDate : public ATOMDateConstruct {
+
+public:
+ DCDate();
+ DCDate(int year);
+ DCDate(int year, int month, int day);
+ DCDate(int year, int month, int day, int hour, int minutes, int seconds);
+ DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract);
+ DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes);
+};
+
+class OPDSEntry : public ATOMEntry {
+
+public:
+ OPDSEntry();
+ OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated);
+
+ const std::string &dcLanguage() const { return myDCLanguage; }
+ const std::string &dcPublisher() const { return myDCPublisher; }
+ shared_ptr<DCDate> dcIssued() { return myDCIssued; }
+ const std::string &seriesTitle() const { return mySeriesTitle; }
+ int seriesIndex() const { return mySeriesIndex; }
+
+ void setDCLanguage(const std::string &language) { myDCLanguage = language; }
+ void setDCPublisher(const std::string &publisher) { myDCPublisher = publisher; }
+ void setDCIssued(shared_ptr<DCDate> issued) { myDCIssued = issued; }
+ void setSeriesTitle(const std::string &seriesTitle) { mySeriesTitle = seriesTitle; }
+ void setSeriesIndex(int seriesIndex) { mySeriesIndex = seriesIndex; }
+
+private:
+ std::string myDCLanguage;
+ std::string myDCPublisher;
+ shared_ptr<DCDate> myDCIssued;
+
+ std::string mySeriesTitle;
+ int mySeriesIndex;
+};
+
+
+
+class OPDSFeedMetadata : public ATOMFeedMetadata {
+
+public:
+ OPDSFeedMetadata();
+ OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated);
+
+ unsigned long getOpensearchTotalResults() const;
+ unsigned long getOpensearchItemsPerPage() const;
+ unsigned long getOpensearchStartIndex() const;
+
+ void setOpensearchTotalResults(unsigned long number);
+ void setOpensearchItemsPerPage(unsigned long number);
+ void setOpensearchStartIndex(unsigned long number);
+
+private:
+ unsigned long myOpensearchTotalResults;
+ unsigned long myOpensearchItemsPerPage;
+ unsigned long myOpensearchStartIndex;
+};
+
+inline unsigned long OPDSFeedMetadata::getOpensearchTotalResults() const { return myOpensearchTotalResults; }
+inline unsigned long OPDSFeedMetadata::getOpensearchItemsPerPage() const { return myOpensearchItemsPerPage; }
+inline unsigned long OPDSFeedMetadata::getOpensearchStartIndex() const { return myOpensearchStartIndex; }
+inline void OPDSFeedMetadata::setOpensearchTotalResults(unsigned long number) { myOpensearchTotalResults = number; }
+inline void OPDSFeedMetadata::setOpensearchItemsPerPage(unsigned long number) { myOpensearchItemsPerPage = number; }
+inline void OPDSFeedMetadata::setOpensearchStartIndex(unsigned long number) { myOpensearchStartIndex = number; }
+
+#endif /* __OPDSMETADATA_H__ */
diff --git a/reader/src/network/opds/OPDSXMLParser.cpp b/reader/src/network/opds/OPDSXMLParser.cpp
new file mode 100644
index 0000000..2b9fb4c
--- /dev/null
+++ b/reader/src/network/opds/OPDSXMLParser.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLUnicodeUtil.h>
+#include <ZLXMLNamespace.h>
+
+#include "OPDSXMLParser.h"
+
+static const std::string TAG_FEED = "feed";
+static const std::string TAG_ENTRY = "entry";
+static const std::string TAG_AUTHOR = "author";
+static const std::string TAG_NAME = "name";
+static const std::string TAG_URI = "uri";
+static const std::string TAG_EMAIL = "email";
+static const std::string TAG_ID = "id";
+static const std::string TAG_CATEGORY = "category";
+static const std::string TAG_LINK = "link";
+static const std::string TAG_PUBLISHED = "published";
+static const std::string TAG_SUMMARY = "summary";
+static const std::string TAG_CONTENT = "content";
+static const std::string TAG_SUBTITLE = "subtitle";
+static const std::string TAG_TITLE = "title";
+static const std::string TAG_UPDATED = "updated";
+static const std::string TAG_PRICE = "price";
+static const std::string TAG_ICON = "icon";
+
+static const std::string TAG_HACK_SPAN = "span";
+
+static const std::string DC_TAG_LANGUAGE = "language";
+static const std::string DC_TAG_ISSUED = "issued";
+static const std::string DC_TAG_PUBLISHER = "publisher";
+static const std::string DC_TAG_FORMAT = "format";
+
+static const std::string CALIBRE_TAG_SERIES = "series";
+static const std::string CALIBRE_TAG_SERIES_INDEX = "series_index";
+
+static const std::string OPENSEARCH_TAG_TOTALRESULTS = "totalResults";
+static const std::string OPENSEARCH_TAG_ITEMSPERPAGE = "itemsPerPage";
+static const std::string OPENSEARCH_TAG_STARTINDEX = "startIndex";
+
+const std::string OPDSXMLParser::KEY_PRICE = "price";
+const std::string OPDSXMLParser::KEY_CURRENCY = "currency";
+const std::string OPDSXMLParser::KEY_FORMAT = "format";
+
+static const std::string TAG_SEARCH_DESCRIPTION = "reader:advancedSearch";
+static const std::string TAG_AUTHENTICATION = "reader:authentication";
+static const std::string TAG_URL_REWRITING_RULES = "reader:urlRewritingRule";
+static const std::string TAG_RELATION_ALIASES = "reader:relationAlias";
+
+OPDSXMLParser::OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed) : myFeedReader(feedReader) {
+ myState = readEntryNotFeed ? FEED : START;
+}
+
+bool OPDSXMLParser::processNamespaces() const {
+ return true;
+}
+
+void OPDSXMLParser::startElementHandler(const char *tag, const char **attributes) {
+ std::map<std::string,std::string> attributeMap = getAttributesMap(attributes);
+ switch (myState) {
+ case START:
+ if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) {
+ myFeedReader->processFeedStart();
+ myFeed = new OPDSFeedMetadata();
+ myFeed->readAttributes(attributeMap);
+ myState = FEED;
+ }
+ break;
+ case FEED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) {
+ myAuthor = new ATOMAuthor();
+ myAuthor->readAttributes(attributeMap);
+ myState = F_AUTHOR;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) {
+ myId = new ATOMId();
+ myId->readAttributes(attributeMap);
+ myState = F_ID;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) {
+ myIcon = new ATOMIcon();
+ myIcon->readAttributes(attributeMap);
+ myState = F_ICON;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) {
+ myLink = new ATOMLink();
+ myLink->readAttributes(attributeMap);
+ myState = F_LINK;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) {
+ myCategory = new ATOMCategory();
+ myCategory->readAttributes(attributeMap);
+ myState = F_CATEGORY;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) {
+ //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle
+ //myTitle->readAttributes(attributeMap);
+ myState = F_TITLE;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) {
+ myState = F_SUBTITLE;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) {
+ myState = F_SUMMARY;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) {
+ myUpdated = new ATOMUpdated();
+ myUpdated->readAttributes(attributeMap);
+ myState = F_UPDATED;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) {
+ myEntry = new OPDSEntry();
+ myEntry->readAttributes(attributeMap);
+ mySummaryTagFound = false;
+ myState = F_ENTRY;
+ } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) {
+ myState = OPENSEARCH_TOTALRESULTS;
+ } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) {
+ myState = OPENSEARCH_ITEMSPERPAGE;
+ } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) {
+ myState = OPENSEARCH_STARTINDEX;
+ }
+ break;
+ case F_ENTRY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) {
+ myAuthor = new ATOMAuthor();
+ myAuthor->readAttributes(attributeMap);
+ myState = FE_AUTHOR;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) {
+ myId = new ATOMId();
+ myId->readAttributes(attributeMap);
+ myState = FE_ID;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) {
+ myCategory = new ATOMCategory();
+ myCategory->readAttributes(attributeMap);
+ myState = FE_CATEGORY;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) {
+ myIcon = new ATOMIcon();
+ myIcon->readAttributes(attributeMap);
+ myState = FE_ICON;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) {
+ myLink = new ATOMLink();
+ myLink->readAttributes(attributeMap);
+ myState = FE_LINK;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) {
+ myPublished = new ATOMPublished();
+ myPublished->readAttributes(attributeMap);
+ myState = FE_PUBLISHED;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) {
+ //mySummary = new ATOMSummary(); // TODO:implement ATOMTextConstruct & ATOMSummary
+ //mySummary->readAttributes(attributeMap);
+ myState = FE_SUMMARY;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) {
+ // ???
+ myState = FE_CONTENT;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) {
+ // ???
+ myState = FE_SUBTITLE;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) {
+ //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle
+ //myTitle->readAttributes(attributeMap);
+ myState = FE_TITLE;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) {
+ myUpdated = new ATOMUpdated();
+ myUpdated->readAttributes(attributeMap);
+ myState = FE_UPDATED;
+ } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) {
+ myState = FE_DC_LANGUAGE;
+ } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) {
+ myState = FE_DC_ISSUED;
+ } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) {
+ myState = FE_DC_PUBLISHER;
+ } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) {
+ myState = FE_CALIBRE_SERIES;
+ } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) {
+ myState = FE_CALIBRE_SERIES_INDEX;
+ }
+ break;
+ case F_AUTHOR:
+ if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) {
+ myState = FA_NAME;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) {
+ myState = FA_URI;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) {
+ myState = FA_EMAIL;
+ }
+ break;
+ case FE_TITLE:
+ // TODO: remove this temporary code
+ // DON'T clear myBuffer
+ return;
+ case FE_LINK:
+ if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) {
+ myLink->setUserData(KEY_CURRENCY, attributeMap["currencycode"]);
+ myState = FEL_PRICE;
+ } if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) {
+ myState = FEL_FORMAT;
+ }
+ break;
+ case FE_AUTHOR:
+ if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) {
+ myState = FEA_NAME;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) {
+ myState = FEA_URI;
+ } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) {
+ myState = FEA_EMAIL;
+ }
+ break;
+ case FE_CONTENT:
+ if (TAG_HACK_SPAN == tag || attributeMap["class"] == "price") {
+ myState = FEC_HACK_SPAN;
+ }
+ break;
+ default:
+ break;
+ }
+
+ myBuffer.clear();
+}
+
+void OPDSXMLParser::endElementHandler(const char *tag) {
+ ZLUnicodeUtil::utf8Trim(myBuffer);
+
+ switch (myState) {
+ case START:
+ break;
+ case FEED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) {
+ myFeedReader->processFeedMetadata(myFeed);
+ myFeed.reset();
+ myFeedReader->processFeedEnd();
+ myState = START;
+ }
+ break;
+ case F_ENTRY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) {
+ myFeedReader->processFeedEntry(myEntry);
+ myEntry.reset();
+ myState = FEED;
+ }
+ break;
+ case F_ID:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) {
+ // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag
+ myId->setUri(myBuffer);
+ if (!myFeed.isNull()) {
+ myFeed->setId(myId);
+ }
+ myId.reset();
+ myState = FEED;
+ }
+ break;
+ case F_ICON:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) {
+ myIcon->setUri(myBuffer);
+ if (!myFeed.isNull()) {
+ myFeed->setIcon(myIcon);
+ }
+ myIcon.reset();
+ myState = FEED;
+ }
+ break;
+ case F_LINK:
+ if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) {
+ if (!myFeed.isNull()) {
+ myFeed->links().push_back(myLink);
+ }
+ myLink.reset();
+ myState = FEED;
+ }
+ break;
+ case F_CATEGORY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) {
+ if (!myFeed.isNull()) {
+ myFeed->categories().push_back(myCategory);
+ }
+ myCategory.reset();
+ myState = FEED;
+ }
+ break;
+ case F_TITLE:
+ if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) {
+ // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag
+ // TODO:implement ATOMTextConstruct & ATOMTitle
+ if (!myFeed.isNull()) {
+ myFeed->setTitle(myBuffer);
+ }
+ myState = FEED;
+ }
+ break;
+ case F_SUBTITLE:
+ if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) {
+ if (!myFeed.isNull()) {
+ myFeed->setSubtitle(myBuffer);
+ }
+ myState = FEED;
+ }
+ break;
+ case F_SUMMARY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) {
+ if (!myFeed.isNull()) {
+ myFeed->setSummary(myBuffer);
+ }
+ myState = FEED;
+ }
+ break;
+ case F_UPDATED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) {
+ // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag
+ ATOMDateConstruct::parse(myBuffer, *myUpdated);
+ if (!myFeed.isNull()) {
+ myFeed->setUpdated(myUpdated);
+ }
+ myUpdated.reset();
+ myState = FEED;
+ }
+ break;
+ case F_AUTHOR:
+ if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) {
+ if (!myFeed.isNull()) {
+ myFeed->authors().push_back(myAuthor);
+ }
+ myAuthor.reset();
+ myState = FEED;
+ }
+ break;
+ case FA_NAME:
+ if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) {
+ myAuthor->setName(myBuffer);
+ myState = F_AUTHOR;
+ }
+ break;
+ case FEA_NAME:
+ if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) {
+ myAuthor->setName(myBuffer);
+ myState = FE_AUTHOR;
+ }
+ break;
+ case FEL_PRICE:
+ if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) {
+ myLink->setUserData(KEY_PRICE, myBuffer);
+ myState = FE_LINK;
+ }
+ break;
+ case FEL_FORMAT:
+ if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) {
+ myLink->setUserData(KEY_FORMAT, myBuffer);
+ myState = FE_LINK;
+ }
+ break;
+ case FA_URI:
+ if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) {
+ myAuthor->setUri(myBuffer);
+ myState = F_AUTHOR;
+ }
+ break;
+ case FEA_URI:
+ if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) {
+ myAuthor->setUri(myBuffer);
+ myState = FE_AUTHOR;
+ }
+ break;
+ case FA_EMAIL:
+ if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) {
+ myAuthor->setEmail(myBuffer);
+ myState = F_AUTHOR;
+ }
+ break;
+ case FEA_EMAIL:
+ if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) {
+ myAuthor->setEmail(myBuffer);
+ myState = FE_AUTHOR;
+ }
+ break;
+ case FE_AUTHOR:
+ if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) {
+ myEntry->authors().push_back(myAuthor);
+ myAuthor.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_ICON:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) {
+ myIcon->setUri(myBuffer);
+ if (!myEntry.isNull()) {
+ myEntry->setIcon(myIcon);
+ }
+ myIcon.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_ID:
+ if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) {
+ // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag
+ myId->setUri(myBuffer);
+ myEntry->setId(myId);
+ myId.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_CATEGORY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) {
+ myEntry->categories().push_back(myCategory);
+ myCategory.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_LINK:
+ if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) {
+ myEntry->links().push_back(myLink);
+ myLink.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_PUBLISHED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) {
+ // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag
+ ATOMDateConstruct::parse(myBuffer, *myPublished);
+ myEntry->setPublished(myPublished);
+ myPublished.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_SUMMARY:
+ if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) {
+ // FIXME:summary can be lost:buffer will be truncated, if there are extension tags inside the <summary> tag
+ // TODO:implement ATOMTextConstruct & ATOMSummary
+ myEntry->setSummary(myBuffer);
+ mySummaryTagFound = true;
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_CONTENT:
+ if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) {
+ // TODO:check this accurately
+ if (!mySummaryTagFound) {
+ myEntry->setSummary(myBuffer);
+ }
+ myState = F_ENTRY;
+ }
+ break;
+ case FEC_HACK_SPAN:
+ myEntry->setUserData(KEY_PRICE, myBuffer);
+ myState = FE_CONTENT;
+ break;
+ case FE_SUBTITLE:
+ if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) {
+ // TODO:check this accurately
+ if (!mySummaryTagFound) {
+ myEntry->setSummary(myBuffer);
+ }
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_TITLE:
+ if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) {
+ // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag
+ // TODO:implement ATOMTextConstruct & ATOMTitle
+ myEntry->setTitle(myBuffer);
+ myState = F_ENTRY;
+ } else {
+ // TODO: remove this temporary code
+ // DON'T clear myBuffer
+ return;
+ }
+ break;
+ case FE_UPDATED:
+ if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) {
+ // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag
+ ATOMDateConstruct::parse(myBuffer, *myUpdated);
+ myEntry->setUpdated(myUpdated);
+ myUpdated.reset();
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_DC_LANGUAGE:
+ if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) {
+ // FIXME:language can be lost:buffer will be truncated, if there are extension tags inside the <dc:language> tag
+ myEntry->setDCLanguage(myBuffer);
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_DC_ISSUED:
+ if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) {
+ // FIXME:issued can be lost:buffer will be truncated, if there are extension tags inside the <dc:issued> tag
+ DCDate *issued = new DCDate();
+ ATOMDateConstruct::parse(myBuffer, *issued);
+ myEntry->setDCIssued(issued);
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_DC_PUBLISHER:
+ if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) {
+ // FIXME:publisher can be lost:buffer will be truncated, if there are extension tags inside the <dc:publisher> tag
+ myEntry->setDCPublisher(myBuffer);
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_CALIBRE_SERIES:
+ if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) {
+ myEntry->setSeriesTitle(myBuffer);
+ myState = F_ENTRY;
+ }
+ break;
+ case FE_CALIBRE_SERIES_INDEX:
+ if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) {
+ myEntry->setSeriesIndex(std::atoi(myBuffer.c_str()));
+ myState = F_ENTRY;
+ }
+ break;
+ case OPENSEARCH_TOTALRESULTS:
+ if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) {
+ int number = std::atoi(myBuffer.c_str());
+ if (!myFeed.isNull()) {
+ myFeed->setOpensearchTotalResults(number);
+ }
+ myState = FEED;
+ }
+ break;
+ case OPENSEARCH_ITEMSPERPAGE:
+ if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) {
+ int number = std::atoi(myBuffer.c_str());
+ if (!myFeed.isNull()) {
+ myFeed->setOpensearchItemsPerPage(number);
+ }
+ myState = FEED;
+ }
+ break;
+ case OPENSEARCH_STARTINDEX:
+ if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) {
+ int number = std::atoi(myBuffer.c_str());
+ if (!myFeed.isNull()) {
+ myFeed->setOpensearchStartIndex(number);
+ }
+ myState = FEED;
+ }
+ break;
+ }
+
+ myBuffer.clear();
+}
+
+void OPDSXMLParser::characterDataHandler(const char *data, std::size_t len) {
+ myBuffer.append(data, len);
+}
diff --git a/reader/src/network/opds/OPDSXMLParser.h b/reader/src/network/opds/OPDSXMLParser.h
new file mode 100644
index 0000000..82f0124
--- /dev/null
+++ b/reader/src/network/opds/OPDSXMLParser.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPDSXMLPARSER_H__
+#define __OPDSXMLPARSER_H__
+
+#include <ZLXMLReader.h>
+
+#include "OPDSMetadata.h"
+#include "OPDSFeedReader.h"
+
+
+class OPDSXMLParser : public ZLXMLReader {
+
+public:
+ static const std::string KEY_PRICE;
+ static const std::string KEY_CURRENCY;
+ static const std::string KEY_FORMAT;
+
+public:
+ OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed = false);
+
+protected:
+ 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;
+
+protected:
+ enum State {
+ START,
+ FEED, F_ENTRY, F_ID, F_LINK, F_CATEGORY, F_TITLE, F_UPDATED, F_AUTHOR, F_SUBTITLE, F_ICON, F_SUMMARY,
+ FA_NAME, FA_URI, FA_EMAIL,
+ FE_AUTHOR, FE_ID, FE_CATEGORY, FE_LINK, FE_PUBLISHED, FE_SUMMARY, FE_CONTENT, FE_SUBTITLE, FE_TITLE, FE_ICON, FE_UPDATED, FE_DC_LANGUAGE, FE_DC_ISSUED, FE_DC_PUBLISHER, FE_CALIBRE_SERIES, FE_CALIBRE_SERIES_INDEX,
+ FEL_PRICE, FEL_FORMAT,
+ FEA_NAME, FEA_URI, FEA_EMAIL,
+ OPENSEARCH_TOTALRESULTS, OPENSEARCH_ITEMSPERPAGE, OPENSEARCH_STARTINDEX,
+ FEC_HACK_SPAN,
+ };
+
+protected:
+ shared_ptr<OPDSFeedReader> myFeedReader;
+ State myState;
+
+private:
+ std::string myBuffer;
+ shared_ptr<OPDSFeedMetadata> myFeed;
+ shared_ptr<OPDSEntry> myEntry;
+
+ shared_ptr<ATOMAuthor> myAuthor;
+ shared_ptr<ATOMId> myId;
+ shared_ptr<ATOMIcon> myIcon;
+ shared_ptr<ATOMLink> myLink;
+ shared_ptr<ATOMCategory> myCategory;
+ shared_ptr<ATOMUpdated> myUpdated;
+ shared_ptr<ATOMPublished> myPublished;
+
+ //shared_ptr<ATOMTitle> myTitle; // TODO: implement ATOMTextConstruct & ATOMTitle
+ //shared_ptr<ATOMSummary> mySummary; // TODO: implement ATOMTextConstruct & ATOMSummary
+ bool mySummaryTagFound;
+};
+
+#endif /* __OPDSXMLPARSER_H__ */
diff --git a/reader/src/network/opds/OpenSearchXMLReader.cpp b/reader/src/network/opds/OpenSearchXMLReader.cpp
new file mode 100644
index 0000000..686d8c1
--- /dev/null
+++ b/reader/src/network/opds/OpenSearchXMLReader.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 "OpenSearchXMLReader.h"
+#include <ZLMimeType.h>
+
+static const std::string TAG_URL = "Url";
+
+std::string OpenSearchXMLReader::convertOpenSearchURL(const std::string& raws) { //TODO
+ std::size_t pos = raws.find('{');
+ return raws.substr(0, pos) + "%s";
+}
+
+void OpenSearchXMLReader::startElementHandler(const char *tag, const char **attributes) {
+ if (TAG_URL == tag) {
+ const char *type = attributeValue(attributes, "type");
+ if (ZLMimeType::get(type)->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) {
+ const char *templ = attributeValue(attributes, "template");
+ if (templ != 0) {
+ myTemplateURL = convertOpenSearchURL(templ);
+ }
+ }
+ }
+}
+
+void OpenSearchXMLReader::endElementHandler(const char *tag) {
+ (void)tag;
+}
+
+void OpenSearchXMLReader::characterDataHandler(const char *text, std::size_t len) {
+ (void)text;
+ (void)len;
+}
diff --git a/reader/src/network/opds/OpenSearchXMLReader.h b/reader/src/network/opds/OpenSearchXMLReader.h
new file mode 100644
index 0000000..2b53f19
--- /dev/null
+++ b/reader/src/network/opds/OpenSearchXMLReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __OPENSEARCHXMLREADER_H__
+#define __OPENSEARCHXMLREADER_H__
+
+#include <string>
+#include <ZLXMLReader.h>
+
+class OpenSearchXMLReader : public ZLXMLReader {
+
+public:
+ OpenSearchXMLReader() {}
+ std::string templateURL() {return myTemplateURL;}
+
+ static std::string convertOpenSearchURL(const std::string& raws);
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+ void characterDataHandler(const char *text, std::size_t len);
+ std::string myTemplateURL;
+
+};
+
+#endif /* __OPENSEARCHXMLREADER_H__ */
diff --git a/reader/src/network/opds/URLRewritingRule.cpp b/reader/src/network/opds/URLRewritingRule.cpp
new file mode 100644
index 0000000..8cea851
--- /dev/null
+++ b/reader/src/network/opds/URLRewritingRule.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 <ZLNetworkUtil.h>
+
+#include "URLRewritingRule.h"
+
+URLRewritingRule::URLRewritingRule(const std::map<std::string,std::string> &map) : myType(UNKNOWN), myApply(ALWAYS) {
+ for (std::map<std::string, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) {
+ std::string key = (*it).first;
+ std::string value = (*it).second;
+
+ if (key == "type") {
+ if (value == "addUrlParameter") {
+ myType = ADD_URL_PARAMETER;
+ } else if (value == "rewrite") {
+ myType = REWRITE;
+ }
+ } else if (key == "apply") {
+ if (value == "internal") {
+ myApply = INTERNAL;
+ } else if (value == "external") {
+ myApply = EXTERNAL;
+ }
+ } else {
+ myParameters.insert(std::make_pair(key, value));
+ }
+
+ }
+}
+
+std::string URLRewritingRule::apply(const std::string &url) const {
+ std::string appliedUrl = url;
+ switch (myType) {
+ case ADD_URL_PARAMETER:
+ {
+ std::string name, value;
+ std::map<std::string, std::string>::const_iterator it;
+ it = myParameters.find("name");
+ if (it != myParameters.end()) {
+ name = (*it).second;
+ }
+ it = myParameters.find("value");
+ if (it != myParameters.end()) {
+ value = (*it).second;
+ }
+ if (name.empty() || value.empty()) {
+ break;
+ }
+ ZLNetworkUtil::appendParameter(appliedUrl, name, value);
+ }
+ case REWRITE: //TODO implement (regular expressions should be used here)
+ default:
+ break;
+ }
+ return appliedUrl;
+}
+
+URLRewritingRule::RuleApply URLRewritingRule::whereToApply() const {
+ return myApply;
+}
diff --git a/reader/src/network/opds/URLRewritingRule.h b/reader/src/network/opds/URLRewritingRule.h
new file mode 100644
index 0000000..1251139
--- /dev/null
+++ b/reader/src/network/opds/URLRewritingRule.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com>
+ *
+ * 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 __URLREWRITINGRULE_H__
+#define __URLREWRITINGRULE_H__
+
+#include <string>
+#include <map>
+
+class URLRewritingRule {
+
+public:
+ enum RuleType {
+ ADD_URL_PARAMETER,
+ REWRITE,
+ UNKNOWN,
+ };
+
+ enum RuleApply {
+ ALWAYS, EXTERNAL, INTERNAL
+ };
+
+ URLRewritingRule(const std::map<std::string,std::string> &attributesMap);
+ std::string apply(const std::string &url) const;
+ RuleApply whereToApply() const;
+
+private:
+ RuleType myType;
+ RuleApply myApply;
+ std::map<std::string, std::string> myParameters;
+};
+
+
+#endif /* __URLREWRITINGRULE_H__ */