diff --git a/include/library.h b/include/library.h index e24bf9d7e..9339cac0d 100644 --- a/include/library.h +++ b/include/library.h @@ -52,7 +52,6 @@ class Library Library(); ~Library(); - std::string version; /** * Add a book to the library. * @@ -163,6 +162,7 @@ class Library size_t maxSize = 0); friend class OPDSDumper; + friend class libXMLDumper; }; } diff --git a/include/libxml_dumper.h b/include/libxml_dumper.h new file mode 100644 index 000000000..ff890a9da --- /dev/null +++ b/include/libxml_dumper.h @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Matthieu Gautier + * + * 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. + */ + +#ifndef KIWIX_LIBXML_DUMPER_H +#define KIWIX_LIBXML_DUMPER_H + +#include +#include + +#include + +#include "library.h" + +namespace kiwix +{ + +/** + * A tool to dump a `Library` into a basic library.xml + * + */ +class LibXMLDumper +{ + public: + LibXMLDumper() = default; + LibXMLDumper(Library* library); + ~LibXMLDumper(); + + /** + * Dump the library.xml + * + * @param id The id of the library. + * @return The library.xml content. + */ + std::string dumpLibXMLContent(const std::vector& bookIds); + + /** + * Set the base directory used. + * + * @param baseDir the base directory to use. + */ + void setBaseDir(const std::string& baseDir) { this->baseDir = baseDir; } + + /** + * Set the library to dump. + * + * @param library The library to dump. + */ + void setLibrary(Library* library) { this->library = library; } + + protected: + kiwix::Library* library; + std::string baseDir; + private: + void handleBook(Book book, pugi::xml_node root_node); +}; +} + +#endif // KIWIX_OPDS_DUMPER_H diff --git a/include/meson.build b/include/meson.build index e7ab6eca8..819a1828b 100644 --- a/include/meson.build +++ b/include/meson.build @@ -3,6 +3,7 @@ headers = [ 'common.h', 'library.h', 'manager.h', + 'libxml_dumper.h', 'opds_dumper.h', 'downloader.h', 'reader.h', diff --git a/src/library.cpp b/src/library.cpp index 34650c2f8..a56876c8d 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -19,6 +19,7 @@ #include "library.h" #include "book.h" +#include "libxml_dumper.h" #include "common/base64.h" #include "common/regexTools.h" @@ -30,7 +31,7 @@ namespace kiwix { /* Constructor */ -Library::Library() : version(KIWIX_LIBRARY_VERSION) +Library::Library() { } /* Destructor */ @@ -78,91 +79,10 @@ unsigned int Library::getBookCount(const bool localBooks, } bool Library::writeToFile(const std::string& path) { - pugi::xml_document doc; auto baseDir = removeLastPathElement(path, true, false); - - /* Add the library node */ - pugi::xml_node libraryNode = doc.append_child("library"); - - if (!version.empty()) - libraryNode.append_attribute("version") = version.c_str(); - - /* Add each book */ - for (auto& pair: books) { - auto& book = pair.second; - if (!book.readOnly()) { - pugi::xml_node bookNode = libraryNode.append_child("book"); - bookNode.append_attribute("id") = book.getId().c_str(); - - if (!book.getPath().empty()) { - bookNode.append_attribute("path") = computeRelativePath( - baseDir, book.getPath()).c_str(); - } - - if (!book.getIndexPath().empty()) { - bookNode.append_attribute("indexPath") = computeRelativePath( - baseDir, book.getIndexPath()).c_str(); - bookNode.append_attribute("indexType") = "xapian"; - } - - if (book.getOrigId().empty()) { - if (!book.getTitle().empty()) - bookNode.append_attribute("title") = book.getTitle().c_str(); - - if (!book.getName().empty()) - bookNode.append_attribute("name") = book.getName().c_str(); - - if (!book.getTags().empty()) - bookNode.append_attribute("tags") = book.getTags().c_str(); - - if (!book.getDescription().empty()) - bookNode.append_attribute("description") = book.getDescription().c_str(); - - if (!book.getLanguage().empty()) - bookNode.append_attribute("language") = book.getLanguage().c_str(); - - if (!book.getCreator().empty()) - bookNode.append_attribute("creator") = book.getCreator().c_str(); - - if (!book.getPublisher().empty()) - bookNode.append_attribute("publisher") = book.getPublisher().c_str(); - - if (!book.getFavicon().empty()) - bookNode.append_attribute("favicon") = base64_encode(book.getFavicon()).c_str(); - - if (!book.getFaviconMimeType().empty()) - bookNode.append_attribute("faviconMimeType") - = book.getFaviconMimeType().c_str(); - } else { - bookNode.append_attribute("origId") = book.getOrigId().c_str(); - } - - if (!book.getDate().empty()) { - bookNode.append_attribute("date") = book.getDate().c_str(); - } - - if (!book.getUrl().empty()) { - bookNode.append_attribute("url") = book.getUrl().c_str(); - } - - if (book.getArticleCount()) - bookNode.append_attribute("articleCount") = to_string(book.getArticleCount()).c_str(); - - if (book.getMediaCount()) - bookNode.append_attribute("mediaCount") = to_string(book.getMediaCount()).c_str(); - - if (book.getSize()) { - bookNode.append_attribute("size") = to_string(book.getSize()>>10).c_str(); - } - - if (!book.getDownloadId().empty()) { - bookNode.append_attribute("downloadId") = book.getDownloadId().c_str(); - } - } - } - - /* saving file */ - return doc.save_file(path.c_str()); + LibXMLDumper dumper(this); + dumper.setBaseDir(baseDir); + return writeTextFile(path, dumper.dumpLibXMLContent(getBooksIds())); } std::vector Library::getBooksLanguages() diff --git a/src/libxml_dumper.cpp b/src/libxml_dumper.cpp new file mode 100644 index 000000000..e7e9fbbb4 --- /dev/null +++ b/src/libxml_dumper.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2017 Matthieu Gautier + * + * 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 "libxml_dumper.h" +#include "book.h" + +#include +#include +#include + +namespace kiwix +{ +/* Constructor */ +LibXMLDumper::LibXMLDumper(Library* library) + : library(library) +{ +} +/* Destructor */ +LibXMLDumper::~LibXMLDumper() +{ +} + +#define ADD_ATTRIBUTE(node, name, value) { (node).append_attribute((name)) = (value).c_str(); } +#define ADD_ATTR_NOT_EMPTY(node, name, value) { if (!(value).empty()) ADD_ATTRIBUTE(node, name, value); } + +void LibXMLDumper::handleBook(Book book, pugi::xml_node root_node) { + if (book.readOnly()) + return; + + auto entry_node = root_node.append_child("book"); + ADD_ATTRIBUTE(entry_node, "id", book.getId()); + + if (!book.getPath().empty()) { + ADD_ATTRIBUTE(entry_node, "path", computeRelativePath(baseDir, book.getPath())); + } + + if (!book.getIndexPath().empty()) { + ADD_ATTRIBUTE(entry_node, "indexPath", computeRelativePath(baseDir, book.getIndexPath())); + entry_node.append_attribute("indexType") = "xapian"; + } + + if (book.getOrigId().empty()) { + ADD_ATTR_NOT_EMPTY(entry_node, "title", book.getTitle()); + ADD_ATTR_NOT_EMPTY(entry_node, "name", book.getName()); + ADD_ATTR_NOT_EMPTY(entry_node, "tags", book.getTags()); + ADD_ATTR_NOT_EMPTY(entry_node, "description", book.getDescription()); + ADD_ATTR_NOT_EMPTY(entry_node, "language", book.getLanguage()); + ADD_ATTR_NOT_EMPTY(entry_node, "creator", book.getCreator()); + ADD_ATTR_NOT_EMPTY(entry_node, "publisher", book.getPublisher()); + ADD_ATTR_NOT_EMPTY(entry_node, "faviconMimeType", book.getFaviconMimeType()); + ADD_ATTR_NOT_EMPTY(entry_node, "language", book.getLanguage()); + ADD_ATTR_NOT_EMPTY(entry_node, "language", book.getLanguage()); + if (!book.getFavicon().empty()) + ADD_ATTRIBUTE(entry_node, "favicon", base64_encode(book.getFavicon())); + } else { + ADD_ATTRIBUTE(entry_node, "origId", book.getOrigId()); + } + + ADD_ATTR_NOT_EMPTY(entry_node, "date", book.getDate()); + ADD_ATTR_NOT_EMPTY(entry_node, "url", book.getUrl()); + + if (book.getArticleCount()) + ADD_ATTRIBUTE(entry_node, "articleCount", to_string(book.getArticleCount())); + + if (book.getMediaCount()) + ADD_ATTRIBUTE(entry_node, "mediaCount", to_string(book.getMediaCount())); + + if (book.getSize()) + ADD_ATTRIBUTE(entry_node, "size", to_string(book.getSize()>>10)); + + ADD_ATTR_NOT_EMPTY(entry_node, "downloadId", book.getDownloadId()); +} + +string LibXMLDumper::dumpLibXMLContent(const std::vector& bookIds) +{ + pugi::xml_document doc; + + /* Add the library node */ + pugi::xml_node libraryNode = doc.append_child("library"); + + libraryNode.append_attribute("version") = KIWIX_LIBRARY_VERSION; + + if (library) { + for (auto& bookId: bookIds) { + handleBook(library->getBookById(bookId), libraryNode); + } + } + + return nodeToString(libraryNode); +} + +} diff --git a/src/meson.build b/src/meson.build index deefdac8f..94288310f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,6 +2,7 @@ kiwix_sources = [ 'book.cpp', 'library.cpp', 'manager.cpp', + 'libxml_dumper.cpp', 'opds_dumper.cpp', 'downloader.cpp', 'reader.cpp',