diff options
Diffstat (limited to 'fbreader/src/formats/fb2')
-rw-r--r-- | fbreader/src/formats/fb2/FB2BookReader.cpp | 336 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2BookReader.h | 61 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2CoverReader.cpp | 92 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2CoverReader.h | 49 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2MetaInfoReader.cpp | 206 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2MetaInfoReader.h | 60 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2Plugin.cpp | 48 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2Plugin.h | 42 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2Reader.cpp | 89 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2Reader.h | 94 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2TagManager.cpp | 124 | ||||
-rw-r--r-- | fbreader/src/formats/fb2/FB2TagManager.h | 45 |
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__ */ |