From ae40ca59a63e3f4eaadc8b3b1d035dee45394102 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Fri, 23 Mar 2012 23:35:09 +0000 Subject: [PATCH] fb2 plugin code is included into master branch --- .../src/formats/fb2/FB2BookReader.cpp | 326 ++++++++++++++++++ .../fbreader/src/formats/fb2/FB2BookReader.h | 60 ++++ .../src/formats/fb2/FB2CoverReader.cpp | 90 +++++ .../fbreader/src/formats/fb2/FB2CoverReader.h | 48 +++ .../src/formats/fb2/FB2MetaInfoReader.cpp | 206 +++++++++++ .../src/formats/fb2/FB2MetaInfoReader.h | 60 ++++ .../fbreader/src/formats/fb2/FB2Plugin.cpp | 46 +++ .../fbreader/src/formats/fb2/FB2Plugin.h | 42 +++ .../fbreader/src/formats/fb2/FB2Reader.cpp | 101 ++++++ .../fbreader/src/formats/fb2/FB2Reader.h | 100 ++++++ .../src/formats/fb2/FB2TagManager.cpp | 124 +++++++ .../fbreader/src/formats/fb2/FB2TagManager.h | 45 +++ 12 files changed, 1248 insertions(+) create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.h create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.h create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.h create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.h create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.h create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.cpp create mode 100644 jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.h diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.cpp new file mode 100644 index 000000000..cc76994cb --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 +#include + +#include +#include +#include + +#include + +#include "FB2BookReader.h" +#include "../../library/Book.h" +#include "../../bookmodel/BookModel.h" + +FB2BookReader::FB2BookReader(BookModel &model) : myModelReader(model) { + myInsideCoverpage = false; + myParagraphsBeforeBodyNumber = (size_t)-1; + myInsidePoem = false; + mySectionDepth = 0; + myBodyCounter = 0; + myReadMainText = false; + myCurrentImage = 0; + myProcessingImage = false; + mySectionStarted = false; + myInsideTitle = false; +} + +void FB2BookReader::characterDataHandler(const char *text, size_t len) { + if ((len > 0) && (myProcessingImage || myModelReader.paragraphIsOpen())) { + std::string str(text, len); + if (myProcessingImage) { + myImageBuffer.push_back(str); + } else { + myModelReader.addData(str); + if (myInsideTitle) { + myModelReader.addContentsData(str); + } + } + } +} + +void FB2BookReader::startElementHandler(int tag, const char **xmlattributes) { + const char *id = attributeValue(xmlattributes, "id"); + if (id != 0) { + 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 std::string hrefName = xlinkNamespace() + ":href"; + const char *ref = attributeValue(xmlattributes, hrefName.c_str()); + 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 std::string hrefName = xlinkNamespace() + ":href"; + const char *ref = attributeValue(xmlattributes, hrefName.c_str()); + //const char *vOffset = attributeValue(xmlattributes, "voffset"); + //char offset = (vOffset != 0) ? atoi(vOffset) : 0; + if ((ref != 0) && (*ref == '#')) { + ++ref; + if ((myCoverImageReference != ref) || + (myParagraphsBeforeBodyNumber != myModelReader.model().bookTextModel()->paragraphsNumber())) { + myModelReader.addImageReference(ref); + } + if (myInsideCoverpage) { + myCoverImageReference = ref; + } + } + break; + } + case _BINARY: + { + static const std::string STRANGE_MIME_TYPE = "text/xml"; + const char *contentType = attributeValue(xmlattributes, "content-type"); + if ((contentType != 0) && (id != 0) && (STRANGE_MIME_TYPE != contentType)) { + myCurrentImage = new ZLBase64EncodedImage(contentType); + myCurrentImageId.assign(id); + myProcessingImage = true; + } + 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 (!myImageBuffer.empty() && !myCurrentImageId.empty() && myCurrentImage != 0) { + myCurrentImage->addData(myImageBuffer); + myModelReader.addImage(myCurrentImageId, myCurrentImage); + myImageBuffer.clear(); + myCurrentImageId.clear(); + myCurrentImage = 0; + } + myProcessingImage = false; + break; + case _BODY: + myModelReader.popKind(); + myModelReader.unsetTextModel(); + myReadMainText = false; + break; + default: + break; + } +} + +bool FB2BookReader::readBook() { + return readDocument(myModelReader.model().book()->file()); +} diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.h new file mode 100644 index 000000000..5f5deac4c --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2BookReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 "FB2Reader.h" +#include "../../bookmodel/BookReader.h" + +class BookModel; +class ZLBase64EncodedImage; + +class FB2BookReader : public FB2Reader { + +public: + FB2BookReader(BookModel &model); + bool readBook(); + + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, size_t len); + +private: + int mySectionDepth; + int myBodyCounter; + bool myReadMainText; + bool myInsideCoverpage; + size_t myParagraphsBeforeBodyNumber; + std::string myCoverImageReference; + bool myInsidePoem; + BookReader myModelReader; + + ZLBase64EncodedImage *myCurrentImage; + std::string myCurrentImageId; + bool myProcessingImage; + std::vector myImageBuffer; + + bool mySectionStarted; + bool myInsideTitle; + + FBTextKind myHyperlinkType; +}; + +#endif /* __FB2BOOKREADER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.cpp new file mode 100644 index 000000000..472a1aefe --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 +#include + +#include "FB2CoverReader.h" + +#include "../../library/Book.h" + +FB2CoverReader::FB2CoverReader(const ZLFile &file) : myFile(file) { +} + +shared_ptr FB2CoverReader::readCover() { + myReadCoverPage = false; + myImageReference.erase(); + readDocument(myFile); + return myImage; +} + +void FB2CoverReader::startElementHandler(int tag, const char **attributes) { + switch (tag) { + case _COVERPAGE: + myReadCoverPage = true; + break; + case _IMAGE: + if (myReadCoverPage) { + const std::string hrefName = xlinkNamespace() + ":href"; + const char *ref = attributeValue(attributes, hrefName.c_str()); + if (ref != 0 && *ref == '#' && *(ref + 1) != '\0') { + myImageReference = ref + 1; + } + } + break; + case _BINARY: + { + const char *id = attributeValue(attributes, "id"); + const char *contentType = attributeValue(attributes, "content-type"); + if (id != 0 && contentType != 0 && myImageReference == id) { + myImage = new ZLBase64EncodedImage(contentType); + } + } + } +} + +void FB2CoverReader::endElementHandler(int tag) { + switch (tag) { + case _COVERPAGE: + myReadCoverPage = false; + break; + case _DESCRIPTION: + if (myImageReference.empty()) { + interrupt(); + } + break; + case _BINARY: + if (!myImage.isNull()) { + if (!myImageBuffer.empty()) { + ((ZLBase64EncodedImage&)*myImage).addData(myImageBuffer); + myImageBuffer.clear(); + } else { + myImage = 0; + } + interrupt(); + } + break; + } +} + +void FB2CoverReader::characterDataHandler(const char *text, size_t len) { + if (len > 0 && !myImage.isNull()) { + myImageBuffer.push_back(std::string(text, len)); + } +} diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.h new file mode 100644 index 000000000..0be0eb222 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2CoverReader.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 "FB2Reader.h" + +class Book; +class ZLfile; +class ZLImage; + +class FB2CoverReader : public FB2Reader { + +public: + FB2CoverReader(const ZLFile &file); + shared_ptr readCover(); + +private: + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, size_t len); + +private: + const ZLFile myFile; + bool myReadCoverPage; + std::string myImageReference; + shared_ptr myImage; + std::vector myImageBuffer; +}; + +#endif /* __FB2COVERREADER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp new file mode 100644 index 000000000..b9eba3bd1 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 + +#include +#include + +#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, 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; + ZLStringUtil::stripWhiteSpaces(seriesTitle); + const char *number = attributeValue(attributes, "number"); + myBook.setSeries(seriesTitle, number != 0 ? atoi(number) : 0); + } + } + 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) { + ZLStringUtil::stripWhiteSpaces(myBuffer); + if (!myBuffer.empty()) { + const std::vector &tags = + FB2TagManager::Instance().humanReadableTags(myBuffer); + if (!tags.empty()) { + for (std::vector::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) { + ZLStringUtil::stripWhiteSpaces(myAuthorNames[0]); + ZLStringUtil::stripWhiteSpaces(myAuthorNames[1]); + ZLStringUtil::stripWhiteSpaces(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/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.h new file mode 100644 index 000000000..9c4237d7d --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2MetaInfoReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 + +#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, 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/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.cpp new file mode 100644 index 000000000..4214bcf51 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 +#include + +#include "FB2Plugin.h" +#include "FB2MetaInfoReader.h" +#include "FB2BookReader.h" +#include "FB2CoverReader.h" + +const std::string FB2Plugin::supportedFileType() const { + return "fb2"; +} + +bool FB2Plugin::readMetaInfo(Book &book) const { + return FB2MetaInfoReader(book).readMetaInfo(); +} + +bool FB2Plugin::readModel(BookModel &model) const { + return FB2BookReader(model).readBook(); +} + +shared_ptr FB2Plugin::coverImage(const ZLFile &file) const { + return FB2CoverReader(file).readCover(); +} + +bool FB2Plugin::readLanguageAndEncoding(Book &book) const { + return true; +} diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.h new file mode 100644 index 000000000..b7188e32f --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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; + const std::string supportedFileType() const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + shared_ptr coverImage(const ZLFile &file) const; +}; + +inline FB2Plugin::FB2Plugin() {} +inline FB2Plugin::~FB2Plugin() {} +inline bool FB2Plugin::providesMetaInfo() const { return true; } + +#endif /* __FB2PLUGIN_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.cpp new file mode 100644 index 000000000..385d9186e --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 + +#include + +#include +#include + +#include "FB2Reader.h" +#include "../util/EntityFilesCollector.h" + +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) || (strcmp(name, TAGS[i].tagName) == 0)) { + return TAGS[i].tagCode; + } + } +} + +bool FB2Reader::processNamespaces() const { + return true; +} + +void FB2Reader::namespaceListChangedHandler() { + const std::map namespaceMap = namespaces(); + for (std::map::const_iterator it = namespaceMap.begin(); it != namespaceMap.end(); ++it) { + if (ZLStringUtil::stringStartsWith(it->second, ZLXMLNamespace::XLink)) { + myXLinkNamespace = it->first; + return; + } + } + myXLinkNamespace.erase(); +} + +void FB2Reader::collectExternalEntities(std::map &entityMap) { + entityMap["FBReaderVersion"] = ZLibrary::Version(); +} diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.h new file mode 100644 index 000000000..29c1b31c9 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2Reader.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * 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 + +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; + + const std::string &xlinkNamespace() const; + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + bool processNamespaces() const; + void namespaceListChangedHandler(); + + void collectExternalEntities(std::map &entityMap); + +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(); + +private: + std::string myXLinkNamespace; +}; + +inline FB2Reader::FB2Reader() {} +inline FB2Reader::~FB2Reader() {} +inline const std::string &FB2Reader::xlinkNamespace() const { return myXLinkNamespace; } + +#endif /* __FB2READER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.cpp b/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.cpp new file mode 100644 index 000000000..615820613 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus + * + * 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 + +#include +#include +#include +#include + +#include "FB2TagManager.h" + +class FB2TagInfoReader : public ZLXMLReader { + +public: + FB2TagInfoReader(std::map > &tagMap); + + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + +private: + std::map > &myTagMap; + + std::string myCategoryName; + std::string mySubCategoryName; + std::vector myGenreIds; + std::string myLanguage; +}; + +FB2TagInfoReader::FB2TagInfoReader(std::map > &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; + ZLStringUtil::stripWhiteSpaces(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; + ZLStringUtil::stripWhiteSpaces(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::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 &FB2TagManager::humanReadableTags(const std::string &id) const { + static const std::vector EMPTY; + std::map >::const_iterator it = myTagMap.find(id); + return (it != myTagMap.end()) ? it->second : EMPTY; +} diff --git a/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.h b/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.h new file mode 100644 index 000000000..cfbf0765b --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/fb2/FB2TagManager.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus + * + * 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 +#include +#include + +class FB2TagManager { + +private: + static FB2TagManager *ourInstance; + +public: + static const FB2TagManager &Instance(); + +private: + FB2TagManager(); + +public: + const std::vector &humanReadableTags(const std::string &id) const; + +private: + std::map > myTagMap; +}; + +#endif /* __FB2TAGMANAGER_H__ */