Logo Search packages:      
Sourcecode: fbreader version File versions

FB2BookReader.cpp

/*
 * Copyright (C) 2004-2009 Geometer Plus <contact@geometerplus.com>
 *
 * 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 <stdlib.h>
#include <string.h>

#include <ZLInputStream.h>
#include <ZLStringUtil.h>

#include <ZLTextParagraph.h>

#include "FB2BookReader.h"
#include "Base64EncodedImage.h"
#include "../../bookmodel/BookModel.h"
#include "../../constants/XMLNamespace.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 char *ref = attributeValue(xmlattributes, myHrefAttributeName.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 char *ref = attributeValue(xmlattributes, myHrefAttributeName.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:
            {
                  const char *contentType = attributeValue(xmlattributes, "content-type");
                  if ((contentType != 0) && (id != 0)) {
                        myCurrentImage = new Base64EncodedImage(contentType);
                        myModelReader.addImage(id, myCurrentImage);
                        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() && (myCurrentImage != 0)) {
                        myCurrentImage->addData(myImageBuffer);
                        myImageBuffer.clear();
                        myCurrentImage = 0;
                  }
                  myProcessingImage = false;
                  break;
            case _BODY:
                  myModelReader.popKind();
                  myModelReader.unsetTextModel();
                  myReadMainText = false;
                  break;
            default:
                  break;
      }
}

bool FB2BookReader::processNamespaces() const {
      return true;
}

void FB2BookReader::namespaceListChangedHandler() {
      const std::map<std::string,std::string> namespaceMap = namespaces();
      for (std::map<std::string,std::string>::const_iterator it = namespaceMap.begin(); it != namespaceMap.end(); ++it) {
            if (ZLStringUtil::stringStartsWith(it->second, XMLNamespace::XLink)) {
                  myHrefAttributeName = it->first + ":href";
                  return;
            }
      }
      myHrefAttributeName = "";
}

bool FB2BookReader::readBook(const std::string &fileName) {
      myHrefAttributeName = "";
      return readDocument(fileName);
}

Generated by  Doxygen 1.6.0   Back to index