summaryrefslogtreecommitdiffstats
path: root/fbreader/src/formats/fb2
diff options
context:
space:
mode:
Diffstat (limited to 'fbreader/src/formats/fb2')
-rw-r--r--fbreader/src/formats/fb2/FB2BookReader.cpp336
-rw-r--r--fbreader/src/formats/fb2/FB2BookReader.h61
-rw-r--r--fbreader/src/formats/fb2/FB2CoverReader.cpp92
-rw-r--r--fbreader/src/formats/fb2/FB2CoverReader.h49
-rw-r--r--fbreader/src/formats/fb2/FB2MetaInfoReader.cpp206
-rw-r--r--fbreader/src/formats/fb2/FB2MetaInfoReader.h60
-rw-r--r--fbreader/src/formats/fb2/FB2Plugin.cpp48
-rw-r--r--fbreader/src/formats/fb2/FB2Plugin.h42
-rw-r--r--fbreader/src/formats/fb2/FB2Reader.cpp89
-rw-r--r--fbreader/src/formats/fb2/FB2Reader.h94
-rw-r--r--fbreader/src/formats/fb2/FB2TagManager.cpp124
-rw-r--r--fbreader/src/formats/fb2/FB2TagManager.h45
12 files changed, 1246 insertions, 0 deletions
diff --git a/fbreader/src/formats/fb2/FB2BookReader.cpp b/fbreader/src/formats/fb2/FB2BookReader.cpp
new file mode 100644
index 0000000..f689343
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2BookReader.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <cstdlib>
+#include <cstring>
+
+#include <ZLInputStream.h>
+#include <ZLStringUtil.h>
+#include <ZLFileImage.h>
+
+#include <ZLTextParagraph.h>
+
+#include "FB2BookReader.h"
+#include "../../library/Book.h"
+#include "../../bookmodel/BookModel.h"
+
+FB2BookReader::FB2BookReader(BookModel &model) : myModelReader(model) {
+ myInsideCoverpage = false;
+ myParagraphsBeforeBodyNumber = (std::size_t)-1;
+ myInsidePoem = false;
+ mySectionDepth = 0;
+ myBodyCounter = 0;
+ myReadMainText = false;
+ myCurrentImageStart = -1;
+ mySectionStarted = false;
+ myInsideTitle = false;
+ myCurrentContentType = ZLMimeType::EMPTY;
+}
+
+void FB2BookReader::characterDataHandler(const char *text, std::size_t len) {
+ if ((len > 0) && (!myCurrentImageId.empty() || myModelReader.paragraphIsOpen())) {
+ std::string str(text, len);
+ if (!myCurrentImageId.empty()) {
+ if (myCurrentImageStart == -1) {
+ myCurrentImageStart = getCurrentPosition();
+ }
+ } else {
+ myModelReader.addData(str);
+ if (myInsideTitle) {
+ myModelReader.addContentsData(str);
+ }
+ }
+ }
+}
+
+bool FB2BookReader::processNamespaces() const {
+ return true;
+}
+
+void FB2BookReader::startElementHandler(int tag, const char **xmlattributes) {
+ const char *id = attributeValue(xmlattributes, "id");
+ if (id != 0 && tag != _BINARY) {
+ if (!myReadMainText) {
+ myModelReader.setFootnoteTextModel(id);
+ }
+ myModelReader.addHyperlinkLabel(id);
+ }
+ switch (tag) {
+ case _P:
+ if (mySectionStarted) {
+ mySectionStarted = false;
+ } else if (myInsideTitle) {
+ static const std::string SPACE = " ";
+ myModelReader.addContentsData(SPACE);
+ }
+ myModelReader.beginParagraph();
+ break;
+ case _V:
+ myModelReader.pushKind(VERSE);
+ myModelReader.beginParagraph();
+ break;
+ case _SUBTITLE:
+ myModelReader.pushKind(SUBTITLE);
+ myModelReader.beginParagraph();
+ break;
+ case _TEXT_AUTHOR:
+ myModelReader.pushKind(AUTHOR);
+ myModelReader.beginParagraph();
+ break;
+ case _DATE:
+ myModelReader.pushKind(DATEKIND);
+ myModelReader.beginParagraph();
+ break;
+ case _CITE:
+ myModelReader.pushKind(CITE);
+ break;
+ case _SECTION:
+ if (myReadMainText) {
+ myModelReader.insertEndOfSectionParagraph();
+ ++mySectionDepth;
+ myModelReader.beginContentsParagraph();
+ mySectionStarted = true;
+ }
+ break;
+ case _TITLE:
+ if (myInsidePoem) {
+ myModelReader.pushKind(POEM_TITLE);
+ } else if (mySectionDepth == 0) {
+ myModelReader.insertEndOfSectionParagraph();
+ myModelReader.pushKind(TITLE);
+ } else {
+ myModelReader.pushKind(SECTION_TITLE);
+ myModelReader.enterTitle();
+ myInsideTitle = true;
+ }
+ break;
+ case _POEM:
+ myInsidePoem = true;
+ break;
+ case _STANZA:
+ myModelReader.pushKind(STANZA);
+ myModelReader.beginParagraph(ZLTextParagraph::BEFORE_SKIP_PARAGRAPH);
+ myModelReader.endParagraph();
+ break;
+ case _EPIGRAPH:
+ myModelReader.pushKind(EPIGRAPH);
+ break;
+ case _ANNOTATION:
+ if (myBodyCounter == 0) {
+ myModelReader.setMainTextModel();
+ }
+ myModelReader.pushKind(ANNOTATION);
+ break;
+ case _COVERPAGE:
+ if (myBodyCounter == 0) {
+ myInsideCoverpage = true;
+ myModelReader.setMainTextModel();
+ }
+ break;
+ case _SUB:
+ myModelReader.addControl(SUB, true);
+ break;
+ case _SUP:
+ myModelReader.addControl(SUP, true);
+ break;
+ case _CODE:
+ myModelReader.addControl(CODE, true);
+ break;
+ case _STRIKETHROUGH:
+ myModelReader.addControl(STRIKETHROUGH, true);
+ break;
+ case _STRONG:
+ myModelReader.addControl(STRONG, true);
+ break;
+ case _EMPHASIS:
+ myModelReader.addControl(EMPHASIS, true);
+ break;
+ case _A:
+ {
+ const char *ref = attributeValue(xmlattributes, myHrefPredicate);
+ if (ref != 0) {
+ if (ref[0] == '#') {
+ const char *type = attributeValue(xmlattributes, "type");
+ static const std::string NOTE = "note";
+ if ((type != 0) && (NOTE == type)) {
+ myHyperlinkType = FOOTNOTE;
+ } else {
+ myHyperlinkType = INTERNAL_HYPERLINK;
+ }
+ ++ref;
+ } else {
+ myHyperlinkType = EXTERNAL_HYPERLINK;
+ }
+ myModelReader.addHyperlinkControl(myHyperlinkType, ref);
+ } else {
+ myHyperlinkType = FOOTNOTE;
+ myModelReader.addControl(myHyperlinkType, true);
+ }
+ break;
+ }
+ case _IMAGE:
+ {
+ const char *ref = attributeValue(xmlattributes, myHrefPredicate);
+ const char *vOffset = attributeValue(xmlattributes, "voffset");
+ char offset = vOffset != 0 ? std::atoi(vOffset) : 0;
+ if (ref != 0 && *ref == '#') {
+ ++ref;
+ const bool isCoverImage =
+ myParagraphsBeforeBodyNumber ==
+ myModelReader.model().bookTextModel()->paragraphsNumber();
+ if (myCoverImageReference != ref || !isCoverImage) {
+ myModelReader.addImageReference(ref, offset);
+ }
+ if (myInsideCoverpage) {
+ myCoverImageReference = ref;
+ }
+ }
+ break;
+ }
+ case _BINARY:
+ {
+ const char *contentType = attributeValue(xmlattributes, "content-type");
+ if (contentType != 0) {
+ shared_ptr<ZLMimeType> contentMimeType = ZLMimeType::get(contentType);
+ if ((!contentMimeType.isNull()) && (id != 0) && (ZLMimeType::TEXT_XML != contentMimeType)) {
+ myCurrentContentType = contentMimeType;
+ myCurrentImageId.assign(id);
+ }
+ }
+ break;
+ }
+ case _EMPTY_LINE:
+ myModelReader.beginParagraph(ZLTextParagraph::EMPTY_LINE_PARAGRAPH);
+ myModelReader.endParagraph();
+ break;
+ case _BODY:
+ ++myBodyCounter;
+ myParagraphsBeforeBodyNumber = myModelReader.model().bookTextModel()->paragraphsNumber();
+ if ((myBodyCounter == 1) || (attributeValue(xmlattributes, "name") == 0)) {
+ myModelReader.setMainTextModel();
+ myReadMainText = true;
+ }
+ myModelReader.pushKind(REGULAR);
+ break;
+ default:
+ break;
+ }
+}
+
+void FB2BookReader::endElementHandler(int tag) {
+ switch (tag) {
+ case _P:
+ myModelReader.endParagraph();
+ break;
+ case _V:
+ case _SUBTITLE:
+ case _TEXT_AUTHOR:
+ case _DATE:
+ myModelReader.popKind();
+ myModelReader.endParagraph();
+ break;
+ case _CITE:
+ myModelReader.popKind();
+ break;
+ case _SECTION:
+ if (myReadMainText) {
+ myModelReader.endContentsParagraph();
+ --mySectionDepth;
+ mySectionStarted = false;
+ } else {
+ myModelReader.unsetTextModel();
+ }
+ break;
+ case _TITLE:
+ myModelReader.exitTitle();
+ myModelReader.popKind();
+ myInsideTitle = false;
+ break;
+ case _POEM:
+ myInsidePoem = false;
+ break;
+ case _STANZA:
+ myModelReader.beginParagraph(ZLTextParagraph::AFTER_SKIP_PARAGRAPH);
+ myModelReader.endParagraph();
+ myModelReader.popKind();
+ break;
+ case _EPIGRAPH:
+ myModelReader.popKind();
+ break;
+ case _ANNOTATION:
+ myModelReader.popKind();
+ if (myBodyCounter == 0) {
+ myModelReader.insertEndOfSectionParagraph();
+ myModelReader.unsetTextModel();
+ }
+ break;
+ case _COVERPAGE:
+ if (myBodyCounter == 0) {
+ myInsideCoverpage = false;
+ myModelReader.insertEndOfSectionParagraph();
+ myModelReader.unsetTextModel();
+ }
+ break;
+ case _SUB:
+ myModelReader.addControl(SUB, false);
+ break;
+ case _SUP:
+ myModelReader.addControl(SUP, false);
+ break;
+ case _CODE:
+ myModelReader.addControl(CODE, false);
+ break;
+ case _STRIKETHROUGH:
+ myModelReader.addControl(STRIKETHROUGH, false);
+ break;
+ case _STRONG:
+ myModelReader.addControl(STRONG, false);
+ break;
+ case _EMPHASIS:
+ myModelReader.addControl(EMPHASIS, false);
+ break;
+ case _A:
+ myModelReader.addControl(myHyperlinkType, false);
+ break;
+ case _BINARY:
+ if (!myCurrentImageId.empty() && myCurrentImageStart != -1) {
+ myModelReader.addImage(myCurrentImageId, new ZLFileImage(
+ ZLFile(myModelReader.model().book()->file().path(), myCurrentContentType),
+ myCurrentImageStart,
+ getCurrentPosition() - myCurrentImageStart,
+ ZLFileImage::ENCODING_BASE64
+ ));
+ }
+ myCurrentImageId.clear();
+ myCurrentContentType = ZLMimeType::EMPTY;
+ myCurrentImageStart = -1;
+ break;
+ case _BODY:
+ myModelReader.popKind();
+ myModelReader.unsetTextModel();
+ myReadMainText = false;
+ break;
+ default:
+ break;
+ }
+}
+
+bool FB2BookReader::readBook() {
+ return readDocument(myModelReader.model().book()->file());
+}
diff --git a/fbreader/src/formats/fb2/FB2BookReader.h b/fbreader/src/formats/fb2/FB2BookReader.h
new file mode 100644
index 0000000..b9d22d1
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2BookReader.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2BOOKREADER_H__
+#define __FB2BOOKREADER_H__
+
+#include <ZLMimeType.h>
+
+#include "FB2Reader.h"
+#include "../../bookmodel/BookReader.h"
+
+class BookModel;
+
+class FB2BookReader : public FB2Reader {
+
+public:
+ FB2BookReader(BookModel &model);
+ bool readBook();
+
+ bool processNamespaces() const;
+ void startElementHandler(int tag, const char **attributes);
+ void endElementHandler(int tag);
+ void characterDataHandler(const char *text, std::size_t len);
+
+private:
+ int mySectionDepth;
+ int myBodyCounter;
+ bool myReadMainText;
+ bool myInsideCoverpage;
+ std::size_t myParagraphsBeforeBodyNumber;
+ std::string myCoverImageReference;
+ bool myInsidePoem;
+ BookReader myModelReader;
+
+ int myCurrentImageStart;
+ std::string myCurrentImageId;
+ shared_ptr<ZLMimeType> myCurrentContentType;
+
+ bool mySectionStarted;
+ bool myInsideTitle;
+
+ FBTextKind myHyperlinkType;
+};
+
+#endif /* __FB2BOOKREADER_H__ */
diff --git a/fbreader/src/formats/fb2/FB2CoverReader.cpp b/fbreader/src/formats/fb2/FB2CoverReader.cpp
new file mode 100644
index 0000000..cc84ac2
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2CoverReader.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <ZLFileImage.h>
+
+#include "FB2CoverReader.h"
+
+#include "../../library/Book.h"
+
+FB2CoverReader::FB2CoverReader(const ZLFile &file) : myFile(file) {
+}
+
+shared_ptr<const ZLImage> FB2CoverReader::readCover() {
+ myReadCoverPage = false;
+ myLookForImage = false;
+ myImageId.erase();
+ myImageStart = -1;
+
+ readDocument(myFile);
+
+ return myImage;
+}
+
+bool FB2CoverReader::processNamespaces() const {
+ return true;
+}
+
+void FB2CoverReader::startElementHandler(int tag, const char **attributes) {
+ switch (tag) {
+ case _COVERPAGE:
+ myReadCoverPage = true;
+ break;
+ case _IMAGE:
+ if (myReadCoverPage) {
+ const char *ref = attributeValue(attributes, myHrefPredicate);
+ if (ref != 0 && *ref == '#' && *(ref + 1) != '\0') {
+ myImageId = ref + 1;
+ }
+ }
+ break;
+ case _BINARY:
+ {
+ const char *id = attributeValue(attributes, "id");
+ const char *contentType = attributeValue(attributes, "content-type");
+ if (id != 0 && contentType != 0 && myImageId == id) {
+ myLookForImage = true;
+ }
+ }
+ }
+}
+
+void FB2CoverReader::endElementHandler(int tag) {
+ switch (tag) {
+ case _COVERPAGE:
+ myReadCoverPage = false;
+ break;
+ case _DESCRIPTION:
+ if (myImageId.empty()) {
+ interrupt();
+ }
+ break;
+ case _BINARY:
+ if (!myImageId.empty() && myImageStart >= 0) {
+ myImage = new ZLFileImage(myFile, myImageStart, getCurrentPosition() - myImageStart, ZLFileImage::ENCODING_BASE64);
+ interrupt();
+ }
+ break;
+ }
+}
+
+void FB2CoverReader::characterDataHandler(const char *text, std::size_t len) {
+ if (len > 0 && myLookForImage) {
+ myImageStart = getCurrentPosition();
+ myLookForImage = false;
+ }
+}
diff --git a/fbreader/src/formats/fb2/FB2CoverReader.h b/fbreader/src/formats/fb2/FB2CoverReader.h
new file mode 100644
index 0000000..6807aa9
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2CoverReader.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2COVERREADER_H__
+#define __FB2COVERREADER_H__
+
+#include <ZLFile.h>
+#include <ZLImage.h>
+
+#include "FB2Reader.h"
+
+class FB2CoverReader : public FB2Reader {
+
+public:
+ FB2CoverReader(const ZLFile &file);
+ shared_ptr<const ZLImage> readCover();
+
+private:
+ bool processNamespaces() const;
+ void startElementHandler(int tag, const char **attributes);
+ void endElementHandler(int tag);
+ void characterDataHandler(const char *text, std::size_t len);
+
+private:
+ const ZLFile myFile;
+ bool myReadCoverPage;
+ bool myLookForImage;
+ std::string myImageId;
+ int myImageStart;
+ shared_ptr<const ZLImage> myImage;
+};
+
+#endif /* __FB2COVERREADER_H__ */
diff --git a/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp b/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp
new file mode 100644
index 0000000..3d596ac
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <cstdlib>
+
+#include <ZLInputStream.h>
+#include <ZLUnicodeUtil.h>
+
+#include "FB2MetaInfoReader.h"
+#include "FB2TagManager.h"
+
+#include "../../library/Book.h"
+
+FB2MetaInfoReader::FB2MetaInfoReader(Book &book) : myBook(book) {
+ myBook.removeAllAuthors();
+ myBook.setTitle(std::string());
+ myBook.setLanguage(std::string());
+ myBook.removeAllTags();
+}
+
+void FB2MetaInfoReader::characterDataHandler(const char *text, std::size_t len) {
+ switch (myReadState) {
+ case READ_TITLE:
+ myBuffer.append(text, len);
+ break;
+ case READ_LANGUAGE:
+ myBuffer.append(text, len);
+ break;
+ case READ_AUTHOR_NAME_0:
+ myAuthorNames[0].append(text, len);
+ break;
+ case READ_AUTHOR_NAME_1:
+ myAuthorNames[1].append(text, len);
+ break;
+ case READ_AUTHOR_NAME_2:
+ myAuthorNames[2].append(text, len);
+ break;
+ case READ_GENRE:
+ myBuffer.append(text, len);
+ break;
+ default:
+ break;
+ }
+}
+
+void FB2MetaInfoReader::startElementHandler(int tag, const char **attributes) {
+ switch (tag) {
+ case _BODY:
+ myReturnCode = true;
+ interrupt();
+ break;
+ case _TITLE_INFO:
+ myReadState = READ_SOMETHING;
+ break;
+ case _BOOK_TITLE:
+ if (myReadState == READ_SOMETHING) {
+ myReadState = READ_TITLE;
+ }
+ break;
+ case _GENRE:
+ if (myReadState == READ_SOMETHING) {
+ myReadState = READ_GENRE;
+ }
+ break;
+ case _AUTHOR:
+ if (myReadState == READ_SOMETHING) {
+ myReadState = READ_AUTHOR;
+ }
+ break;
+ case _LANG:
+ if (myReadState == READ_SOMETHING) {
+ myReadState = READ_LANGUAGE;
+ }
+ break;
+ case _FIRST_NAME:
+ if (myReadState == READ_AUTHOR) {
+ myReadState = READ_AUTHOR_NAME_0;
+ }
+ break;
+ case _MIDDLE_NAME:
+ if (myReadState == READ_AUTHOR) {
+ myReadState = READ_AUTHOR_NAME_1;
+ }
+ break;
+ case _LAST_NAME:
+ if (myReadState == READ_AUTHOR) {
+ myReadState = READ_AUTHOR_NAME_2;
+ }
+ break;
+ case _SEQUENCE:
+ if (myReadState == READ_SOMETHING) {
+ const char *name = attributeValue(attributes, "name");
+ if (name != 0) {
+ std::string seriesTitle = name;
+ ZLUnicodeUtil::utf8Trim(seriesTitle);
+ const char *number = attributeValue(attributes, "number");
+ myBook.setSeries(seriesTitle, number != 0 ? std::string(number) : std::string());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void FB2MetaInfoReader::endElementHandler(int tag) {
+ switch (tag) {
+ case _TITLE_INFO:
+ myReadState = READ_NOTHING;
+ break;
+ case _BOOK_TITLE:
+ if (myReadState == READ_TITLE) {
+ myBook.setTitle(myBuffer);
+ myBuffer.erase();
+ myReadState = READ_SOMETHING;
+ }
+ break;
+ case _GENRE:
+ if (myReadState == READ_GENRE) {
+ ZLUnicodeUtil::utf8Trim(myBuffer);
+ if (!myBuffer.empty()) {
+ const std::vector<std::string> &tags =
+ FB2TagManager::Instance().humanReadableTags(myBuffer);
+ if (!tags.empty()) {
+ for (std::vector<std::string>::const_iterator it = tags.begin(); it != tags.end(); ++it) {
+ myBook.addTag(*it);
+ }
+ } else {
+ myBook.addTag(myBuffer);
+ }
+ myBuffer.erase();
+ }
+ myReadState = READ_SOMETHING;
+ }
+ break;
+ case _AUTHOR:
+ if (myReadState == READ_AUTHOR) {
+ ZLUnicodeUtil::utf8Trim(myAuthorNames[0]);
+ ZLUnicodeUtil::utf8Trim(myAuthorNames[1]);
+ ZLUnicodeUtil::utf8Trim(myAuthorNames[2]);
+ std::string fullName = myAuthorNames[0];
+ if (!fullName.empty() && !myAuthorNames[1].empty()) {
+ fullName += ' ';
+ }
+ fullName += myAuthorNames[1];
+ if (!fullName.empty() && !myAuthorNames[2].empty()) {
+ fullName += ' ';
+ }
+ fullName += myAuthorNames[2];
+ myBook.addAuthor(fullName, myAuthorNames[2]);
+ myAuthorNames[0].erase();
+ myAuthorNames[1].erase();
+ myAuthorNames[2].erase();
+ myReadState = READ_SOMETHING;
+ }
+ break;
+ case _LANG:
+ if (myReadState == READ_LANGUAGE) {
+ myBook.setLanguage(myBuffer);
+ myBuffer.erase();
+ myReadState = READ_SOMETHING;
+ }
+ break;
+ case _FIRST_NAME:
+ if (myReadState == READ_AUTHOR_NAME_0) {
+ myReadState = READ_AUTHOR;
+ }
+ break;
+ case _MIDDLE_NAME:
+ if (myReadState == READ_AUTHOR_NAME_1) {
+ myReadState = READ_AUTHOR;
+ }
+ break;
+ case _LAST_NAME:
+ if (myReadState == READ_AUTHOR_NAME_2) {
+ myReadState = READ_AUTHOR;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool FB2MetaInfoReader::readMetaInfo() {
+ myReadState = READ_NOTHING;
+ for (int i = 0; i < 3; ++i) {
+ myAuthorNames[i].erase();
+ }
+ return readDocument(myBook.file());
+}
diff --git a/fbreader/src/formats/fb2/FB2MetaInfoReader.h b/fbreader/src/formats/fb2/FB2MetaInfoReader.h
new file mode 100644
index 0000000..cc09909
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2MetaInfoReader.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2METAINFOREADER_H__
+#define __FB2METAINFOREADER_H__
+
+#include <string>
+
+#include "FB2Reader.h"
+
+class Book;
+
+class FB2MetaInfoReader : public FB2Reader {
+
+public:
+ FB2MetaInfoReader(Book &book);
+ bool readMetaInfo();
+
+ void startElementHandler(int tag, const char **attributes);
+ void endElementHandler(int tag);
+ void characterDataHandler(const char *text, std::size_t len);
+
+private:
+ Book &myBook;
+
+ bool myReturnCode;
+
+ enum {
+ READ_NOTHING,
+ READ_SOMETHING,
+ READ_TITLE,
+ READ_AUTHOR,
+ READ_AUTHOR_NAME_0,
+ READ_AUTHOR_NAME_1,
+ READ_AUTHOR_NAME_2,
+ READ_LANGUAGE,
+ READ_GENRE
+ } myReadState;
+
+ std::string myAuthorNames[3];
+ std::string myBuffer;
+};
+
+#endif /* __FB2METAINFOREADER_H__ */
diff --git a/fbreader/src/formats/fb2/FB2Plugin.cpp b/fbreader/src/formats/fb2/FB2Plugin.cpp
new file mode 100644
index 0000000..f65ddcb
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2Plugin.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <ZLFile.h>
+#include <ZLImage.h>
+
+#include "FB2Plugin.h"
+#include "FB2MetaInfoReader.h"
+#include "FB2BookReader.h"
+#include "FB2CoverReader.h"
+
+#include "../../database/booksdb/BooksDBUtil.h"
+
+bool FB2Plugin::acceptsFile(const ZLFile &file) const {
+ return file.extension() == "fb2";
+}
+
+bool FB2Plugin::readMetaInfo(Book &book) const {
+ return FB2MetaInfoReader(book).readMetaInfo();
+}
+
+bool FB2Plugin::readModel(BookModel &model) const {
+ return FB2BookReader(model).readBook();
+}
+
+shared_ptr<const ZLImage> FB2Plugin::coverImage(const ZLFile &file) const {
+ return FB2CoverReader(file).readCover();
+}
+bool FB2Plugin::readLanguageAndEncoding(Book &book) const {
+ (void)book;
+ return true;
+}
diff --git a/fbreader/src/formats/fb2/FB2Plugin.h b/fbreader/src/formats/fb2/FB2Plugin.h
new file mode 100644
index 0000000..d96558d
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2Plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2PLUGIN_H__
+#define __FB2PLUGIN_H__
+
+#include "../FormatPlugin.h"
+
+class FB2Plugin : public FormatPlugin {
+
+public:
+ FB2Plugin();
+ ~FB2Plugin();
+ bool providesMetaInfo() const;
+ bool acceptsFile(const ZLFile &file) const;
+ bool readMetaInfo(Book &book) const;
+ bool readLanguageAndEncoding(Book &book) const;
+ bool readModel(BookModel &model) const;
+ shared_ptr<const ZLImage> coverImage(const ZLFile &file) const;
+};
+
+inline FB2Plugin::FB2Plugin() {}
+inline FB2Plugin::~FB2Plugin() {}
+inline bool FB2Plugin::providesMetaInfo() const { return true; }
+
+#endif /* __FB2PLUGIN_H__ */
diff --git a/fbreader/src/formats/fb2/FB2Reader.cpp b/fbreader/src/formats/fb2/FB2Reader.cpp
new file mode 100644
index 0000000..c8e279c
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2Reader.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <cstring>
+
+#include <ZLibrary.h>
+#include <ZLStringUtil.h>
+#include <ZLXMLNamespace.h>
+
+#include "FB2Reader.h"
+
+#include "../util/EntityFilesCollector.h"
+
+FB2Reader::FB2Reader() : myHrefPredicate(ZLXMLNamespace::XLink, "href") {
+}
+
+void FB2Reader::startElementHandler(const char *t, const char **attributes) {
+ startElementHandler(tag(t), attributes);
+}
+
+void FB2Reader::endElementHandler(const char *t) {
+ endElementHandler(tag(t));
+}
+
+static const FB2Reader::Tag TAGS[] = {
+ {"p", FB2Reader::_P},
+ {"subtitle", FB2Reader::_SUBTITLE},
+ {"cite", FB2Reader::_CITE},
+ {"text-author", FB2Reader::_TEXT_AUTHOR},
+ {"date", FB2Reader::_DATE},
+ {"section", FB2Reader::_SECTION},
+ {"v", FB2Reader::_V},
+ {"title", FB2Reader::_TITLE},
+ {"poem", FB2Reader::_POEM},
+ {"stanza", FB2Reader::_STANZA},
+ {"epigraph", FB2Reader::_EPIGRAPH},
+ {"annotation", FB2Reader::_ANNOTATION},
+ {"sub", FB2Reader::_SUB},
+ {"sup", FB2Reader::_SUP},
+ {"code", FB2Reader::_CODE},
+ {"strikethrough", FB2Reader::_STRIKETHROUGH},
+ {"strong", FB2Reader::_STRONG},
+ {"emphasis", FB2Reader::_EMPHASIS},
+ {"a", FB2Reader::_A},
+ {"image", FB2Reader::_IMAGE},
+ {"binary", FB2Reader::_BINARY},
+ {"description", FB2Reader::_DESCRIPTION},
+ {"body", FB2Reader::_BODY},
+ {"empty-line", FB2Reader::_EMPTY_LINE},
+ {"title-info", FB2Reader::_TITLE_INFO},
+ {"book-title", FB2Reader::_BOOK_TITLE},
+ {"author", FB2Reader::_AUTHOR},
+ {"lang", FB2Reader::_LANG},
+ {"first-name", FB2Reader::_FIRST_NAME},
+ {"middle-name", FB2Reader::_MIDDLE_NAME},
+ {"last-name", FB2Reader::_LAST_NAME},
+ {"coverpage", FB2Reader::_COVERPAGE},
+ {"sequence", FB2Reader::_SEQUENCE},
+ {"genre", FB2Reader::_GENRE},
+ {0, FB2Reader::_UNKNOWN}
+};
+
+int FB2Reader::tag(const char *name) {
+ for (int i = 0; ; ++i) {
+ if (TAGS[i].tagName == 0 || std::strcmp(name, TAGS[i].tagName) == 0) {
+ return TAGS[i].tagCode;
+ }
+ }
+}
+
+const std::vector<std::string> &FB2Reader::externalDTDs() const {
+ return EntityFilesCollector::Instance().externalDTDs("fb2");
+}
diff --git a/fbreader/src/formats/fb2/FB2Reader.h b/fbreader/src/formats/fb2/FB2Reader.h
new file mode 100644
index 0000000..8fa8654
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2Reader.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2READER_H__
+#define __FB2READER_H__
+
+#include <ZLXMLReader.h>
+
+class FB2Reader : public ZLXMLReader {
+
+public:
+ struct Tag {
+ const char *tagName;
+ int tagCode;
+ };
+
+protected:
+ virtual int tag(const char *name);
+
+ virtual void startElementHandler(int tag, const char **attributes) = 0;
+ virtual void endElementHandler(int tag) = 0;
+
+private:
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+
+ const std::vector<std::string> &externalDTDs() const;
+
+public:
+ enum TagCode {
+ _P,
+ _SUBTITLE,
+ _CITE,
+ _TEXT_AUTHOR,
+ _DATE,
+ _SECTION,
+ _V,
+ _TITLE,
+ _POEM,
+ _STANZA,
+ _EPIGRAPH,
+ _ANNOTATION,
+ _SUB,
+ _SUP,
+ _CODE,
+ _STRIKETHROUGH,
+ _STRONG,
+ _EMPHASIS,
+ _A,
+ _IMAGE,
+ _BINARY,
+ _DESCRIPTION,
+ _BODY,
+ _EMPTY_LINE,
+ _TITLE_INFO,
+ _BOOK_TITLE,
+ _AUTHOR,
+ _LANG,
+ _FIRST_NAME,
+ _MIDDLE_NAME,
+ _LAST_NAME,
+ _COVERPAGE,
+ _SEQUENCE,
+ _GENRE,
+ _UNKNOWN
+ };
+
+protected:
+ FB2Reader();
+ ~FB2Reader();
+
+protected:
+ const NamespaceAttributeNamePredicate myHrefPredicate;
+};
+
+inline FB2Reader::~FB2Reader() {}
+
+#endif /* __FB2READER_H__ */
diff --git a/fbreader/src/formats/fb2/FB2TagManager.cpp b/fbreader/src/formats/fb2/FB2TagManager.cpp
new file mode 100644
index 0000000..f698ace
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2TagManager.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <vector>
+
+#include <ZLFile.h>
+#include <ZLXMLReader.h>
+#include <ZLibrary.h>
+#include <ZLUnicodeUtil.h>
+
+#include "FB2TagManager.h"
+
+class FB2TagInfoReader : public ZLXMLReader {
+
+public:
+ FB2TagInfoReader(std::map<std::string,std::vector<std::string> > &tagMap);
+
+ void startElementHandler(const char *tag, const char **attributes);
+ void endElementHandler(const char *tag);
+
+private:
+ std::map<std::string,std::vector<std::string> > &myTagMap;
+
+ std::string myCategoryName;
+ std::string mySubCategoryName;
+ std::vector<std::string> myGenreIds;
+ std::string myLanguage;
+};
+
+FB2TagInfoReader::FB2TagInfoReader(std::map<std::string,std::vector<std::string> > &tagMap) : myTagMap(tagMap) {
+ myLanguage = ZLibrary::Language();
+ if (myLanguage != "ru") {
+ myLanguage = "en";
+ }
+}
+
+static const std::string CATEGORY_NAME_TAG = "root-descr";
+static const std::string SUBCATEGORY_NAME_TAG = "genre-descr";
+static const std::string GENRE_TAG = "genre";
+static const std::string SUBGENRE_TAG = "subgenre";
+static const std::string SUBGENRE_ALT_TAG = "genre-alt";
+
+void FB2TagInfoReader::startElementHandler(const char *tag, const char **attributes) {
+ if ((SUBGENRE_TAG == tag) || (SUBGENRE_ALT_TAG == tag)) {
+ const char *id = attributeValue(attributes, "value");
+ if (id != 0) {
+ myGenreIds.push_back(id);
+ }
+ } else if (CATEGORY_NAME_TAG == tag) {
+ const char *lang = attributeValue(attributes, "lang");
+ if ((lang != 0) && (myLanguage == lang)) {
+ const char *name = attributeValue(attributes, "genre-title");
+ if (name != 0) {
+ myCategoryName = name;
+ ZLUnicodeUtil::utf8Trim(myCategoryName);
+ }
+ }
+ } else if (SUBCATEGORY_NAME_TAG == tag) {
+ const char *lang = attributeValue(attributes, "lang");
+ if ((lang != 0) && (myLanguage == lang)) {
+ const char *name = attributeValue(attributes, "title");
+ if (name != 0) {
+ mySubCategoryName = name;
+ ZLUnicodeUtil::utf8Trim(mySubCategoryName);
+ }
+ }
+ }
+}
+
+void FB2TagInfoReader::endElementHandler(const char *tag) {
+ if (GENRE_TAG == tag) {
+ myCategoryName.erase();
+ mySubCategoryName.erase();
+ myGenreIds.clear();
+ } else if (SUBGENRE_TAG == tag) {
+ if (!myCategoryName.empty() && !mySubCategoryName.empty()) {
+ const std::string fullTagName = myCategoryName + '/' + mySubCategoryName;
+ for (std::vector<std::string>::const_iterator it = myGenreIds.begin(); it != myGenreIds.end(); ++it) {
+ myTagMap[*it].push_back(fullTagName);
+ }
+ }
+ mySubCategoryName.erase();
+ myGenreIds.clear();
+ }
+}
+
+FB2TagManager *FB2TagManager::ourInstance = 0;
+
+const FB2TagManager &FB2TagManager::Instance() {
+ if (ourInstance == 0) {
+ ourInstance = new FB2TagManager();
+ }
+ return *ourInstance;
+}
+
+FB2TagManager::FB2TagManager() {
+ FB2TagInfoReader(myTagMap).readDocument(ZLFile(
+ ZLibrary::ApplicationDirectory() + ZLibrary::FileNameDelimiter +
+ "formats" + ZLibrary::FileNameDelimiter + "fb2" +
+ ZLibrary::FileNameDelimiter + "fb2genres.xml"
+ ));
+}
+
+const std::vector<std::string> &FB2TagManager::humanReadableTags(const std::string &id) const {
+ static const std::vector<std::string> EMPTY;
+ std::map<std::string,std::vector<std::string> >::const_iterator it = myTagMap.find(id);
+ return (it != myTagMap.end()) ? it->second : EMPTY;
+}
diff --git a/fbreader/src/formats/fb2/FB2TagManager.h b/fbreader/src/formats/fb2/FB2TagManager.h
new file mode 100644
index 0000000..cfbf076
--- /dev/null
+++ b/fbreader/src/formats/fb2/FB2TagManager.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008-2012 Geometer Plus <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __FB2TAGMANAGER_H__
+#define __FB2TAGMANAGER_H__
+
+#include <string>
+#include <map>
+#include <vector>
+
+class FB2TagManager {
+
+private:
+ static FB2TagManager *ourInstance;
+
+public:
+ static const FB2TagManager &Instance();
+
+private:
+ FB2TagManager();
+
+public:
+ const std::vector<std::string> &humanReadableTags(const std::string &id) const;
+
+private:
+ std::map<std::string,std::vector<std::string> > myTagMap;
+};
+
+#endif /* __FB2TAGMANAGER_H__ */