mirror of https://github.com/kiwix/libkiwix.git
323 lines
8.1 KiB
C++
323 lines
8.1 KiB
C++
/*
|
|
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
|
*
|
|
* 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 3 of the License, or
|
|
* 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 "manager.h"
|
|
|
|
#include "tools.h"
|
|
#include "tools/pathTools.h"
|
|
|
|
#include <pugixml.hpp>
|
|
|
|
namespace kiwix
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
struct NoDelete
|
|
{
|
|
template<class T> void operator()(T*) {}
|
|
};
|
|
|
|
} // unnamed namespace
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// LibraryManipulator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LibraryManipulator::LibraryManipulator(Library* library)
|
|
: library(*library)
|
|
{}
|
|
|
|
LibraryManipulator::~LibraryManipulator()
|
|
{}
|
|
|
|
bool LibraryManipulator::addBookToLibrary(const Book& book)
|
|
{
|
|
const auto ret = library.addBook(book);
|
|
if ( ret ) {
|
|
bookWasAddedToLibrary(book);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void LibraryManipulator::addBookmarkToLibrary(const Bookmark& bookmark)
|
|
{
|
|
library.addBookmark(bookmark);
|
|
bookmarkWasAddedToLibrary(bookmark);
|
|
}
|
|
|
|
uint32_t LibraryManipulator::removeBooksNotUpdatedSince(Library::Revision rev)
|
|
{
|
|
const auto n = library.removeBooksNotUpdatedSince(rev);
|
|
if ( n != 0 ) {
|
|
booksWereRemovedFromLibrary();
|
|
}
|
|
return n;
|
|
}
|
|
|
|
void LibraryManipulator::bookWasAddedToLibrary(const Book& book)
|
|
{
|
|
}
|
|
|
|
void LibraryManipulator::bookmarkWasAddedToLibrary(const Bookmark& bookmark)
|
|
{
|
|
}
|
|
|
|
void LibraryManipulator::booksWereRemovedFromLibrary()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Manager
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* Constructor */
|
|
Manager::Manager(LibraryManipulator* manipulator):
|
|
writableLibraryPath(""),
|
|
manipulator(manipulator, NoDelete())
|
|
{
|
|
}
|
|
|
|
Manager::Manager(Library* library) :
|
|
writableLibraryPath(""),
|
|
manipulator(new LibraryManipulator(library))
|
|
{
|
|
}
|
|
|
|
bool Manager::parseXmlDom(const pugi::xml_document& doc,
|
|
bool readOnly,
|
|
const std::string& libraryPath,
|
|
bool trustLibrary)
|
|
{
|
|
pugi::xml_node libraryNode = doc.child("library");
|
|
|
|
std::string libraryVersion = libraryNode.attribute("version").value();
|
|
|
|
for (pugi::xml_node bookNode = libraryNode.child("book"); bookNode;
|
|
bookNode = bookNode.next_sibling("book")) {
|
|
kiwix::Book book;
|
|
|
|
book.setReadOnly(readOnly);
|
|
book.updateFromXml(bookNode,
|
|
removeLastPathElement(libraryPath));
|
|
|
|
if (!trustLibrary && !book.getPath().empty()) {
|
|
this->readBookFromPath(book.getPath(), &book);
|
|
}
|
|
manipulator->addBookToLibrary(book);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Manager::readXml(const std::string& xml,
|
|
bool readOnly,
|
|
const std::string& libraryPath,
|
|
bool trustLibrary)
|
|
{
|
|
pugi::xml_document doc;
|
|
pugi::xml_parse_result result
|
|
= doc.load_buffer((void*)xml.data(), xml.size());
|
|
|
|
if (result) {
|
|
this->parseXmlDom(doc, readOnly, libraryPath, trustLibrary);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool Manager::parseOpdsDom(const pugi::xml_document& doc, const std::string& urlHost)
|
|
{
|
|
pugi::xml_node libraryNode = doc.child("feed");
|
|
|
|
try {
|
|
m_totalBooks = strtoull(libraryNode.child("totalResults").child_value(), 0, 0);
|
|
m_startIndex = strtoull(libraryNode.child("startIndex").child_value(), 0, 0);
|
|
m_itemsPerPage = strtoull(libraryNode.child("itemsPerPage").child_value(), 0, 0);
|
|
m_hasSearchResult = true;
|
|
} catch(...) {
|
|
m_hasSearchResult = false;
|
|
}
|
|
|
|
for (pugi::xml_node entryNode = libraryNode.child("entry"); entryNode;
|
|
entryNode = entryNode.next_sibling("entry")) {
|
|
kiwix::Book book;
|
|
|
|
book.setReadOnly(false);
|
|
book.updateFromOpds(entryNode, urlHost);
|
|
|
|
/* Update the book properties with the new importer */
|
|
manipulator->addBookToLibrary(book);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool Manager::readOpds(const std::string& content, const std::string& urlHost)
|
|
{
|
|
pugi::xml_document doc;
|
|
pugi::xml_parse_result result
|
|
= doc.load_buffer((void*)content.data(), content.size());
|
|
|
|
if (result) {
|
|
this->parseOpdsDom(doc, urlHost);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Manager::readFile(
|
|
const std::string& path,
|
|
bool readOnly,
|
|
bool trustLibrary)
|
|
{
|
|
bool retVal = true;
|
|
pugi::xml_document doc;
|
|
|
|
#ifdef _WIN32
|
|
pugi::xml_parse_result result = doc.load_file(Utf8ToWide(path).c_str());
|
|
#else
|
|
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
|
#endif
|
|
|
|
if (result) {
|
|
this->parseXmlDom(doc, readOnly, path, trustLibrary);
|
|
} else {
|
|
retVal = false;
|
|
}
|
|
|
|
/* This has to be set (although if the file does not exists) to be
|
|
* able to know where to save the library if new content are
|
|
* available */
|
|
if (!readOnly) {
|
|
this->writableLibraryPath = path;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/* Add a book to the library. Return empty string if failed, book id otherwise
|
|
*/
|
|
std::string Manager::addBookFromPathAndGetId(const std::string& pathToOpen,
|
|
const std::string& pathToSave,
|
|
const std::string& url,
|
|
const bool checkMetaData)
|
|
{
|
|
kiwix::Book book;
|
|
|
|
if (this->readBookFromPath(pathToOpen, &book)) {
|
|
if (!pathToSave.empty() && pathToSave != pathToOpen) {
|
|
book.setPath(isRelativePath(pathToSave)
|
|
? computeAbsolutePath(
|
|
removeLastPathElement(writableLibraryPath),
|
|
pathToSave)
|
|
: pathToSave);
|
|
}
|
|
|
|
if (!checkMetaData
|
|
|| (checkMetaData && !book.getTitle().empty() && !book.getLanguage().empty()
|
|
&& !book.getDate().empty())) {
|
|
book.setUrl(url);
|
|
manipulator->addBookToLibrary(book);
|
|
return book.getId();
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
/* Wrapper over Manager::addBookFromPath which return a bool instead of a string
|
|
*/
|
|
bool Manager::addBookFromPath(const std::string& pathToOpen,
|
|
const std::string& pathToSave,
|
|
const std::string& url,
|
|
const bool checkMetaData)
|
|
{
|
|
return !(
|
|
this->addBookFromPathAndGetId(pathToOpen, pathToSave, url, checkMetaData)
|
|
.empty());
|
|
}
|
|
|
|
bool Manager::readBookFromPath(const std::string& path, kiwix::Book* book)
|
|
{
|
|
std::string tmp_path = path;
|
|
if (isRelativePath(path)) {
|
|
tmp_path = computeAbsolutePath(getCurrentDirectory(), path);
|
|
}
|
|
try {
|
|
zim::Archive archive(tmp_path);
|
|
book->update(archive);
|
|
book->setPathValid(true);
|
|
} catch (const std::exception& e) {
|
|
book->setPathValid(false);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Manager::readBookmarkFile(const std::string& path)
|
|
{
|
|
pugi::xml_document doc;
|
|
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
|
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
|
|
pugi::xml_node libraryNode = doc.child("bookmarks");
|
|
|
|
for (pugi::xml_node node = libraryNode.child("bookmark"); node;
|
|
node = node.next_sibling("bookmark")) {
|
|
kiwix::Bookmark bookmark;
|
|
|
|
bookmark.updateFromXml(node);
|
|
|
|
manipulator->addBookmarkToLibrary(bookmark);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Manager::reload(const Paths& paths)
|
|
{
|
|
const auto libRevision = manipulator->getLibrary().getRevision();
|
|
for (std::string path : paths) {
|
|
if (!path.empty()) {
|
|
if ( kiwix::isRelativePath(path) )
|
|
path = kiwix::computeAbsolutePath(kiwix::getCurrentDirectory(), path);
|
|
|
|
if (!readFile(path, false, true)) {
|
|
throw std::runtime_error("Failed to load the XML library file '" + path + "'.");
|
|
}
|
|
}
|
|
}
|
|
|
|
manipulator->removeBooksNotUpdatedSince(libRevision);
|
|
}
|
|
|
|
}
|