1 #include "../include/odtfmt.h"
2 #include "../include/lvtinydom.h"
3 #include "../include/fb2def.h"
4 #include "../include/lvopc.h"
5 #include "../include/crlog.h"
6 #include "odxutil.h"
7 
8 // If you add new element - update odt_elements_mapping table below
9 #define ODT_TAGS \
10     ODT_TAG(a)\
11     ODT_TAG2(automaticStyles, "automatic-styles")\
12     ODT_TAG(body)\
13     ODT_TAG(bookmark)\
14     ODT_TAG2(bookmarkRef, "bookmark-ref")\
15     ODT_TAG2(bookmarkStart, "bookmark-start")\
16     ODT_TAG2(defaultStyle, "default-style")\
17     ODT_TAG2(documentContent, "document-content")\
18     ODT_TAG2(documentStyles, "document-styles")\
19     ODT_TAG(frame)\
20     ODT_TAG(h)\
21     ODT_TAG(image)\
22     ODT_TAG2(indexBody, "index-body")\
23     ODT_TAG2(lineBreak, "line-break")\
24     ODT_TAG(list)\
25     ODT_TAG2(listStyle, "list-style")\
26     ODT_TAG2(listLevelStyleBullet, "list-level-style-bullet")\
27     ODT_TAG2(listLevelStyleNumber, "list-level-style-number")\
28     ODT_TAG2(listItem, "list-item")\
29     ODT_TAG(note)\
30     ODT_TAG2(noteBody, "note-body")\
31     ODT_TAG2(noteCitation, "note-citation")\
32     ODT_TAG2(noteRef, "note-ref")\
33     ODT_TAG(p)\
34     ODT_TAG2(paragraphProperties, "paragraph-properties")\
35     ODT_TAG2(referenceMark, "reference-mark")\
36     ODT_TAG2(referenceMarkStart, "reference-mark-start")\
37     ODT_TAG2(referenceRef, "reference-ref")\
38     ODT_TAG(s)\
39     ODT_TAG(span)\
40     ODT_TAG(style)\
41     ODT_TAG(styles)\
42     ODT_TAG(tab)\
43     ODT_TAG(table)\
44     ODT_TAG2(tableHeaderRows, "table-header-rows")\
45     ODT_TAG2(tableOfContent, "table-of-content")\
46     ODT_TAG2(tableRow, "table-row")\
47     ODT_TAG2(tableCell, "table-cell")\
48     ODT_TAG(text)\
49     ODT_TAG2(textBox, "text-box")\
50     ODT_TAG2(textProperties, "text-properties")
51 
52 #define ODT_TAG_NAME(itm) odt_el_##itm##_name
53 #define ODT_TAG_ID(itm) odt_el_##itm
54 #define ODT_TAG_CHILD(itm) { ODT_TAG_ID(itm), ODT_TAG_NAME(itm) }
55 #define ODT_TAG_CHILD2(itm, name) { ODT_TAG_ID(itm), U ## name }
56 #define ODT_LAST_ITEM { -1, NULL }
57 
58 enum {
59 #define ODT_TAG(itm) ODT_TAG_ID(itm),
60 #define ODT_TAG2(itm, name) ODT_TAG_ID(itm),
61     odt_el_NULL = 0,
62     ODT_TAGS
63     odt_el_MAX_ID
64 };
65 
66 #undef ODT_TAG
67 #undef ODT_TAG2
68 #define ODT_TAG(itm) static const lChar32 * const ODT_TAG_NAME(itm) = U ## #itm;
69 #define ODT_TAG2(itm, name) static const lChar32 * const ODT_TAG_NAME(itm) = U ## name;
70     ODT_TAGS
71 
72 #undef ODT_TAG
73 #undef ODT_TAG2
74 #define ODT_TAG(itm) ODT_TAG_CHILD(itm),
75 #define ODT_TAG2(itm, name) ODT_TAG_CHILD2(itm, name),
76 
77 const struct item_def_t odt_elements_mapping[] = {
78     { odt_el_NULL, NULL },
79     { odt_el_a, U"a" },
80     { odt_el_automaticStyles, NULL },
81     { odt_el_body, U"body" },
82     { odt_el_bookmark, U"a" },
83     { odt_el_bookmarkRef, U"a" },
84     { odt_el_bookmarkStart, U"a" },
85     { odt_el_defaultStyle, NULL },
86     { odt_el_documentContent, NULL },
87     { odt_el_documentStyles, NULL },
88     { odt_el_frame, NULL },
89     { odt_el_h, NULL /*Special processing*/},
90     { odt_el_image, U"img" },
91     { odt_el_indexBody, NULL },
92     { odt_el_lineBreak, U"br" },
93     { odt_el_list, U"ol" },
94     { odt_el_listStyle, NULL },
95     { odt_el_listLevelStyleBullet, NULL },
96     { odt_el_listLevelStyleNumber, NULL },
97     { odt_el_listItem, U"li" },
98     { odt_el_note, NULL },
99     { odt_el_noteBody, NULL /*Special Processing */ },
100     { odt_el_noteCitation, NULL /*Special Processing */ },
101     { odt_el_noteRef, U"a" },
102     { odt_el_p, U"p" },
103     { odt_el_paragraphProperties, NULL },
104     { odt_el_referenceMark, U"a" },
105     { odt_el_referenceMarkStart, U"a" },
106     { odt_el_referenceRef, U"a" },
107     { odt_el_s, NULL },
108     { odt_el_span, NULL },
109     { odt_el_style, NULL },
110     { odt_el_styles, NULL },
111     { odt_el_tab, NULL },
112     { odt_el_table, U"table" },
113     { odt_el_tableHeaderRows, U"thead" },
114     { odt_el_tableOfContent, NULL },
115     { odt_el_tableRow, U"tr" },
116     { odt_el_tableCell, U"td" },
117     { odt_el_text, NULL },
118     { odt_el_textBox, NULL },
119     { odt_el_textProperties, NULL }
120 };
121 
122 const struct item_def_t odt_elements[] = {
123     ODT_TAG_CHILD(a),
124     ODT_TAG_CHILD(automaticStyles),
125     ODT_TAG_CHILD(body),
126     ODT_TAG_CHILD(bookmark),
127     ODT_TAG_CHILD(bookmarkRef),
128     ODT_TAG_CHILD(bookmarkStart),
129     ODT_TAG_CHILD(documentContent),
130     ODT_TAG_CHILD(frame),
131     ODT_TAG_CHILD(h),
132     ODT_TAG_CHILD(image),
133     ODT_TAG_CHILD(indexBody),
134     ODT_TAG_CHILD(lineBreak),
135     ODT_TAG_CHILD(list),
136     ODT_TAG_CHILD(listItem),
137     ODT_TAG_CHILD(note),
138     ODT_TAG_CHILD(noteBody),
139     ODT_TAG_CHILD(noteCitation),
140     ODT_TAG_CHILD(noteRef),
141     ODT_TAG_CHILD(p),
142     ODT_TAG_CHILD(referenceMark),
143     ODT_TAG_CHILD(referenceMarkStart),
144     ODT_TAG_CHILD(referenceRef),
145     ODT_TAG_CHILD(s),
146     ODT_TAG_CHILD(span),
147     ODT_TAG_CHILD(tab),
148     ODT_TAG_CHILD(table),
149     ODT_TAG_CHILD(tableHeaderRows),
150     ODT_TAG_CHILD(tableOfContent),
151     ODT_TAG_CHILD(tableRow),
152     ODT_TAG_CHILD(tableCell),
153     ODT_TAG_CHILD(text),
154     ODT_TAG_CHILD(textBox),
155     ODT_LAST_ITEM
156 };
157 
158 const struct item_def_t odt_style_elements[] = {
159     ODT_TAG_CHILD(automaticStyles),
160     ODT_TAG_CHILD(defaultStyle),
161     ODT_TAG_CHILD(documentStyles),
162     ODT_TAG_CHILD(listStyle),
163     ODT_TAG_CHILD(listLevelStyleBullet),
164     ODT_TAG_CHILD(listLevelStyleNumber),
165     ODT_TAG_CHILD(paragraphProperties),
166     ODT_TAG_CHILD(style),
167     ODT_TAG_CHILD(styles),
168     ODT_TAG_CHILD(textProperties),
169     ODT_LAST_ITEM
170 };
171 
172 static const struct item_def_t styleFamily_attr_values[] = {
173     { odx_paragraph_style, U"paragraph" },
174     { odx_character_style, U"text"},
175     ODT_LAST_ITEM
176 };
177 
178 const struct item_def_t odt_fontWeigth_attr_values[] = {
179     { 400, U"normal" },
180     { 600, U"bold" },
181     { 100, U"100" },
182     { 200, U"200" },
183     { 300, U"300" },
184     { 400, U"400" },
185     { 500, U"500" },
186     { 600, U"600" },
187     { 700, U"700" },
188     { 800, U"800" },
189     { 900, U"900" },
190     ODT_LAST_ITEM
191 };
192 
193 static const struct item_def_t odt_textAlign_attr_values[] =
194 {
195     { css_ta_left, U"left" },
196     { css_ta_right, U"right" },
197     { css_ta_center, U"center" },
198     { css_ta_justify, U"justify" },
199     { css_ta_start, U"start" },
200     { css_ta_end, U"end" },
201     ODT_LAST_ITEM
202 };
203 
DetectOpenDocumentFormat(LVStreamRef stream)204 bool DetectOpenDocumentFormat( LVStreamRef stream )
205 {
206     LVContainerRef arc = LVOpenArchieve( stream );
207     if ( arc.isNull() )
208         return false; // not a ZIP archive
209     lString32 mimeType;
210     {
211         LVStreamRef mtStream = arc->OpenStream(U"mimetype", LVOM_READ );
212         if ( !mtStream.isNull() ) {
213             lvsize_t size = mtStream->GetSize();
214             if ( size>4 && size<100 ) {
215                 LVArray<char> buf( size+1, '\0' );
216                 if ( mtStream->Read( buf.get(), size, NULL )==LVERR_OK ) {
217                     for ( lvsize_t i=0; i<size; i++ )
218                         if ( buf[i]<32 || ((unsigned char)buf[i])>127 )
219                             buf[i] = 0;
220                     buf[size] = 0;
221                     if ( buf[0] )
222                         mimeType = Utf8ToUnicode( lString8( buf.get() ) );
223                 }
224             }
225         }
226     }
227     return ( mimeType == U"application/vnd.oasis.opendocument.text" );
228 }
229 
230 class odt_ListLevelStyle : public LVRefCounter
231 {
232     css_length_t m_lvlStart;
233     css_list_style_type_t m_levelType;
234     int m_level;
235 public:
odt_ListLevelStyle()236     odt_ListLevelStyle() :
237         m_lvlStart(css_val_unspecified, 0), m_levelType(css_lst_disc), m_level(0) { }
~odt_ListLevelStyle()238     virtual ~odt_ListLevelStyle() {}
getLevelStart() const239     inline css_length_t getLevelStart() const { return m_lvlStart; }
setLevelStart(int value)240     inline void setLevelStart( int value) {
241         m_lvlStart.type = css_val_pt;
242         m_lvlStart.value = value;
243     }
getLevel()244     inline int getLevel() { return m_level; }
setLevel(const lChar32 * value)245     inline void setLevel( const lChar32* value) { m_level = lString32(value).atoi(); }
getLevelType()246     inline css_list_style_type_t getLevelType() { return m_levelType; }
setLevelType(css_list_style_type_t levelType)247     inline void setLevelType(css_list_style_type_t levelType) { m_levelType = levelType; }
reset()248     void reset() {}
249 };
250 
251 typedef LVFastRef< odt_ListLevelStyle > odt_ListLevelStyleRef;
252 
253 class odt_ListStyle : public LVRefCounter
254 {
255     LVHashTable<lUInt32, odt_ListLevelStyleRef> m_levels;
256     bool m_consecutiveNumbering;
257     lString32 m_Id;
258 public:
odt_ListStyle()259     odt_ListStyle() : m_levels(10), m_consecutiveNumbering(false) {}
~odt_ListStyle()260     virtual ~odt_ListStyle() {}
getLevel(int level)261     odt_ListLevelStyle* getLevel(int level) {
262         return m_levels.get(level).get();
263     }
getId() const264     inline lString32 getId() const { return m_Id; }
setId(const lChar32 * value)265     inline void setId(const lChar32 * value) { m_Id = value; }
getConsecutiveNumbering()266     bool getConsecutiveNumbering() { return m_consecutiveNumbering; }
setConsecutiveNumbering(bool value)267     void setConsecutiveNumbering(bool value) {
268         m_consecutiveNumbering = value;
269     }
270     void addLevel(odt_ListLevelStyleRef listLevel);
reset()271     void reset() { m_levels.clear(); }
272 };
273 
274 typedef LVFastRef< odt_ListStyle > odt_ListStyleRef;
275 
276 class odtImportContext : public odx_ImportContext
277 {
278     LVHashTable<lString32, odt_ListStyleRef> m_ListStyles;
279 public:
odtImportContext(ldomDocument * doc)280     explicit odtImportContext(ldomDocument* doc) : odx_ImportContext(doc), m_ListStyles(64) { }
281     void addListStyle(odt_ListStyleRef listStyle);
getListStyle(lString32 id)282     odt_ListStyle* getListStyle(lString32 id) {
283         if( !id.empty() )
284             return m_ListStyles.get(id).get();
285         return NULL;
286     }
287     LVStreamRef openFile(const lChar32 * const fileName);
288 };
289 
290 class odt_stylesHandler : public xml_ElementHandler
291 {
292 private:
293     LVArray<int> m_levels;
294     odx_StyleRef m_styleRef;
295     odx_Style *m_style;
296     odt_ListStyleRef m_ListStyleRef;
297     odt_ListStyle *m_ListStyle;
298     odt_ListLevelStyleRef m_ListLevelStyleRef;
299     odt_ListLevelStyle *m_ListLevelStyle;
300     odx_pPr* m_pPr;
301     odx_rPr* m_rPr;
302     odtImportContext *m_context;
303 public:
304     /// constructor
odt_stylesHandler(docXMLreader * reader,ldomDocumentWriter * writer,int element,odtImportContext * context)305     odt_stylesHandler(docXMLreader * reader, ldomDocumentWriter *writer, int element,
306                       odtImportContext *context) :
307         xml_ElementHandler(reader, writer, element, odt_style_elements),
308             m_style(NULL), m_ListStyle(NULL), m_pPr(NULL), m_rPr(NULL), m_context(context)
309     {
310     }
311     ldomNode * handleTagOpen(int tagId);
312     void handleAttribute(const lChar32 * attrname, const lChar32 * attrvalue);
313     void handleTagClose( const lChar32 * nsname, const lChar32 * tagname );
314 };
315 
316 class odt_documentHandler : public xml_ElementHandler, odx_styleTagsHandler
317 {
318     LVArray<int> m_levels;
319     LVArray<bool> m_listItems;
320     LVArray<odt_ListStyle*> m_ListLevels;
321     ldomDocumentWriter m_footNotesWriter;
322     ldomDocumentWriter m_endNotesWriter;
323     ldomDocumentWriter *m_saveWriter;
324     odtImportContext * m_context;
325     ldomNode *m_footNotes;
326     ldomNode *m_endNotes;
327     ldomNode *m_body;
328     lString32 m_noteId;
329     lString32 m_noteRefText;
330     lString32 m_StyleName;
331     lString32 m_spanStyleName;
332     bool m_isEndNote;
333     bool m_paragraphStarted;
334     odt_stylesHandler m_stylesHandler;
335 private:
startNotes(const lChar32 * notesKind)336     ldomNode* startNotes(const lChar32 * notesKind) {
337         m_writer->OnStart(NULL);
338 #ifdef ODX_CRENGINE_IN_PAGE_FOOTNOTES
339         ldomNode* notes = m_writer->OnTagOpen(U"", U"body");
340         m_writer->OnAttribute(U"", U"name", notesKind);
341 #else
342         ldomNode* notes = m_writer->OnTagOpen(U"", U"div");
343         m_writer->OnAttribute(U"", U"style", U"page-break-before: always");
344 #endif
345         m_writer->OnTagBody();
346         return notes;
347     }
finishNotes(ldomNode * notes,ldomDocumentWriter & writer)348     void finishNotes(ldomNode* notes, ldomDocumentWriter& writer) {
349         ldomNode* parent = notes->getParentNode();
350         int index = notes->getNodeIndex();
351 #ifdef ODX_CRENGINE_IN_PAGE_FOOTNOTES
352         writer.OnTagClose(U"", U"body");
353 #else
354         writer.OnTagClose(U"", U"div");
355 #endif
356         writer.OnStop();
357         parent->moveItemsTo(m_body->getParentNode(), index, index);
358     }
checkParagraphStart()359     inline void checkParagraphStart() {
360         if( !m_paragraphStarted ) {
361             startParagraph();
362         }
363     }
364     void startParagraph();
365 protected:
366     odx_titleHandler* m_titleHandler;
367     int m_outlineLevel;
368     bool m_inTable;
369     bool m_inListItem;
370     bool m_listItemHadContent;
371 public:
odt_documentHandler(ldomDocument * doc,docXMLreader * reader,ldomDocumentWriter * writer,odx_titleHandler * titleHandler,odtImportContext * context)372     odt_documentHandler(ldomDocument * doc, docXMLreader * reader,
373                         ldomDocumentWriter * writer, odx_titleHandler* titleHandler,
374                         odtImportContext * context) :
375         xml_ElementHandler(reader, writer, odt_el_NULL, odt_elements),
376         m_footNotesWriter(doc), m_endNotesWriter(doc), m_saveWriter(NULL),
377         m_context(context), m_footNotes(NULL), m_endNotes(NULL), m_body(NULL),
378         m_isEndNote(false), m_titleHandler(titleHandler),
379         m_outlineLevel(0), m_inTable(false), m_inListItem(false),
380         m_stylesHandler(reader, NULL, odt_el_automaticStyles, context),
381         m_listItemHadContent(false), m_paragraphStarted(false) {
382     }
isInList()383     inline bool isInList() { return m_ListLevels.length() != 0; }
384     ldomNode *handleTagOpen(int tagId);
385     void handleAttribute(const lChar32 *attrname, const lChar32 *attrValue);
386     void handleTagBody();
387     void handleTagClose(const lChar32 *nsname, const lChar32 *tagname);
388     void handleText(const lChar32 *text, int len, lUInt32 flags);
389     void reset();
390 };
391 
parseStyles(odtImportContext * context)392 static bool parseStyles(odtImportContext *context)
393 {
394     LVStreamRef stream = context->openFile(U"styles.xml");
395     if ( stream.isNull() )
396         return false;
397 
398     docXMLreader docReader(NULL);
399     odt_stylesHandler stylesHandler(&docReader, NULL, odt_el_documentStyles, context);
400     docReader.setHandler(&stylesHandler);
401 
402     LVXMLParser parser(stream, &docReader);
403 
404     if ( !parser.Parse() )
405         return false;
406     return true;
407 }
408 
ImportOpenDocument(LVStreamRef stream,ldomDocument * doc,LVDocViewCallback * progressCallback,CacheLoadingCallback * formatCallback)409 bool ImportOpenDocument( LVStreamRef stream, ldomDocument * doc, LVDocViewCallback * progressCallback, CacheLoadingCallback * formatCallback )
410 {
411     LVContainerRef arc = LVOpenArchieve( stream );
412     if ( arc.isNull() )
413         return false; // not a ZIP archive
414 
415     doc->setContainer(arc);
416 
417     //Read document metadata
418     LVStreamRef meta_stream = arc->OpenStream(U"meta.xml", LVOM_READ);
419     if ( meta_stream.isNull() )
420         return false;
421     ldomDocument * metaDoc = LVParseXMLStream( meta_stream );
422     if ( metaDoc ) {
423         CRPropRef doc_props = doc->getProps();
424 
425         lString32 author = metaDoc->textFromXPath( cs32("document-meta/meta/creator") );
426         lString32 title = metaDoc->textFromXPath( cs32("document-meta/meta/title") );
427         lString32 description = metaDoc->textFromXPath( cs32("document-meta/meta/description") );
428         doc_props->setString(DOC_PROP_TITLE, title);
429         doc_props->setString(DOC_PROP_AUTHORS, author );
430         doc_props->setString(DOC_PROP_DESCRIPTION, description );
431         delete metaDoc;
432     } else {
433         CRLog::error("Couldn't parse document meta data");
434     }
435 
436 #if BUILD_LITE!=1
437     if ( doc->openFromCache(formatCallback) ) {
438         if ( progressCallback ) {
439             progressCallback->OnLoadFileEnd( );
440         }
441         return true;
442     }
443 #endif
444 
445     ldomDocumentWriter writer(doc);
446     docXMLreader docReader(&writer);
447 
448     odtImportContext importContext(doc);
449     if( !parseStyles(&importContext) )
450         return false;
451 
452     LVStreamRef m_stream = arc->OpenStream(U"content.xml", LVOM_READ);
453     if ( m_stream.isNull() )
454         return false;
455 
456     importContext.startDocument(writer);
457 
458 #ifdef DOCX_FB2_DOM_STRUCTURE
459     //Two options when dealing with titles: (FB2|HTML)
460     odx_fb2TitleHandler titleHandler(&writer, DOCX_USE_CLASS_FOR_HEADING); //<section><title>..</title></section>
461 #else
462     odx_titleHandler titleHandler(&writer);  //<hx>..</hx>
463 #endif
464 
465     odt_documentHandler documentHandler(doc, &docReader, &writer, &titleHandler, &importContext);
466     docReader.setHandler(&documentHandler);
467 
468     LVXMLParser parser(m_stream, &docReader);
469 
470     if ( !parser.Parse() )
471         return false;
472 
473     importContext.endDocument(writer);
474     writer.OnStop();
475 
476     if ( progressCallback ) {
477         progressCallback->OnLoadFileEnd( );
478         doc->compact();
479         doc->dumpStatistics();
480     }
481 
482     return true;
483 }
484 
startParagraph()485 void odt_documentHandler::startParagraph()
486 {
487     if(m_inListItem) {
488         m_listItemHadContent = true;
489         m_writer->OnTagOpenNoAttr(U"", U"li");
490     }
491     m_writer->OnTagOpen(U"", U"p");
492     odx_Style* style = m_context->getStyle(m_StyleName);
493     if( style ) {
494         odx_pPr pPr;
495 
496         pPr.combineWith(style->get_pPr(m_context));
497         pPr.combineWith(m_context->get_pPrDefault());
498         lString32 css = pPr.getCss();
499         if( !css.empty() )
500             m_writer->OnAttribute(U"", U"style", css.c_str());
501     }
502     m_writer->OnTagBody();
503 #ifndef DOCX_FB2_DOM_STRUCTURE
504     if(m_state == odt_el_noteBody) {
505         m_writer->OnTagOpen(U"", U"sup");
506         m_writer->OnTagBody();
507         m_writer->OnText(m_noteRefText.c_str(), m_noteRefText.length(), 0);
508         m_writer->OnTagClose(U"", U"sup");
509     }
510 #endif
511     m_paragraphStarted = true;
512 }
513 
handleTagOpen(int tagId)514 ldomNode *odt_documentHandler::handleTagOpen(int tagId)
515 {
516     bool elementHandled = false;
517     switch(tagId) {
518     case odt_el_automaticStyles:
519         m_stylesHandler.start();
520         elementHandled = true;
521         break;
522     case odt_el_note:
523         m_isEndNote = false;
524         m_writer->OnTagOpen(U"", U"a");
525         break;
526     case odt_el_body:
527         m_body = m_titleHandler->onBodyStart();
528         m_writer->OnTagBody();
529         break;
530     case odt_el_h:
531         if( odt_el_p == m_state)
532             checkParagraphStart();
533         m_StyleName.clear();
534         m_outlineLevel = 0;
535         break;
536     case odt_el_p:
537 #ifndef DOCX_FB2_DOM_STRUCTURE
538         if( odt_el_p == m_state || odt_el_noteBody == m_state)
539             checkParagraphStart();
540         m_paragraphStarted = odt_el_noteBody == m_state;
541 #else
542         if( odt_el_p == m_state)
543             checkParagraphStart();
544         m_paragraphStarted = false;
545 #endif
546         m_StyleName.clear();
547         break;
548     case odt_el_span:
549         m_spanStyleName.clear();
550         break;
551     case odt_el_list:
552         if( odt_el_p == m_state)
553             checkParagraphStart();
554         m_StyleName.clear();
555         m_writer->OnTagOpen(U"", U"ol");
556         if (isInList())
557             m_listItems.add(m_listItemHadContent);
558         break;
559     case odt_el_listItem:
560         m_inListItem = true;
561         m_listItemHadContent = false;
562         break;
563     case odt_el_tab:
564     case odt_el_s:
565         if( odt_el_p == m_state)
566             checkParagraphStart();
567         m_writer->OnText(U" ", 1, TXTFLG_PRE);
568         break;
569     case odt_el_noteBody:
570         m_saveWriter = m_writer;
571         if(m_isEndNote) {
572             m_writer = &m_endNotesWriter;
573             if(!m_endNotes)
574                 m_endNotes = startNotes(U"comments");
575         } else {
576             m_writer = &m_footNotesWriter;
577             if(!m_footNotes)
578                 m_footNotes = startNotes(U"notes");;
579         }
580         m_writer->OnTagOpen(U"", U"section");
581         m_writer->OnAttribute(U"", U"id", m_noteId.c_str());
582         m_writer->OnAttribute(U"", U"role", m_isEndNote ? U"doc-rearnote" : U"doc-footnote");
583         m_writer->OnTagBody();
584 #ifdef DOCX_FB2_DOM_STRUCTURE
585         m_writer->OnTagOpenNoAttr(U"", U"title");
586         m_writer->OnTagOpenNoAttr(U"", U"p");
587         m_writer->OnText(m_noteRefText.c_str(), m_noteRefText.length(), 0);
588         m_writer->OnTagClose(U"", U"p");
589         m_writer->OnTagClose(U"", U"title");
590 #else
591         m_paragraphStarted = false;
592 #endif
593         break;
594     case odt_el_table:
595         m_inTable = true;
596     default:
597         if( odt_elements_mapping[tagId].name ) {
598             if( odt_el_p == m_state)
599                 checkParagraphStart();
600             m_writer->OnTagOpen(U"", odt_elements_mapping[tagId].name);
601         }
602         break;
603     }
604     if( !elementHandled ) {
605         m_state = tagId;
606         m_levels.add(tagId);
607     }
608     return NULL;
609 }
610 
handleAttribute(const lChar32 * attrname,const lChar32 * attrValue)611 void odt_documentHandler::handleAttribute(const lChar32 *attrname, const lChar32 *attrValue)
612 {
613     switch (m_state) {
614     case odt_el_bookmark:
615     case odt_el_bookmarkStart:
616     case odt_el_referenceMark:
617     case odt_el_referenceMarkStart:
618         if(!lStr_cmp(attrname, "name") ) {
619             m_writer->OnAttribute(U"", U"id", attrValue);
620         }
621         break;
622     case odt_el_bookmarkRef:
623     case odt_el_noteRef:
624     case odt_el_referenceRef:
625         if(!lStr_cmp(attrname, "ref-name") ) {
626             lString32 target = cs32("#") + lString32(attrValue);
627             m_writer->OnAttribute(U"", U"href", target.c_str());
628         }
629         break;
630     case odt_el_h:
631         if(!lStr_cmp(attrname, "outline-level") ) {
632             lString32 value = attrValue;
633             int tmp;
634 
635             if(value.atoi(tmp))
636                 m_outlineLevel = tmp - 1;
637             break;
638         }
639         if( !lStr_cmp(attrname, "style-name") ) {
640             m_StyleName = attrValue;
641         }
642         break;
643     case odt_el_note:
644         if(!lStr_cmp(attrname, "note-class")) {
645             if(!lStr_cmp(attrValue, "endnote")) {
646                 m_writer->OnAttribute(U"", U"type", U"comment");
647                 m_isEndNote = true;
648             } else if(!lStr_cmp(attrValue, "footnote")) {
649                 m_writer->OnAttribute(U"", U"type", U"note");
650             }
651             m_writer->OnAttribute(U"", U"role", U"doc-noteref");
652         } else if(!lStr_cmp(attrname, "id")) {
653             m_noteId = lString32(attrValue);
654             lString32 target = cs32("#") + m_noteId;
655             m_writer->OnAttribute(U"", U"href", target.c_str());
656         }
657         break;
658     case odt_el_tableCell:
659         if(!lStr_cmp(attrname, "number-columns-spanned"))
660             m_writer->OnAttribute(U"", U"colspan", attrValue);
661         else if(!lStr_cmp(attrname, "number-rows-spanned"))
662             m_writer->OnAttribute(U"", U"rowspan", attrValue);
663         break;
664     case odt_el_a:
665     case odt_el_image:
666         if( !lStr_cmp(attrname, "href") )
667             m_writer->OnAttribute(U"", attrname, attrValue);
668         break;
669     case odt_el_p:
670     case odt_el_list:
671     case odt_el_span:
672         if( !lStr_cmp(attrname, "style-name") ) {
673             if( m_state == odt_el_span)
674                 m_spanStyleName = attrValue;
675             else
676                 m_StyleName = attrValue;
677         }
678         break;
679     default:
680         break;
681     }
682 }
683 
handleTagBody()684 void odt_documentHandler::handleTagBody()
685 {
686     switch(m_state) {
687     case odt_el_span:
688     case odt_el_p:
689         break;
690     case odt_el_list:
691         {
692             css_list_style_type_t listType = css_lst_none;
693             css_length_t levelStart(css_val_unspecified, 0);
694             odt_ListStyle* listStyle = m_context->getListStyle(m_StyleName);
695             if( !listStyle && !m_ListLevels.empty() ) {
696                 listStyle = m_ListLevels.get( m_ListLevels.length() -1);
697             }
698             m_ListLevels.add(listStyle);
699             if(listStyle) {
700                 odt_ListLevelStyle* levelStyle = listStyle->getLevel(m_ListLevels.length());
701                 if(levelStyle) {
702                     listType = levelStyle->getLevelType();
703                     levelStart = levelStyle->getLevelStart();
704                 }
705             }
706             m_writer->OnAttribute(U"", U"style", m_context->getListStyleCss(listType).c_str());
707             if(levelStart.type != css_val_unspecified)
708                 m_writer->OnAttribute(U"", U"start", lString32::itoa(levelStart.value).c_str());
709             m_writer->OnTagBody();
710         }
711         break;
712     case odt_el_h:
713         if(m_inListItem) {
714             m_listItemHadContent = true;
715             m_writer->OnTagOpenNoAttr(U"", U"li");
716         }
717         m_titleHandler->onTitleStart(m_outlineLevel + 1, m_inTable || m_inListItem);
718         m_writer->OnTagBody();
719         break;
720     default:
721         if( odt_elements_mapping[m_state].name )
722             m_writer->OnTagBody();
723         break;
724     }
725 }
726 
handleTagClose(const lChar32 * nsname,const lChar32 * tagname)727 void odt_documentHandler::handleTagClose(const lChar32 *nsname, const lChar32 *tagname)
728 {
729     switch(m_state) {
730     case odt_el_body:
731         m_titleHandler->onBodyEnd();
732         m_writer->OnTagClose(nsname, tagname);
733         if(m_footNotes)
734             finishNotes(m_footNotes, m_footNotesWriter);
735         if(m_endNotes)
736             finishNotes(m_endNotes, m_endNotesWriter);
737         break;
738     case odt_el_h:
739         closeStyleTags(m_writer);
740         m_titleHandler->onTitleEnd();
741         break;
742     case odt_el_p:
743         if( !m_paragraphStarted ) {
744             if( m_inListItem) {
745                 m_writer->OnTagOpen(U"", U"li");
746                 m_writer->OnAttribute(U"", U"style", U"display:none");
747                 m_writer->OnTagBody();
748                 m_writer->OnTagClose(U"", U"li");
749             } else
750                 m_writer->OnTagOpenNoAttr(U"", U"p");
751             m_paragraphStarted = true;
752         } else
753             closeStyleTags(m_writer);
754         m_writer->OnTagClose(nsname, tagname);
755         break;
756     case odt_el_list:
757         m_ListLevels.remove(m_ListLevels.length() - 1);
758         m_writer->OnTagClose(U"", U"ol");
759         break;
760     case odt_el_listItem:
761         if(m_listItemHadContent)
762             m_writer->OnTagClose(U"", U"li");
763         if(!m_listItems.empty()) {
764             m_listItemHadContent = m_listItems[m_listItems.length() - 1];
765             m_listItems.erase(m_listItems.length() - 1, 1);
766         }
767         m_inListItem = false;
768         break;
769     case odt_el_noteBody:
770         m_writer->OnTagClose(U"", U"section");
771         m_writer = m_saveWriter;
772         break;
773     case odt_el_noteCitation:
774         m_writer->OnTagClose(U"", U"a");
775         break;
776     case odt_el_table:
777         m_inTable = false;
778     default:
779         if( odt_elements_mapping[m_state].name )
780             m_writer->OnTagClose(U"", odt_elements_mapping[m_state].name);
781         break;
782     }
783     m_levels.erase(m_levels.length() - 1, 1);
784     if( !m_levels.empty() )
785         m_state = m_levels[m_levels.length() - 1];
786     else
787         m_state = odt_el_NULL;
788 }
789 
handleText(const lChar32 * text,int len,lUInt32 flags)790 void odt_documentHandler::handleText(const lChar32 *text, int len, lUInt32 flags)
791 {
792     odx_Style* style;
793 
794     switch(m_state) {
795     case odt_el_h:
796     case odt_el_p:
797     case odt_el_span:
798         style = m_context->getStyle(m_state == odt_el_span ? m_spanStyleName : m_StyleName);
799         if(style) {
800             odx_rPr rPr;
801 
802             rPr.combineWith(style->get_rPr(m_context));
803             rPr.combineWith(m_context->get_rPrDefault());
804             if( rPr.isHidden() )
805                 break;
806             checkParagraphStart();
807             closeStyleTags(&rPr, m_writer);
808             openStyleTags(&rPr, m_writer);
809         } else
810             checkParagraphStart();
811         m_writer->OnText(text, len, flags);
812         break;
813     case odt_el_noteCitation:
814         m_noteRefText = text;
815         m_writer->OnTagBody();
816     case odt_el_bookmarkRef:
817     case odt_el_noteRef:
818     case odt_el_referenceRef:
819     case odt_el_a:
820         m_writer->OnText(text, len, flags);
821         break;
822     default:
823         break;
824     }
825 }
826 
reset()827 void odt_documentHandler::reset()
828 {
829     m_levels.clear();
830     m_ListLevels.clear();
831     m_listItems.clear();
832     m_state = odt_el_NULL;
833     m_outlineLevel = 0;
834     m_inTable = false;
835     m_inListItem = false;
836     m_listItemHadContent = false;
837     m_paragraphStarted = false;
838 }
839 
addListStyle(odt_ListStyleRef listStyle)840 void odtImportContext::addListStyle(odt_ListStyleRef listStyle)
841 {
842     if( !listStyle.isNull())
843         m_ListStyles.set(listStyle->getId(), listStyle);
844 }
845 
openFile(const lChar32 * const fileName)846 LVStreamRef odtImportContext::openFile(const lChar32 * const fileName)
847 {
848     LVContainerRef container = m_doc->getContainer();
849     if( !container.isNull() )
850         return container->OpenStream(fileName, LVOM_READ);
851     return LVStreamRef();
852 }
853 
handleTagOpen(int tagId)854 ldomNode *odt_stylesHandler::handleTagOpen(int tagId)
855 {
856     switch(tagId) {
857     case odt_el_defaultStyle:
858         m_style = NULL;
859         break;
860     case odt_el_paragraphProperties:
861         m_pPr = m_style ? m_style->get_pPrPointer() : m_context->get_pPrDefault();
862         break;
863     case odt_el_textProperties:
864         m_rPr = m_style ? m_style->get_rPrPointer() : m_context->get_rPrDefault();
865         break;
866     case odt_el_style:
867         m_styleRef = odx_StyleRef( new odx_Style );
868         m_style = m_styleRef.get();
869     case odt_el_listStyle:
870         m_ListStyleRef = odt_ListStyleRef( new odt_ListStyle );
871         m_ListStyle = m_ListStyleRef.get();
872         break;
873     case odt_el_listLevelStyleBullet:
874     case odt_el_listLevelStyleNumber:
875         m_ListLevelStyleRef = odt_ListLevelStyleRef( new odt_ListLevelStyle );
876         m_ListLevelStyle = m_ListLevelStyleRef.get();
877         break;
878     default:
879         break;
880     }
881     m_state = tagId;
882     m_levels.add(tagId);
883     return NULL;
884 }
885 
handleAttribute(const lChar32 * attrname,const lChar32 * attrvalue)886 void odt_stylesHandler::handleAttribute(const lChar32 *attrname, const lChar32 *attrvalue)
887 {
888     switch(m_state) {
889     case odt_el_style:
890         if( !lStr_cmp(attrname, "name") ) {
891             m_style->setId(attrvalue);
892         } else if( !lStr_cmp(attrname, "display-name") ) {
893             m_style->setName(attrvalue);
894         } else if( !lStr_cmp(attrname, "family") ) {
895             int n = parse_name(styleFamily_attr_values, attrvalue);
896             if(n != -1)
897                 m_style->setStyleType((odx_style_type)n);
898         } else if( !lStr_cmp(attrname, "parent-style-name") ) {
899             m_style->setBasedOn(attrvalue);
900         }
901         break;
902     case odt_el_listStyle:
903         if( !lStr_cmp(attrname, "name") )
904             m_ListStyle->setId(attrvalue);
905         break;
906     case odt_el_listLevelStyleNumber:
907         if( !lStr_cmp(attrname, "num-format") ) {
908             lString32 format(attrvalue);
909 
910             if( format.length() == 1) {
911                 switch(attrvalue[0]) {
912                 case '1':
913                     m_ListLevelStyle->setLevelType(css_lst_decimal);
914                     break;
915                 case 'a':
916                     m_ListLevelStyle->setLevelType(css_lst_lower_alpha);
917                     break;
918                 case 'A':
919                     m_ListLevelStyle->setLevelType(css_lst_upper_alpha);
920                     break;
921                 case 'i':
922                     m_ListLevelStyle->setLevelType(css_lst_lower_roman);
923                     break;
924                 case 'I':
925                     m_ListLevelStyle->setLevelType(css_lst_upper_roman);
926                     break;
927                 default:
928                     m_ListLevelStyle->setLevelType(css_lst_none);
929                     break;
930                 }
931             } else if( format.empty() )
932                 m_ListLevelStyle->setLevelType(css_lst_none);
933             break;
934         }
935         if( !lStr_cmp(attrname, "start-value") ) {
936             int startValue;
937 
938             if( lString32(attrvalue).atoi( startValue) )
939                 m_ListLevelStyle->setLevelStart( startValue );
940             break;
941         }
942     case odt_el_listLevelStyleBullet:
943         if( !lStr_cmp(attrname, "level") )
944             m_ListLevelStyle->setLevel(attrvalue);
945         break;
946     case odt_el_paragraphProperties:
947         if( !lStr_cmp(attrname, "break-before") ) {
948             m_pPr->setPageBreakBefore( !lStr_cmp(attrvalue, "page") );
949         } else if( !lStr_cmp(attrname, "text-align") ) {
950             int n = parse_name(odt_textAlign_attr_values, attrvalue);
951             if(n != -1)
952                 m_pPr->setTextAlign((css_text_align_t)n);
953         } else if( !lStr_cmp(attrname, "keep-with-next") ) {
954             m_pPr->setKeepNext( !lStr_cmp(attrvalue, "always") );
955         }
956         break;
957     case odt_el_textProperties:
958         if( NULL == m_style && !lStr_cmp(attrname, "language") ) {
959             m_context->setLanguage(attrvalue);
960         } else if( !lStr_cmp(attrname, "font-style") ) {
961             m_rPr->setItalic( lStr_cmp(attrvalue, "normal") !=0 );
962         } else if( !lStr_cmp(attrname, "font-weight") ) {
963             int n = parse_name(odt_fontWeigth_attr_values, attrvalue);
964             if( n != -1 )
965                 m_rPr->setBold( n >= 600 );
966         } else if( !lStr_cmp(attrname, "text-underline-style") ) {
967             m_rPr->setUnderline( lStr_cmp( attrvalue, "none") !=0 );
968         } else if( !lStr_cmp(attrname, "text-line-through-type") ) {
969             m_rPr->setStrikeThrough( lStr_cmp( attrvalue, "none") !=0 );
970         } else if( !lStr_cmp(attrname, "text-position") ) {
971             lString32 val = attrvalue;
972 
973             if( val.startsWith(U"super") ) {
974                 m_rPr->setVertAlign(css_va_super);
975             } else if( val.startsWith(U"sub") ) {
976                 m_rPr->setVertAlign(css_va_sub);
977             }
978         }
979         break;
980     default:
981         break;
982     }
983 }
984 
handleTagClose(const lChar32 * nsname,const lChar32 * tagname)985 void odt_stylesHandler::handleTagClose(const lChar32 *nsname, const lChar32 *tagname)
986 {
987     CR_UNUSED2(nsname, tagname);
988 
989     switch(m_state) {
990     case odt_el_listStyle:
991         m_context->addListStyle(m_ListStyleRef);
992         break;
993     case odt_el_listLevelStyleBullet:
994     case odt_el_listLevelStyleNumber:
995         m_ListStyle->addLevel(m_ListLevelStyleRef);
996         break;
997     case odt_el_style:
998         if(m_style && m_style->isValid()) {
999             m_context->addStyle(m_styleRef);
1000         }
1001     default:
1002         break;
1003     }
1004     if( !m_levels.empty() ) {
1005         m_levels.erase(m_levels.length() - 1, 1);
1006         if(! m_levels.empty() )
1007             m_state = m_levels[m_levels.length() - 1];
1008         else
1009             m_state = m_element;
1010     } else
1011         stop();
1012 }
1013 
addLevel(odt_ListLevelStyleRef listLevel)1014 void odt_ListStyle::addLevel(odt_ListLevelStyleRef listLevel)
1015 {
1016     if( !listLevel.isNull() )
1017         m_levels.set( listLevel->getLevel(), listLevel );
1018 }
1019