diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-06-07 23:30:05 +0900 |
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-06-07 23:30:05 +0900 |
| commit | 17b259df9cb6b28779d4881b2b6c805ee2e48eea (patch) | |
| tree | 5ed61937459cb7081089111b0242c01ec178f1f3 /reader/src/network/opds | |
| parent | 1cba8bce178eb2d6719c6f7f21e2c9352c5513a6 (diff) | |
| download | tde-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')
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__ */ |
