1 #include "../include/fb2def.h"
2 #include "../include/crlog.h"
3 #include "odxutil.h"
4
OnTagOpen(const lChar32 * nsname,const lChar32 * tagname)5 ldomNode * docXMLreader::OnTagOpen( const lChar32 * nsname, const lChar32 * tagname)
6 {
7 if ( m_state == xml_doc_in_start && !lStr_cmp(tagname, "?xml") )
8 m_state = xml_doc_in_xml_declaration;
9 else if( !isSkipping() ) {
10 if ( m_handler )
11 return m_handler->handleTagOpen(nsname, tagname);
12 } else
13 // skip nested tag
14 skip();
15 return NULL;
16 }
17
OnStart(LVFileFormatParser *)18 void docXMLreader::OnStart(LVFileFormatParser *)
19 {
20 m_skipTag = 0;
21 m_state = xml_doc_in_start;
22 }
23
OnTagBody()24 void docXMLreader::OnTagBody()
25 {
26 if( m_state != xml_doc_in_xml_declaration && !isSkipping() && m_handler )
27 m_handler->handleTagBody();
28 }
29
OnTagClose(const lChar32 * nsname,const lChar32 * tagname,bool self_closing_tag)30 void docXMLreader::OnTagClose(const lChar32 * nsname, const lChar32 * tagname , bool self_closing_tag)
31 {
32 CR_UNUSED2(nsname, self_closing_tag);
33
34 switch(m_state) {
35 case xml_doc_in_xml_declaration:
36 m_state = xml_doc_in_document;
37 break;
38 case xml_doc_in_document:
39 if( isSkipping() )
40 skipped();
41 else if ( m_handler )
42 m_handler->handleTagClose(U"", tagname);
43 break;
44 default:
45 CRLog::error("Unexpected state");
46 break;
47 }
48 }
49
OnAttribute(const lChar32 * nsname,const lChar32 * attrname,const lChar32 * attrvalue)50 void docXMLreader::OnAttribute( const lChar32 * nsname, const lChar32 * attrname, const lChar32 * attrvalue )
51 {
52 switch(m_state) {
53 case xml_doc_in_xml_declaration:
54 if ( m_writer )
55 m_writer->OnAttribute(nsname, attrname, attrvalue);
56 break;
57 case xml_doc_in_document:
58 if ( !isSkipping() && m_handler )
59 m_handler->handleAttribute(nsname, attrname, attrvalue);
60 break;
61 default:
62 CRLog::error("Unexpected state");
63 }
64 }
65
OnText(const lChar32 * text,int len,lUInt32 flags)66 void docXMLreader::OnText( const lChar32 * text, int len, lUInt32 flags )
67 {
68 if( !isSkipping() && m_handler )
69 m_handler->handleText(text, len, flags);
70 }
71
OnBlob(lString32 name,const lUInt8 * data,int size)72 bool docXMLreader::OnBlob(lString32 name, const lUInt8 * data, int size)
73 {
74 if ( !isSkipping() && m_writer )
75 return m_writer->OnBlob(name, data, size);
76 return false;
77 }
78
setChildrenInfo(const struct item_def_t * tags)79 void xml_ElementHandler::setChildrenInfo(const struct item_def_t *tags)
80 {
81 m_children = tags;
82 }
83
parse_name(const struct item_def_t * tags,const lChar32 * nameValue)84 int xml_ElementHandler::parse_name(const struct item_def_t *tags, const lChar32 * nameValue)
85 {
86 for (int i=0; tags[i].name; i++) {
87 if ( !lStr_cmp( tags[i].name, nameValue )) {
88 // found!
89 return tags[i].id;
90 }
91 }
92 return -1;
93 }
94
parse_int(const lChar32 * attrValue,css_length_t & result)95 void xml_ElementHandler::parse_int(const lChar32 * attrValue, css_length_t & result)
96 {
97 lString32 value = attrValue;
98
99 result.type = css_val_unspecified;
100 if ( value.atoi(result.value) )
101 result.type = css_val_pt; //just to distinguish with unspecified value
102 }
103
handleTagOpen(const lChar32 * nsname,const lChar32 * tagname)104 ldomNode *xml_ElementHandler::handleTagOpen(const lChar32 *nsname, const lChar32 *tagname)
105 {
106 int tag = parseTagName(tagname);
107
108 CR_UNUSED(nsname);
109 if( -1 == tag) {
110 // skip the tag we are not interested in
111 m_reader->skip();
112 return NULL;
113 }
114 return handleTagOpen(tag);
115 }
116
handleTagOpen(int tagId)117 ldomNode *xml_ElementHandler::handleTagOpen(int tagId)
118 {
119 m_state = tagId;
120 return NULL;
121 }
122
start()123 void xml_ElementHandler::start()
124 {
125 m_savedHandler = m_reader->getHandler();
126 reset();
127 m_reader->setHandler(this);
128 }
129
stop()130 void xml_ElementHandler::stop()
131 {
132 m_reader->setHandler(m_savedHandler);
133 m_savedHandler = NULL;
134 }
135
reset()136 void xml_ElementHandler::reset()
137 {
138 }
139
onBodyStart()140 ldomNode *odx_titleHandler::onBodyStart()
141 {
142 return m_writer->OnTagOpen(U"", U"body");
143 }
144
onTitleStart(int level,bool noSection)145 void odx_titleHandler::onTitleStart(int level, bool noSection)
146 {
147 CR_UNUSED(noSection);
148
149 m_titleLevel = level;
150 lString32 name = cs32("h") + lString32::itoa(m_titleLevel);
151 if( m_useClassName ) {
152 m_writer->OnTagOpen(U"", U"p");
153 m_writer->OnAttribute(U"", U"class", name.c_str());
154 } else
155 m_writer->OnTagOpen(U"", name.c_str());
156 }
157
onTitleEnd()158 void odx_titleHandler::onTitleEnd()
159 {
160 if( !m_useClassName ) {
161 lString32 tagName = cs32("h") + lString32::itoa(m_titleLevel);
162 m_writer->OnTagClose(U"", tagName.c_str());
163 } else
164 m_writer->OnTagClose(U"", U"p");
165 }
166
onBodyStart()167 ldomNode* odx_fb2TitleHandler::onBodyStart()
168 {
169 m_section = m_writer->OnTagOpen(U"", U"body");
170 return m_section;
171 }
172
onTitleStart(int level,bool noSection)173 void odx_fb2TitleHandler::onTitleStart(int level, bool noSection)
174 {
175 if( noSection )
176 odx_titleHandler::onTitleStart(level, true);
177 else {
178 if( m_titleLevel < level ) {
179 int startIndex = m_hasTitle ? 1 : 0;
180 int contentCount = m_section->getChildCount();
181 if(contentCount > startIndex)
182 makeSection(startIndex);
183 } else
184 closeSection(m_titleLevel - level + 1);
185 openSection(level);
186 m_writer->OnTagOpen(U"", U"title");
187 lString32 headingName = cs32("h") + lString32::itoa(level);
188 if( m_useClassName ) {
189 m_writer->OnTagBody();
190 m_writer->OnTagOpen(U"", U"p");
191 m_writer->OnAttribute(U"", U"class", headingName.c_str());
192 } else {
193 m_writer->OnTagBody();
194 m_writer->OnTagOpen(U"", headingName.c_str());
195 }
196 }
197 }
198
onTitleEnd()199 void odx_fb2TitleHandler::onTitleEnd()
200 {
201 if( !m_useClassName ) {
202 lString32 headingName = cs32("h") + lString32::itoa(m_titleLevel);
203 m_writer->OnTagClose(U"", headingName.c_str());
204 } else
205 m_writer->OnTagClose(U"", U"p");
206
207 m_writer->OnTagClose(U"", U"title");
208 m_hasTitle = true;
209 }
210
makeSection(int startIndex)211 void odx_fb2TitleHandler::makeSection(int startIndex)
212 {
213 ldomNode *newSection = m_section->insertChildElement(startIndex, LXML_NS_NONE, el_section);
214 newSection->initNodeStyle();
215 m_section->moveItemsTo(newSection, startIndex + 1, m_section->getChildCount() - 1);
216 newSection->initNodeRendMethod( );
217 m_section = newSection;
218 }
219
openSection(int level)220 void odx_fb2TitleHandler::openSection(int level)
221 {
222 for(int i = m_titleLevel; i < level; i++) {
223 m_section = m_writer->OnTagOpen(U"", U"section");
224 m_writer->OnTagBody();
225 }
226 m_titleLevel = level;
227 m_hasTitle = false;
228 }
229
closeSection(int level)230 void odx_fb2TitleHandler::closeSection(int level)
231 {
232 for(int i = 0; i < level; i++) {
233 m_writer->OnTagClose(U"", U"section");
234 m_titleLevel--;
235 }
236 m_hasTitle = false;
237 }
238
odx_rPr()239 odx_rPr::odx_rPr() : odx_StylePropertiesContainer(odx_character_style)
240 {
241 }
242
getCss()243 lString32 odx_rPr::getCss()
244 {
245 lString32 style;
246
247 if( isBold() )
248 style << " font-weight: bold;";
249 if( isItalic() )
250 style << " font-style: italic;";
251 if( isUnderline() )
252 style << " text-decoration: underline;";
253 if( isStrikeThrough() )
254 style << " text-decoration: line-through;";
255 return style;
256 }
257
odx_pPr()258 odx_pPr::odx_pPr() : odx_StylePropertiesContainer(odx_paragraph_style)
259 {
260 }
261
getCss()262 lString32 odx_pPr::getCss()
263 {
264 lString32 style;
265
266 css_text_align_t align = getTextAlign();
267 if(align != css_ta_inherit)
268 {
269 style << "text-align: ";
270 switch(align)
271 {
272 case css_ta_left:
273 style << "left;";
274 break;
275 case css_ta_right:
276 style << "right;";
277 break;
278 case css_ta_center:
279 style << "center;";
280 break;
281 case css_ta_justify:
282 style << "justify;";
283 break;
284 case css_ta_end:
285 style << "end;";
286 break;
287 case css_ta_start:
288 style << "start;";
289 break;
290 default:
291 style << "inherited;";
292 break;
293 }
294 }
295 if( isPageBreakBefore() )
296 style << "page-break-before: always;";
297 else if ( isKeepNext() )
298 style << "page-break-before: avoid;";
299 return style;
300 }
301
odx_Style()302 odx_Style::odx_Style() : m_type(odx_paragraph_style),
303 m_pPrMerged(false), m_rPrMerged(false)
304 {
305 }
306
isValid() const307 bool odx_Style::isValid() const
308 {
309 return ( odx_invalid_style != m_type && !m_Id.empty() );
310 }
311
getBaseStyle(odx_ImportContext * context)312 odx_Style *odx_Style::getBaseStyle(odx_ImportContext *context)
313 {
314 lString32 basedOn = getBasedOn();
315 if ( !basedOn.empty() ) {
316 odx_Style *pStyle = context->getStyle(basedOn);
317 if( pStyle && pStyle->getStyleType() == getStyleType() )
318 return pStyle;
319 }
320 return NULL;
321 }
322
get_pPr(odx_ImportContext * context)323 odx_pPr *odx_Style::get_pPr(odx_ImportContext *context)
324 {
325 if( !m_pPrMerged ) {
326 odx_Style* pStyle = getBaseStyle(context);
327 if (pStyle ) {
328 m_pPr.combineWith(pStyle->get_pPr(context));
329 }
330 m_pPrMerged = true;
331 }
332 return &m_pPr;
333 }
334
get_rPr(odx_ImportContext * context)335 odx_rPr *odx_Style::get_rPr(odx_ImportContext *context)
336 {
337 if( !m_rPrMerged ) {
338 odx_Style* pStyle = getBaseStyle(context);
339 if (pStyle ) {
340 m_rPr.combineWith(pStyle->get_rPr(context));
341 }
342 m_rPrMerged = true;
343 }
344 return &m_rPr;
345 }
346
getStyleProperties(odx_ImportContext * context,odx_style_type styleType)347 odx_StylePropertiesGetter *odx_Style::getStyleProperties(odx_ImportContext *context, odx_style_type styleType)
348 {
349 switch(styleType) {
350 case odx_paragraph_style:
351 return get_pPr(context);
352 case odx_character_style:
353 return get_rPr(context);
354 default:
355 break;
356 }
357 return NULL;
358 }
359
addStyle(odx_StyleRef style)360 void odx_ImportContext::addStyle(odx_StyleRef style)
361 {
362 odx_Style *referenced = style.get();
363 if ( NULL != referenced)
364 {
365 m_styles.set(referenced->getId(), style);
366 }
367 }
368
setLanguage(const lChar32 * lang)369 void odx_ImportContext::setLanguage(const lChar32 *lang)
370 {
371 lString32 language(lang);
372
373 int p = language.pos(cs32("-"));
374 if ( p > 0 ) {
375 language = language.substr(0, p);
376 }
377 m_doc->getProps()->setString(DOC_PROP_LANGUAGE, language);
378 }
379
getListStyleCss(css_list_style_type_t listType)380 lString32 odx_ImportContext::getListStyleCss(css_list_style_type_t listType)
381 {
382 switch(listType) {
383 case css_lst_disc:
384 return cs32("list-style-type: disc;");
385 case css_lst_circle:
386 return cs32("list-style-type: circle;");
387 case css_lst_square:
388 return cs32("list-style-type: square;");
389 case css_lst_decimal:
390 return cs32("list-style-type: decimal;");
391 case css_lst_lower_roman:
392 return cs32("list-style-type: lower-roman;");
393 case css_lst_upper_roman:
394 return cs32("list-style-type: upper-roman;");
395 case css_lst_lower_alpha:
396 return cs32("list-style-type: lower-alpha;");
397 case css_lst_upper_alpha:
398 return cs32("list-style-type: upper-alpha;");
399 default:
400 break;
401 }
402 return cs32("list-style-type: none;");
403 }
404
startDocument(ldomDocumentWriter & writer)405 void odx_ImportContext::startDocument(ldomDocumentWriter &writer)
406 {
407 #ifdef DOCX_FB2_DOM_STRUCTURE
408 writer.OnStart(NULL);
409 writer.OnTagOpen(NULL, U"?xml");
410 writer.OnAttribute(NULL, U"version", U"1.0");
411 writer.OnAttribute(NULL, U"encoding", U"utf-8");
412 writer.OnEncoding(U"utf-8", NULL);
413 writer.OnTagBody();
414 writer.OnTagClose(NULL, U"?xml");
415 writer.OnTagOpenNoAttr(NULL, U"FictionBook");
416 // DESCRIPTION
417 writer.OnTagOpenNoAttr(NULL, U"description");
418 writer.OnTagOpenNoAttr(NULL, U"title-info");
419 writer.OnTagOpenNoAttr(NULL, U"book-title");
420 writer.OnTagClose(NULL, U"book-title");
421 writer.OnTagClose(NULL, U"title-info");
422 writer.OnTagClose(NULL, U"description");
423 #else
424 writer.OnStart(NULL);
425 writer.OnTagOpen(NULL, U"?xml");
426 writer.OnAttribute(NULL, U"version", U"1.0");
427 writer.OnAttribute(NULL, U"encoding", U"utf-8");
428 writer.OnEncoding(U"utf-8", NULL);
429 writer.OnTagBody();
430 writer.OnTagClose(NULL, U"?xml");
431 writer.OnTagOpenNoAttr(NULL, U"html");
432 #endif
433 }
434
endDocument(ldomDocumentWriter & writer)435 void odx_ImportContext::endDocument(ldomDocumentWriter &writer)
436 {
437 #ifdef DOCX_FB2_DOM_STRUCTURE
438 writer.OnTagClose(NULL, U"FictionBook");
439 #else
440 writer.OnTagClose(NULL, U"html");
441 #endif
442 }
443
styleTagPos(lChar32 ch)444 int odx_styleTagsHandler::styleTagPos(lChar32 ch)
445 {
446 for (int i=0; i < m_styleTags.length(); i++)
447 if (m_styleTags[i] == ch)
448 return i;
449 return -1;
450 }
451
getStyleTagName(lChar32 ch)452 const lChar32 *odx_styleTagsHandler::getStyleTagName(lChar32 ch)
453 {
454 switch ( ch ) {
455 case 'b':
456 return U"strong";
457 case 'i':
458 return U"em";
459 case 'u':
460 return U"u";
461 case 's':
462 return U"s";
463 case 't':
464 return U"sup";
465 case 'd':
466 return U"sub";
467 default:
468 return NULL;
469 }
470 }
471
closeStyleTag(lChar32 ch,ldomDocumentWriter * writer)472 void odx_styleTagsHandler::closeStyleTag(lChar32 ch, ldomDocumentWriter *writer)
473 {
474 int pos = styleTagPos( ch );
475 if (pos >= 0) {
476 for (int i = m_styleTags.length() - 1; i >= pos; i--) {
477 const lChar32 * tag = getStyleTagName(m_styleTags[i]);
478 m_styleTags.erase(m_styleTags.length() - 1, 1);
479 if ( tag ) {
480 writer->OnTagClose(U"", tag);
481 }
482 }
483 }
484 }
485
openStyleTag(lChar32 ch,ldomDocumentWriter * writer)486 void odx_styleTagsHandler::openStyleTag(lChar32 ch, ldomDocumentWriter *writer)
487 {
488 int pos = styleTagPos( ch );
489 if (pos < 0) {
490 const lChar32 * tag = getStyleTagName(ch);
491 if ( tag ) {
492 writer->OnTagOpenNoAttr(U"", tag);
493 m_styleTags.append( 1, ch );
494 }
495 }
496 }
497
openStyleTags(odx_rPr * runProps,ldomDocumentWriter * writer)498 void odx_styleTagsHandler::openStyleTags(odx_rPr *runProps, ldomDocumentWriter *writer)
499 {
500 if(runProps->isBold())
501 openStyleTag('b', writer);
502 if(runProps->isItalic())
503 openStyleTag('i', writer);
504 if(runProps->isUnderline())
505 openStyleTag('u', writer);
506 if(runProps->isStrikeThrough())
507 openStyleTag('s', writer);
508 if(runProps->isSubScript())
509 openStyleTag('d', writer);
510 if(runProps->isSuperScript())
511 openStyleTag('t', writer);
512 }
513
closeStyleTags(odx_rPr * runProps,ldomDocumentWriter * writer)514 void odx_styleTagsHandler::closeStyleTags(odx_rPr *runProps, ldomDocumentWriter *writer)
515 {
516 if(!runProps->isBold())
517 closeStyleTag('b', writer);
518 if(!runProps->isItalic())
519 closeStyleTag('i', writer);
520 if(!runProps->isUnderline())
521 closeStyleTag('u', writer);
522 if(!runProps->isStrikeThrough())
523 closeStyleTag('s', writer);
524 if(!runProps->isSubScript())
525 closeStyleTag('d', writer);
526 if(!runProps->isSuperScript())
527 closeStyleTag('t', writer);
528 }
529
closeStyleTags(ldomDocumentWriter * writer)530 void odx_styleTagsHandler::closeStyleTags(ldomDocumentWriter *writer)
531 {
532 for(int i = m_styleTags.length() - 1; i >= 0; i--)
533 closeStyleTag(m_styleTags[i], writer);
534 m_styleTags.clear();
535 }
536