gui
[lbook_fbreader.git] / fbreader / src / formats / fb2 / FB2BookReader.cpp
blobd95736b67d526eae42c96e9f81810cedca2464cb
1 /*
2 * Copyright (C) 2004-2008 Geometer Plus <contact@geometerplus.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
20 #include <stdlib.h>
21 #include <string.h>
23 #include <ZLInputStream.h>
24 #include <ZLStringUtil.h>
26 #include <ZLTextParagraph.h>
28 #include "FB2BookReader.h"
29 #include "Base64EncodedImage.h"
30 #include "../../bookmodel/BookModel.h"
32 FB2BookReader::FB2BookReader(BookModel &model) : myModelReader(model) {
33 myInsideCoverpage = false;
34 myParagraphsBeforeBodyNumber = (size_t)-1;
35 myInsidePoem = false;
36 mySectionDepth = 0;
37 myBodyCounter = 0;
38 myReadMainText = false;
39 myCurrentImage = 0;
40 myProcessingImage = false;
41 mySectionStarted = false;
42 myInsideTitle = false;
45 void FB2BookReader::characterDataHandler(const char *text, int len) {
46 if ((len > 0) && (myProcessingImage || myModelReader.paragraphIsOpen())) {
47 std::string str(text, len);
48 if (myProcessingImage) {
49 myImageBuffer.push_back(str);
50 } else {
51 myModelReader.addData(str);
52 if (myInsideTitle) {
53 myModelReader.addContentsData(str);
59 void FB2BookReader::startElementHandler(int tag, const char **xmlattributes) {
60 const char *id = attributeValue(xmlattributes, "id");
61 if (id != 0) {
62 if (!myReadMainText) {
63 myModelReader.setFootnoteTextModel(id);
65 myModelReader.addHyperlinkLabel(id);
67 switch (tag) {
68 case _P:
69 if (mySectionStarted) {
70 mySectionStarted = false;
71 } else if (myInsideTitle) {
72 static const std::string SPACE = " ";
73 myModelReader.addContentsData(SPACE);
75 myModelReader.beginParagraph();
76 break;
77 case _V:
78 myModelReader.pushKind(VERSE);
79 myModelReader.beginParagraph();
80 break;
81 case _SUBTITLE:
82 myModelReader.pushKind(SUBTITLE);
83 myModelReader.beginParagraph();
84 break;
85 case _TEXT_AUTHOR:
86 myModelReader.pushKind(AUTHOR);
87 myModelReader.beginParagraph();
88 break;
89 case _DATE:
90 myModelReader.pushKind(DATE);
91 myModelReader.beginParagraph();
92 break;
93 case _CITE:
94 myModelReader.pushKind(CITE);
95 break;
96 case _SECTION:
97 if (myReadMainText) {
98 myModelReader.insertEndOfSectionParagraph();
99 ++mySectionDepth;
100 myModelReader.beginContentsParagraph();
101 mySectionStarted = true;
103 break;
104 case _TITLE:
105 if (myInsidePoem) {
106 myModelReader.pushKind(POEM_TITLE);
107 } else if (mySectionDepth == 0) {
108 myModelReader.insertEndOfSectionParagraph();
109 myModelReader.pushKind(TITLE);
110 } else {
111 myModelReader.pushKind(SECTION_TITLE);
112 myModelReader.enterTitle();
113 myInsideTitle = true;
115 break;
116 case _POEM:
117 myInsidePoem = true;
118 break;
119 case _STANZA:
120 myModelReader.pushKind(STANZA);
121 myModelReader.beginParagraph(ZLTextParagraph::BEFORE_SKIP_PARAGRAPH);
122 myModelReader.endParagraph();
123 break;
124 case _EPIGRAPH:
125 myModelReader.pushKind(EPIGRAPH);
126 break;
127 case _ANNOTATION:
128 if (myBodyCounter == 0) {
129 myModelReader.setMainTextModel();
131 myModelReader.pushKind(ANNOTATION);
132 break;
133 case _COVERPAGE:
134 if (myBodyCounter == 0) {
135 myInsideCoverpage = true;
136 myModelReader.setMainTextModel();
138 break;
139 case _SUB:
140 myModelReader.addControl(SUB, true);
141 break;
142 case _SUP:
143 myModelReader.addControl(SUP, true);
144 break;
145 case _CODE:
146 myModelReader.addControl(CODE, true);
147 break;
148 case _STRIKETHROUGH:
149 myModelReader.addControl(STRIKETHROUGH, true);
150 break;
151 case _STRONG:
152 myModelReader.addControl(STRONG, true);
153 break;
154 case _EMPHASIS:
155 myModelReader.addControl(EMPHASIS, true);
156 break;
157 case _A:
159 const char *ref = attributeValue(xmlattributes, myHrefAttributeName.c_str());
160 if (ref != 0) {
161 const char *type = attributeValue(xmlattributes, "type");
162 if((type != 0 && !strncmp(type, "note", 4)) || strstr(ref, "note"))
163 myHyperlinkType = FOOTNOTE;
164 else if(ref[0] == '#')
165 myHyperlinkType = INTERNAL_HYPERLINK;
166 else
167 myHyperlinkType = EXTERNAL_HYPERLINK;
169 if(ref[0] == '#')
170 ref++;
171 /* wrong
172 * if (ref[0] == '#') {
173 myHyperlinkType = FOOTNOTE;
174 ++ref;
175 } else {
176 myHyperlinkType = EXTERNAL_HYPERLINK;
179 myModelReader.addHyperlinkControl(myHyperlinkType, ref);
180 } else {
181 myHyperlinkType = FOOTNOTE;
182 myModelReader.addControl(myHyperlinkType, true);
184 break;
186 case _IMAGE:
188 const char *ref = attributeValue(xmlattributes, myHrefAttributeName.c_str());
189 const char *vOffset = attributeValue(xmlattributes, "voffset");
190 char offset = (vOffset != 0) ? atoi(vOffset) : 0;
191 if ((ref != 0) && (*ref == '#')) {
192 ++ref;
193 if ((myCoverImageReference != ref) ||
194 (myParagraphsBeforeBodyNumber != myModelReader.model().bookTextModel()->paragraphsNumber())) {
195 myModelReader.addImageReference(ref);
197 if (myInsideCoverpage) {
198 myCoverImageReference = ref;
201 break;
203 case _BINARY:
205 const char *contentType = attributeValue(xmlattributes, "content-type");
206 if ((contentType != 0) && (id != 0)) {
207 myCurrentImage = new Base64EncodedImage(contentType);
208 myModelReader.addImage(id, myCurrentImage);
209 myProcessingImage = true;
211 break;
213 case _EMPTY_LINE:
214 myModelReader.beginParagraph(ZLTextParagraph::EMPTY_LINE_PARAGRAPH);
215 myModelReader.endParagraph();
216 break;
217 case _BODY:
218 ++myBodyCounter;
219 myParagraphsBeforeBodyNumber = myModelReader.model().bookTextModel()->paragraphsNumber();
220 if ((myBodyCounter == 1) || (attributeValue(xmlattributes, "name") == 0)) {
221 myModelReader.setMainTextModel();
222 myReadMainText = true;
224 myModelReader.pushKind(REGULAR);
225 break;
226 default:
227 break;
231 void FB2BookReader::endElementHandler(int tag) {
232 switch (tag) {
233 case _P:
234 myModelReader.endParagraph();
235 break;
236 case _V:
237 case _SUBTITLE:
238 case _TEXT_AUTHOR:
239 case _DATE:
240 myModelReader.popKind();
241 myModelReader.endParagraph();
242 break;
243 case _CITE:
244 myModelReader.popKind();
245 break;
246 case _SECTION:
247 if (myReadMainText) {
248 myModelReader.endContentsParagraph();
249 --mySectionDepth;
250 mySectionStarted = false;
251 } else {
252 myModelReader.unsetTextModel();
254 break;
255 case _TITLE:
256 myModelReader.exitTitle();
257 myModelReader.popKind();
258 myInsideTitle = false;
259 break;
260 case _POEM:
261 myInsidePoem = false;
262 break;
263 case _STANZA:
264 myModelReader.beginParagraph(ZLTextParagraph::AFTER_SKIP_PARAGRAPH);
265 myModelReader.endParagraph();
266 myModelReader.popKind();
267 break;
268 case _EPIGRAPH:
269 myModelReader.popKind();
270 break;
271 case _ANNOTATION:
272 myModelReader.popKind();
273 if (myBodyCounter == 0) {
274 myModelReader.insertEndOfSectionParagraph();
275 myModelReader.unsetTextModel();
277 break;
278 case _COVERPAGE:
279 if (myBodyCounter == 0) {
280 myInsideCoverpage = false;
281 myModelReader.insertEndOfSectionParagraph();
282 myModelReader.unsetTextModel();
284 break;
285 case _SUB:
286 myModelReader.addControl(SUB, false);
287 break;
288 case _SUP:
289 myModelReader.addControl(SUP, false);
290 break;
291 case _CODE:
292 myModelReader.addControl(CODE, false);
293 break;
294 case _STRIKETHROUGH:
295 myModelReader.addControl(STRIKETHROUGH, false);
296 break;
297 case _STRONG:
298 myModelReader.addControl(STRONG, false);
299 break;
300 case _EMPHASIS:
301 myModelReader.addControl(EMPHASIS, false);
302 break;
303 case _A:
304 myModelReader.addControl(myHyperlinkType, false);
305 break;
306 case _BINARY:
307 if (!myImageBuffer.empty() && (myCurrentImage != 0)) {
308 myCurrentImage->addData(myImageBuffer);
309 myImageBuffer.clear();
310 myCurrentImage = 0;
312 myProcessingImage = false;
313 break;
314 case _BODY:
315 myModelReader.popKind();
316 myModelReader.unsetTextModel();
317 myReadMainText = false;
318 break;
319 default:
320 break;
324 bool FB2BookReader::processNamespaces() const {
325 return true;
328 void FB2BookReader::namespaceListChangedHandler() {
329 const std::string XLINK_REFERENCE = "http://www.w3.org/1999/xlink";
330 const std::map<std::string,std::string> namespaceMap = namespaces();
331 for (std::map<std::string,std::string>::const_iterator it = namespaceMap.begin(); it != namespaceMap.end(); ++it) {
332 if (ZLStringUtil::stringStartsWith(it->second, XLINK_REFERENCE)) {
333 myHrefAttributeName = it->first + ":href";
334 return;
337 myHrefAttributeName = "";
340 bool FB2BookReader::readBook(const std::string &fileName) {
341 myHrefAttributeName = "";
342 return readDocument(fileName);