1 /* AbiWord
2 * Copyright (C) 1998 AbiSource, Inc.
3 * Copyright (C) 2000-2002 Dom Lachowicz
4 * Copyright (C) 2002 Screetch
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "ut_string.h"
26 #include "ut_std_string.h"
27 #include "ut_bytebuf.h"
28 #include "ut_base64.h"
29 #include "ut_locale.h"
30 #include "ut_units.h"
31 #include "pt_Types.h"
32 #include "pd_Document.h"
33 #include "ie_impexp_DocBook.h"
34 #include "ie_exp_DocBook.h"
35 #include "pp_AttrProp.h"
36 #include "px_ChangeRecord.h"
37 #include "px_CR_Object.h"
38 #include "px_CR_Span.h"
39 #include "px_CR_Strux.h"
40 #include "xap_App.h"
41 #include "xap_EncodingManager.h"
42 #include "ap_Strings.h"
43 #include "fd_Field.h"
44
45 #include "ut_path.h"
46 #include "ut_string_class.h"
47
48 /*****************************************************************/
49 /*****************************************************************/
50
IE_Exp_DocBook_Sniffer(const char * _name)51 IE_Exp_DocBook_Sniffer::IE_Exp_DocBook_Sniffer (const char * _name) :
52 IE_ExpSniffer(_name)
53 {
54 //
55 }
56
recognizeSuffix(const char * szSuffix)57 bool IE_Exp_DocBook_Sniffer::recognizeSuffix(const char * szSuffix)
58 {
59 return (!g_ascii_strcasecmp(szSuffix,".dbk") ||!g_ascii_strcasecmp(szSuffix,".xml"));
60 }
61
constructExporter(PD_Document * pDocument,IE_Exp ** ppie)62 UT_Error IE_Exp_DocBook_Sniffer::constructExporter(PD_Document * pDocument,
63 IE_Exp ** ppie)
64 {
65 IE_Exp_DocBook * p = new IE_Exp_DocBook(pDocument);
66 *ppie = p;
67 return UT_OK;
68 }
69
getDlgLabels(const char ** pszDesc,const char ** pszSuffixList,IEFileType * ft)70 bool IE_Exp_DocBook_Sniffer::getDlgLabels(const char ** pszDesc,
71 const char ** pszSuffixList,
72 IEFileType * ft)
73 {
74 *pszDesc = "DocBook (.dbk, .xml)";
75 *pszSuffixList = "*.dbk; *.xml";
76 *ft = getFileType();
77 return true;
78 }
79
80 /*****************************************************************/
81 /*****************************************************************/
82
IE_Exp_DocBook(PD_Document * pDocument)83 IE_Exp_DocBook::IE_Exp_DocBook(PD_Document * pDocument)
84 : IE_Exp(pDocument)
85 {
86 m_error = 0;
87 s_align = 0;
88 m_pListener = NULL;
89 }
90
~IE_Exp_DocBook()91 IE_Exp_DocBook::~IE_Exp_DocBook()
92 {
93 }
94
indent(void)95 int IE_Exp_DocBook :: indent (void)
96 {
97 return ++s_align;
98 }
99
unindent(void)100 int IE_Exp_DocBook :: unindent (void)
101 {
102 if (--s_align < 0)
103 {
104 s_align = 0;
105 UT_DEBUGMSG(("DocBook: trying to unindent at min indent.\n"));
106 }
107 return s_align;
108 }
109
iwrite(const char * txt)110 void IE_Exp_DocBook :: iwrite (const char *txt)
111 {
112 if (s_align)
113 {
114 char *tmpIndent = new char [s_align + 1];
115 memset (tmpIndent, '\t', s_align);
116 tmpIndent [s_align] = '\0';
117
118 IE_Exp :: write (tmpIndent);
119 DELETEPV(tmpIndent);
120 }
121
122 IE_Exp :: write (txt);
123 }
124
writeln(const char * txt)125 void IE_Exp_DocBook :: writeln (const char *txt)
126 {
127 iwrite (txt);
128 IE_Exp :: write ("\n");
129 }
130
131 /*****************************************************************/
132 /*****************************************************************/
133
134 /*!
135 removes the suffix from a string by searching backwards for the specified
136 character delimiter. If the delimiter is not found, a copy of the original
137 string is returned
138
139 eg. _stripSuffix("/home/user/file.png, '.') returns "/home/user/file"
140 _stripSuffix("/home/user/foo_bar, '_') returns /home/user/foo
141 _stripSuffix("/home/user/file.png, '_') returns /home/user/file.png"
142 TODO: put this in UT_String somehow, it came from ie_exp_HTML.
143 */
_stripSuffix(const char * from,char delimiter)144 static char *_stripSuffix(const char* from, char delimiter)
145 {
146 char * fremove_s = (char *)g_try_malloc(strlen(from)+1);
147 strcpy(fremove_s, from);
148
149 char * p = fremove_s + strlen(fremove_s);
150 while ((p >= fremove_s) && (*p != delimiter))
151 p--;
152
153 if (p >= fremove_s)
154 *p = '\0';
155
156 return fremove_s;
157 }
158
_stripSuffix(const UT_UTF8String & from,char delimiter)159 static char * _stripSuffix(const UT_UTF8String & from, char delimiter)
160 {
161 return _stripSuffix(from.utf8_str(), delimiter);
162 }
163
164 /*****************************************************************/
165 /*****************************************************************/
166
167 #define BT_NORMAL 1
168 #define BT_PLAINTEXT 2
169
_initFile(void)170 bool s_DocBook_Listener::_initFile(void)
171 {
172 // write out the doctype descriptor
173 m_pie->writeln("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
174 m_pie->writeln("<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"");
175 m_pie->writeln("\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">\n");
176 m_pie->writeln("<!-- ================================================================================ -->");
177 m_pie->writeln("<!-- This DocBook file was created by AbiWord. -->");
178 m_pie->writeln("<!-- AbiWord is a free, Open Source word processor. -->");
179 m_pie->writeln("<!-- You may obtain more information about AbiWord at http://www.abisource.com -->");
180 m_pie->writeln("<!-- ================================================================================ -->");
181 m_pie->write("\n");
182 _handleDocument();
183 _handleMetaData();
184
185 return true;
186 }
187
_closeFile(void)188 void s_DocBook_Listener::_closeFile(void)
189 {
190 if(m_bInTitle && !m_bInSection) //in case the file contains a lone chapter heading
191 {
192 _closeChapterTitle();
193 _tagOpenClose("section",false);
194 _tagOpenClose("para",false);
195 }
196 _closeChapter(); //handles all of the section closing
197 _handleDataItems();
198 _tagClose(TT_DOCUMENT,"book");
199 }
200
_tagClose(UT_uint32 tagID,const UT_UTF8String & content,bool newline,bool indent,bool decrease)201 void s_DocBook_Listener::_tagClose(UT_uint32 tagID, const UT_UTF8String & content, bool newline, bool indent, bool decrease)
202 {
203 UT_uint32 i = 0;
204
205 if(decrease)
206 m_pie->unindent();
207
208 if(indent)
209 m_pie->iwrite("</");
210 else
211 m_pie->write("</");
212
213 m_pie->write(content.utf8_str());
214 m_pie->write(">");
215
216 if(newline)
217 m_pie->write("\n");
218
219 m_utnsTagStack.pop((UT_sint32*)&i);
220 m_iLastClosed = i;
221 xxx_UT_DEBUGMSG(("Popping %d off of stack\n",i));
222
223 if(i != tagID)
224 {
225 UT_DEBUGMSG(("DocBook export: possible mismatched tag. Requested: %d, Popped: %d\n",tagID,i));
226 }
227 }
228
_tagOpen(UT_uint32 tagID,const UT_UTF8String & content,bool newline,bool indent,bool increase)229 void s_DocBook_Listener::_tagOpen(UT_uint32 tagID, const UT_UTF8String & content, bool newline, bool indent, bool increase)
230 {
231 if(indent)
232 m_pie->iwrite("<");
233 else
234 m_pie->write("<");
235
236 m_pie->write(content.utf8_str());
237 m_pie->write(">");
238
239 if(newline)
240 m_pie->write("\n");
241
242 if(increase)
243 m_pie->indent();
244
245 m_utnsTagStack.push(tagID);
246 xxx_UT_DEBUGMSG(("Pushing %d onto stack\n",tagID));
247 }
248
_tagOpenClose(const UT_UTF8String & content,bool suppress,bool newline,bool indent)249 void s_DocBook_Listener::_tagOpenClose(const UT_UTF8String & content, bool suppress, bool newline, bool indent)
250 {
251 if(indent)
252 m_pie->iwrite("<");
253 else
254 m_pie->write("<");
255
256 m_pie->write(content.utf8_str());
257
258 if(suppress)
259 m_pie->write("/>");
260 else
261 {
262 m_pie->write("></");
263 m_pie->write(content.utf8_str());
264 m_pie->write(">");
265 }
266
267 if(newline)
268 m_pie->write("\n");
269 }
270
_tagTop(void)271 UT_uint32 s_DocBook_Listener::_tagTop(void)
272 {
273 UT_sint32 i = 0;
274
275 if (m_utnsTagStack.viewTop (i))
276 return (UT_uint32)i;
277 return 0;
278 }
279
_closeSection(int sub)280 void s_DocBook_Listener :: _closeSection(int sub)
281 {
282 _closeParagraph(); // this also prevents section titles from being left open, so keep it above the return
283
284 if(_tagTop() == TT_FOOTNOTE) // triggered by the .doc importer sometimes
285 {
286 _tagClose(TT_FOOTNOTE,"footnote",false,false,false);
287 m_bInNote = false;
288 _closeParagraph();
289 }
290
291 if((!m_bInSection) || (sub > m_iSectionDepth) || (m_bInTable))
292 return;
293
294 while((sub < m_iSectionDepth) && (m_iSectionDepth > 0))
295 {
296 if(_tagTop() == TT_TITLE)
297 _closeSectionTitle();
298 if(m_iLastClosed == TT_TITLE)
299 _tagOpenClose("para",false); //we can't have empty sections
300
301 if(_tagTop() != TT_SECTION)
302 {
303 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
304 }
305
306 _tagClose(TT_SECTION,"section");
307 m_iSectionDepth--;
308 }
309
310 if(m_iSectionDepth == 0)
311 m_bInSection = false;
312 if(m_bInHdrFtr)
313 m_bInHdrFtr = false;
314 m_sLastStyle = "";
315 }
316
_closeSectionTitle()317 void s_DocBook_Listener :: _closeSectionTitle()
318 {
319 if(!m_bInTitle)
320 return;
321
322 if(_tagTop() != TT_TITLE)
323 {
324 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
325 }
326
327 _tagClose(TT_TITLE,"title",true,false);
328 m_bInTitle = false;
329 }
330
331
_closeParagraph(void)332 void s_DocBook_Listener :: _closeParagraph(void)
333 {
334 if((_tagTop() == TT_FOOTNOTE) || (!m_bInParagraph))
335 return;
336
337 _closeSpan();
338
339 if(_tagTop() == TT_LINK) // don't let links span paragraphs
340 _tagClose(TT_LINK,"link",false,false,false);
341 else if(_tagTop() == TT_ULINK)
342 _tagClose(TT_ULINK,"ulink",false,false,false);
343
344 if((m_iBlockType == BT_PLAINTEXT) || (_tagTop() == TT_PLAINTEXT))
345 {
346 m_iBlockType = BT_NORMAL;
347 _tagClose(TT_PLAINTEXT,"literallayout",true,false,false);
348 }
349 else if((m_iBlockType == BT_NORMAL) || (_tagTop() == TT_BLOCK))
350 {
351 bool deindent = true;
352 if(m_bInTable)
353 deindent = false;
354 else if(m_bInNote)
355 deindent = false;
356
357 _tagClose(TT_BLOCK,"para",((!m_bInTable) && (!m_bInNote)),false,deindent);
358 }
359 else
360 {
361 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
362 }
363
364 if(!m_bInNote)
365 m_bInParagraph = false;
366 }
367
_closeSpan(void)368 void s_DocBook_Listener :: _closeSpan(void)
369 {
370 if(!m_bInSpan)
371 return;
372
373 const PP_AttrProp * pAP = m_pAP_Span;
374
375 if (pAP)
376 {
377 const gchar * szValue = 0;
378
379 if (pAP->getProperty(static_cast<const gchar *>("text-position"), szValue))
380 {
381 if (!strcmp("superscript", szValue))
382 {
383 _tagClose(TT_SUPERSCRIPT,"superscript",false,false,false);
384 }
385 else if (!strcmp("subscript", szValue))
386 {
387 _tagClose(TT_SUBSCRIPT,"subscript",false,false,false);
388 }
389 }
390
391 if ((pAP->getProperty(static_cast<const gchar *>("font-style"), szValue)) && !strcmp(szValue, "italic"))
392 {
393 _tagClose(TT_EMPHASIS,"emphasis",false,false,false);
394 }
395
396 _tagClose(TT_PHRASE,"phrase",false,false,false);
397 m_pAP_Span = NULL;
398 }
399
400 m_bInSpan = false;
401 }
402
_closeChapter(void)403 void s_DocBook_Listener :: _closeChapter (void)
404 {
405 if(!m_bInChapter)
406 return;
407
408 if(m_bInTable) // bad .doc import can lead to <section>s being closed in <cell>s; try to export valid XML regardless
409 {
410 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
411 _closeTable();
412 }
413
414 _closeSection(0); //close any open sections
415 _tagClose(TT_CHAPTER,"chapter");
416 m_bInChapter = false;
417 }
418
_closeChapterTitle(void)419 void s_DocBook_Listener :: _closeChapterTitle (void)
420 {
421 if(!m_bInChapter || !m_bInTitle)
422 return;
423
424 if(_tagTop() != TT_TITLE)
425 {
426 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
427 }
428
429 _tagClose(TT_TITLE,"title",true,false);
430 m_bInTitle = false;
431 }
432
_openChapter(PT_AttrPropIndex api)433 void s_DocBook_Listener :: _openChapter (PT_AttrPropIndex api)
434 {
435 _closeChapter(); // close any open chapters (and sections)
436
437 if(_tagTop() != TT_DOCUMENT)
438 {
439 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
440 }
441
442 _tagOpen(TT_CHAPTER,"chapter");
443 m_bInChapter = true;
444 _openChapterTitle(api);
445 }
446
_openChapterTitle(PT_AttrPropIndex)447 void s_DocBook_Listener :: _openChapterTitle (PT_AttrPropIndex /*api*/)
448 {
449 if(_tagTop() == TT_CHAPTER)
450 {
451 _tagOpen(TT_TITLE,"title",false);
452 m_bInTitle = true;
453 }
454 else
455 {
456 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
457 }
458 }
459
_openList(PT_AttrPropIndex)460 void s_DocBook_Listener :: _openList (PT_AttrPropIndex /*api*/)
461 {
462 /*
463 if(_tagTop() != TT_ITEMIZEDLIST)
464 {
465 m_pie->write("\n");
466 _tagOpen(TT_ITEMIZEDLIST,"itemizedlist");
467 }
468
469 _tagOpen(TT_LISTITEM,"listitem");
470 */
471 }
472
_openBlock(bool indent)473 void s_DocBook_Listener :: _openBlock(bool indent)
474 {
475 if(m_bInTitle)
476 return;
477
478 UT_UTF8String buf = "para";
479
480 _closeParagraph();
481 _tagOpen(TT_BLOCK,buf,false,indent,indent);
482 m_bInParagraph = true;
483 m_iBlockType = BT_NORMAL;
484 }
485
_openPlainBlock()486 void s_DocBook_Listener :: _openPlainBlock()
487 {
488 if(m_bInTitle)
489 return;
490
491 UT_UTF8String buf = "literallayout";
492
493 _closeParagraph();
494 _tagOpen(TT_PLAINTEXT,buf,true,false,false);
495 m_bInParagraph = true;
496 m_iBlockType = BT_PLAINTEXT;
497 }
498
_openParagraph(PT_AttrPropIndex api)499 void s_DocBook_Listener :: _openParagraph(PT_AttrPropIndex api)
500 {
501 if((m_iNestedTable == 0) || (m_iNestedTable == 2))
502 return; // we can't write before/after a nested table
503
504 if(m_bInTable && (_tagTop() == TT_ROW)) //no <entry>, can happen on bad .doc import
505 {
506 _openCell();
507 }
508
509 const PP_AttrProp * pAP = NULL;
510 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP), indent = false;
511 UT_UTF8String buf("");
512
513 if (bHaveProp && pAP)
514 {
515 const gchar * szValue = 0;
516
517 if (pAP->getAttribute(static_cast<const gchar *>(PT_STYLE_ATTRIBUTE_NAME), szValue))
518 {
519 if((!strcmp(szValue, "Heading 1")) || (!strcmp(szValue, "Numbered Heading 1")))
520 {
521 // <p style="Heading 1"> ...
522 _closeChapterTitle();
523
524 if((!_inSectionStrux()) && !m_bInTitle)
525 _openSection(api, 1, szValue);
526 else if(!m_bInTitle)
527 {
528 indent = _decideIndent();
529 _openBlock(indent);
530 }
531 return;
532 }
533 else if((!strcmp(szValue, "Heading 2")) || (!strcmp(szValue, "Numbered Heading 2")))
534 {
535 // <p style="Heading 2"> ...
536 _closeChapterTitle();
537
538 if((!_inSectionStrux()) && !m_bInTitle)
539 {
540 _openSection(api, !strcmp(szValue, m_sParentStyle.utf8_str()) ? m_iSectionDepth : 2, szValue);
541 m_sParentStyle = szValue; //don't coalesce runs inside of a title
542 }
543 else if(!m_bInTitle)
544 {
545 indent = _decideIndent();
546 _openBlock(indent);
547 m_sParentStyle = szValue;
548 }
549 return;
550 }
551 else if((!strcmp(szValue, "Heading 3")) || (!strcmp(szValue, "Numbered Heading 3")))
552 {
553 // <p style="Heading 3"> ...
554 _closeChapterTitle();
555
556 if(!_inSectionStrux() && !m_bInTitle)
557 {
558 _openSection(api, !strcmp(szValue, m_sParentStyle.utf8_str()) ? m_iSectionDepth : 3, szValue);
559 m_sParentStyle = szValue;
560 }
561 else
562 {
563 indent = _decideIndent();
564 _openBlock(indent);
565 m_sParentStyle = szValue;
566 }
567 return;
568 }
569 else if(!strcmp(szValue, "Heading 4"))
570 {
571 // <p style="Heading 4"> ...
572 _closeChapterTitle();
573
574 if(!_inSectionStrux() && !m_bInTitle)
575 {
576 _openSection(api, !strcmp(szValue, m_sParentStyle.utf8_str()) ? m_iSectionDepth : 4, szValue);
577 m_sParentStyle = szValue;
578 }
579 else
580 {
581 indent = _decideIndent();
582 _openBlock(indent);
583 m_sParentStyle = szValue;
584 }
585 return;
586 }
587 else if (!strcmp (szValue, "Chapter Heading"))
588 {
589 if(!_inSectionStrux() && !m_bInTitle)
590 {
591 _openChapter(api);
592 m_sParentStyle = szValue;
593 }
594 else
595 {
596 indent = _decideIndent();
597 _openBlock(indent);
598 m_sParentStyle = szValue;
599 }
600 return;
601 }
602 else if (!strcmp (szValue, "Section Heading"))
603 {
604 _closeChapterTitle();
605
606 if(!_inSectionStrux() && !m_bInTitle)
607 {
608 _openSection(api, 1, szValue);
609 m_sParentStyle = szValue;
610 }
611 else
612 {
613 indent = _decideIndent();
614 _openBlock(indent);
615 m_sParentStyle = szValue;
616 }
617 return;
618 }
619 else if (!strcmp (szValue, "Plain Text"))
620 {
621 _closeChapterTitle();
622
623 if (!m_iSectionDepth)
624 {
625 _openSection (api,1, szValue);
626 _closeSectionTitle(); // no title
627 }
628
629 if(m_iLastClosed == TT_SECTION)
630 {
631 _openSection(api,m_iSectionDepth,szValue);
632 _closeSectionTitle(); //no title
633 }
634
635 /* merge all plaintexts into 1 if possible */
636 if ((!m_bInParagraph) || (!(m_iBlockType == BT_PLAINTEXT)))
637 {
638 indent = _decideIndent();
639 _openPlainBlock();
640 }
641 else
642 m_pie -> write ("\n");
643
644 m_sParentStyle = szValue;
645 return;
646 }
647 else if (!strcmp (szValue, "Normal"))
648 {
649 _closeChapterTitle();
650
651 if (!m_iSectionDepth)
652 _openSection (api,1, szValue);
653
654 _closeSectionTitle();
655 _closeParagraph();
656
657 if(m_iLastClosed == TT_SECTION)
658 {
659 _openSection(api,m_iSectionDepth,szValue);
660 _closeSectionTitle(); //no title
661 }
662
663 buf = "para";
664
665 indent = _decideIndent();
666 _tagOpen(TT_BLOCK,buf,false,indent,indent); //don't indent in tables
667 m_iBlockType = BT_NORMAL;
668 }
669 else
670 {
671 /* unhandled style */
672 _closeChapterTitle();
673
674 if(!_inSectionStrux() && !m_bInTitle)
675 {
676 buf = "para";
677
678 if(strcmp (szValue, m_sLastStyle.utf8_str())) // not a coalescing run
679 {
680 _openSection(api,m_iSectionDepth,szValue);
681 _closeSectionTitle(); //no title
682 }
683
684 _closeParagraph();
685 indent = _decideIndent();
686 _tagOpen(TT_BLOCK,buf,false,indent,indent);
687 m_bInParagraph = true;
688 m_iBlockType = BT_NORMAL;
689 m_sLastStyle = szValue;
690 }
691 else
692 {
693 indent = _decideIndent();
694 _openBlock(indent);
695 }
696 return;
697 }
698 }
699 else
700 {
701 // <p> with no style attribute ...
702 if (!m_iSectionDepth)
703 _openSection (api,1, "");
704
705 _closeSectionTitle();
706 _closeParagraph();
707 m_iBlockType = BT_NORMAL;
708
709 if(m_iLastClosed == TT_SECTION)
710 {
711 _openSection(api,m_iSectionDepth,szValue);
712 _closeSectionTitle();
713 }
714
715 buf = "para";
716 indent = _decideIndent();
717 _tagOpen(TT_BLOCK,buf,false,indent,indent); //don't indent in table
718 }
719 }
720 else
721 {
722 // <p> with no style attribute, and no properties either
723 if (!m_iSectionDepth)
724 _openSection (api,1,"");
725
726 _closeSectionTitle();
727 _closeParagraph ();
728 m_iBlockType = BT_NORMAL;
729
730 if(m_iLastClosed == TT_SECTION)
731 {
732 _openSection(api,m_iSectionDepth,"");
733 _closeSectionTitle();
734 }
735
736 indent = _decideIndent();
737 _tagOpen(TT_BLOCK,"para",false,indent,indent); //don't indent in table
738 }
739 m_bInParagraph = true;
740 }
741
_openSection(PT_AttrPropIndex api,int sub,const UT_UTF8String & content)742 void s_DocBook_Listener :: _openSection (PT_AttrPropIndex api, int sub, const UT_UTF8String & content)
743 {
744 if((m_bInTable) || (m_bInFrame) || (m_bInHdrFtr))
745 return;
746
747 if(!m_bInChapter)
748 _openChapter(api);
749
750 if(!m_bInSection)
751 _closeChapterTitle();
752
753 _closeSection(sub - 1);
754
755 if(_tagTop() == TT_TITLE)
756 _closeSectionTitle();
757
758 UT_UTF8String section = "section", escaped = "";
759 const PP_AttrProp * pAP = NULL;
760 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
761 const gchar * szValue = 0;
762
763 if(content.length())
764 {
765 escaped = content;
766 escaped.escapeXML();
767 section += " role=\"";
768 section += escaped;
769 section += "\"";
770 }
771
772 _tagOpen(TT_SECTION,section);
773 m_iSectionDepth++;
774 m_bInSection = true;
775 _openSectionTitle();
776
777 if(pAP && bHaveProp && (pAP->getAttribute("strux-image-dataid", szValue)))
778 {
779 _closeSectionTitle(); // no title
780 _handlePositionedImage(api);
781 }
782 }
783
_openSectionTitle(void)784 void s_DocBook_Listener :: _openSectionTitle(void)
785 {
786 if((_tagTop() != TT_SECTION) || m_bInTitle)
787 return;
788
789 _tagOpen(TT_TITLE,"title",false);
790 m_bInTitle = true;
791 }
792
_openSpan(PT_AttrPropIndex api)793 void s_DocBook_Listener :: _openSpan(PT_AttrPropIndex api)
794 {
795 if ((!m_bInParagraph && !m_bInTitle))
796 return;
797
798 if(m_bInSpan)
799 _closeSpan();
800
801 UT_UTF8String buf = "phrase";
802 const PP_AttrProp * pAP = NULL;
803 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
804
805 if (bHaveProp && pAP)
806 {
807 const gchar * szValue = 0;
808
809 if ((pAP->getAttribute(static_cast<const gchar *>("revision"), szValue)))
810 {
811 buf += " revision=\"";
812 buf += szValue;
813 buf += "\"";
814 }
815 if ((pAP->getProperty(static_cast<const gchar *>("lang"), szValue)))
816 {
817 buf += " lang=\"";
818 buf += szValue;
819 buf += "\"";
820 }
821 if ((pAP->getProperty(static_cast<const gchar *>("font-weight"), szValue)) && !strcmp(szValue, "bold"))
822 {
823 buf += " role=\"strong\"";
824 }
825
826 _tagOpen(TT_PHRASE,buf,false,false,false);
827
828 if ((pAP->getProperty(static_cast<const gchar *>("font-style"), szValue)) && !strcmp(szValue, "italic"))
829 {
830 _tagOpen(TT_EMPHASIS,"emphasis",false,false,false);
831 }
832 if (pAP->getProperty(static_cast<const gchar *>("text-position"), szValue))
833 {
834 if (!strcmp("superscript", szValue))
835 {
836 _tagOpen(TT_SUPERSCRIPT,"superscript",false,false,false);
837 }
838 else if (!strcmp("subscript", szValue))
839 {
840 _tagOpen(TT_SUBSCRIPT,"subscript",false,false,false);
841 }
842 }
843 m_bInSpan = true;
844 m_pAP_Span = pAP;
845 }
846 }
847
_outputData(const UT_UCSChar * data,UT_uint32 length)848 void s_DocBook_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length)
849 {
850 if ((!m_bInParagraph) && (!m_bInTitle))
851 {
852 return;
853 }
854 m_bWasSpace = false;
855
856 UT_UTF8String sBuf = "";
857 const UT_UCSChar * pData;
858
859 UT_ASSERT(sizeof(UT_Byte) == sizeof(char));
860
861 sBuf.reserve(length);
862 for (pData=data; (pData<data+length); /**/)
863 {
864 switch (*pData)
865 {
866 case UCS_FF: // page break
867 if ((!m_bInTitle) && (m_bInParagraph)) // we don't put tags in <title>
868 {
869 if(_inFormattedSpan())
870 _closeSpan();
871 sBuf += "<beginpage/>";
872 }
873 else
874 {
875 UT_ASSERT_HARMLESS(UT_TODO);
876 }
877
878 pData++;
879 break;
880 case '<':
881 sBuf += "<";
882 pData++;
883 break;
884
885 case '>':
886 sBuf += ">";
887 pData++;
888 break;
889
890 case '&':
891 sBuf += "&";
892 pData++;
893 break;
894
895 case UCS_VTAB: // column break
896 case UCS_LF: // LF -- representing a Forced-Line-Break
897 if (m_iBlockType == BT_PLAINTEXT)
898 {
899 sBuf += "\n";
900 }
901 else
902 {
903 UT_ASSERT_HARMLESS(UT_TODO); // <br/> isn't valid in docbook
904 }
905 pData++;
906 break;
907
908 case ' ':
909 // try to honor multiple spaces
910 // except in PLAINTEXT
911 if (m_iBlockType != BT_PLAINTEXT)
912 {
913 if(m_bWasSpace)
914 {
915 // not defined in dbk, nor in abw...
916 // sBuf += " ";
917 pData++;
918 }
919 else
920 {
921 // just tack on a single space to the textrun
922 m_bWasSpace = true;
923 sBuf += " ";
924 pData++;
925 }
926 break;
927 }
928 else
929 {
930 // plain text: allowing multiple spaces and so
931 sBuf.appendUCS4(pData,1);
932 pData++;
933 break;
934 }
935 case UCS_TAB:
936 // try to honor multiple spaces
937 // except in PLAINTEXT
938 if (m_iBlockType != BT_PLAINTEXT)
939 {
940 if(m_bWasSpace)
941 {
942 // not defined in dbk, nor in abw...
943 // sBuf += " ";
944 pData++;
945 }
946 else
947 {
948 // just tack on a single space to the textrun
949 m_bWasSpace = true;
950 sBuf += "\t";
951 pData++;
952 }
953 break;
954 }
955 else
956 {
957 // plain text: allowing multiple spaces and so
958 sBuf.appendUCS4(pData,1);
959 pData++;
960 break;
961 }
962
963 default:
964
965 // reset this variable
966 m_bWasSpace = false;
967 if(*pData < 0x20) //invalid xml chars
968 pData++;
969 else
970 {
971 sBuf.appendUCS4(pData, 1);
972 pData++;
973 }
974 break;
975 }
976 }
977
978 m_pie->write(sBuf.utf8_str(),sBuf.byteLength());
979 }
980
s_DocBook_Listener(PD_Document * pDocument,IE_Exp_DocBook * pie)981 s_DocBook_Listener::s_DocBook_Listener(PD_Document * pDocument,
982 IE_Exp_DocBook * pie)
983 : mTableHelper(pDocument)
984 {
985 m_pDocument = pDocument;
986 m_pie = pie;
987 m_bInParagraph = false;
988 m_bInSection = false;
989 m_bInSpan = false;
990 m_bInChapter = false;
991 m_bInTable = false;
992 m_bInTitle = false;
993 m_bInFrame = false;
994 m_bInHdrFtr = false;
995 m_bInNote = false;
996 m_iBlockType = 0;
997 m_iNestedTable = -1;
998 m_iTableDepth = 0;
999 m_iListDepth = 0;
1000 m_iPreviousListDepth = 0;
1001 m_iSectionDepth = 0;
1002 m_iLastClosed = 0;
1003 m_sLastStyle = ""; //only used for non-handled styles
1004 m_sParentStyle = "";
1005 m_bExternal = false;
1006 }
1007
~s_DocBook_Listener()1008 s_DocBook_Listener::~s_DocBook_Listener()
1009 {
1010 UT_VECTOR_FREEALL(char *, m_utvDataIDs);
1011 }
1012
populate(fl_ContainerLayout *,const PX_ChangeRecord * pcr)1013 bool s_DocBook_Listener::populate(fl_ContainerLayout* /*sfh*/,
1014 const PX_ChangeRecord * pcr)
1015 {
1016 switch (pcr -> getType ())
1017 {
1018 case PX_ChangeRecord :: PXT_InsertSpan:
1019 {
1020 const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *> (pcr);
1021
1022 PT_AttrPropIndex api = pcr->getIndexAP();
1023 if (api)
1024 {
1025 _openSpan(api);
1026 }
1027
1028 PT_BufIndex bi = pcrs->getBufIndex();
1029 _outputData(m_pDocument->getPointer(bi),pcrs->getLength());
1030
1031 if (api)
1032 _closeSpan();
1033 return true;
1034 }
1035 case PX_ChangeRecord::PXT_InsertObject:
1036 {
1037 const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *> (pcr);
1038 PT_AttrPropIndex api = pcr->getIndexAP();
1039
1040 switch (pcro->getObjectType())
1041 {
1042 case PTO_Image:
1043 _handleImage(api);
1044 return true;
1045
1046 case PTO_Math:
1047 _handleMath(api);
1048 return true;
1049
1050 case PTO_Embed:
1051 _handleEmbedded(api);
1052 return true;
1053
1054 case PTO_Field:
1055 _handleField(pcro, api);
1056 return true;
1057
1058 case PTO_Hyperlink:
1059 _handleHyperlink(api);
1060 return true;
1061
1062 case PTO_Bookmark:
1063 _handleBookmark(api);
1064 return true;
1065
1066 default:
1067 UT_ASSERT_HARMLESS(UT_TODO);
1068 return true;
1069 }
1070 return false;
1071 }
1072
1073 default:
1074 return true;
1075 }
1076 }
1077
1078 /* http://www.docbook.org/tdg/en/html/table.html */
1079
_openTable(PT_AttrPropIndex api)1080 void s_DocBook_Listener::_openTable(PT_AttrPropIndex api)
1081 {
1082 if(m_bInTitle)
1083 _closeSectionTitle();
1084
1085 if(m_bInTable)
1086 {
1087 _openNestedTable();
1088 return;
1089 }
1090
1091 UT_UTF8String buf("");
1092 UT_sint32 nCols = mTableHelper.getNumCols();
1093
1094 if(!m_bInSection) //tables as first elements
1095 {
1096 _openSection(api,1,"");
1097 _closeSectionTitle(); //no title in this instance, so just close it
1098 }
1099
1100 if(m_iLastClosed == TT_SECTION)
1101 {
1102 _openSection(api,m_iSectionDepth,"");
1103 _closeSectionTitle(); //no title
1104 }
1105
1106 buf = "informaltable frame=\"all\"";
1107
1108 _tagOpen(TT_TABLE,buf);
1109
1110 UT_UTF8String tgroup(UT_UTF8String_sprintf("tgroup cols='%d' align='left' colsep='1' rowsep='1'", nCols));
1111 _tagOpen(TT_TGROUP,tgroup,true,true,false);
1112
1113 for (int i = 0; i < nCols; i++)
1114 {
1115 UT_UTF8String colspec (UT_UTF8String_sprintf("colspec colname='c%d'", i+1));
1116 _tagOpenClose(colspec,true);
1117 }
1118
1119 _tagOpen(TT_TBODY,"tbody");
1120 m_bInTable = true;
1121 }
1122
_openNestedTable()1123 void s_DocBook_Listener::_openNestedTable()
1124 {
1125 if(m_iNestedTable != 0) //docbook only allows one level of nesting
1126 return;
1127
1128 if(_tagTop() != TT_ROW)
1129 _openRow();
1130
1131 UT_sint32 nCols = mTableHelper.getNumCols();
1132
1133 UT_UTF8String entrytbl(UT_UTF8String_sprintf("entrytbl cols='%d' align='left' colsep='1' rowsep='1'", nCols));
1134
1135 _tagOpen(TT_ENTRYTBL,entrytbl);
1136 _tagOpen(TT_TBODY,"tbody");
1137 m_iNestedTable = 1;
1138 }
1139
_openCell()1140 void s_DocBook_Listener::_openCell()
1141 {
1142 UT_sint32 rowspan = 1, colspan = 1;
1143 UT_UTF8String entry ("entry");
1144
1145 rowspan = mTableHelper.getBot() - mTableHelper.getTop();
1146 colspan = mTableHelper.getRight() - mTableHelper.getLeft();
1147
1148 _openRow();
1149
1150 if (rowspan > 1)
1151 entry += UT_UTF8String_sprintf(" morerows='%d'", rowspan-1);
1152 if (colspan > 1)
1153 entry += UT_UTF8String_sprintf(" namest='c%d' nameend='c%d'", mTableHelper.getLeft()+1, mTableHelper.getRight());
1154
1155 _tagOpen(TT_ENTRY,entry,false,true,true);
1156 }
1157
_openRow(void)1158 void s_DocBook_Listener::_openRow(void)
1159 {
1160 if (mTableHelper.isNewRow())
1161 {
1162 _closeCell();
1163 _closeRow();
1164 _tagOpen(TT_ROW,"row");
1165 }
1166 }
1167
_closeTable(void)1168 void s_DocBook_Listener::_closeTable(void)
1169 {
1170 if(!m_bInTable)
1171 return;
1172
1173 if(m_iNestedTable == 1)
1174 {
1175 _closeNestedTable();
1176 return;
1177 }
1178
1179 _closeCell();
1180 _closeRow();
1181 _tagClose(TT_TBODY,"tbody");
1182 _tagClose(TT_TGROUP,"tgroup",true,true,false); //keep tgroup and tbody at the same indent level
1183 _tagClose(TT_TABLE,"informaltable");
1184 m_bInTable = false;
1185 }
1186
_closeNestedTable(void)1187 void s_DocBook_Listener::_closeNestedTable(void)
1188 {
1189 if(m_iNestedTable != 1)
1190 return;
1191
1192 _closeCell();
1193 _closeRow();
1194 _tagClose(TT_TBODY,"tbody");
1195 _tagClose(TT_ENTRYTBL,"entrytbl");
1196 m_iNestedTable = 2;
1197 }
1198
_closeCell(void)1199 void s_DocBook_Listener::_closeCell(void)
1200 {
1201 _closeParagraph();
1202
1203 if(_tagTop() == TT_ENTRY)
1204 {
1205 _tagClose(TT_ENTRY,"entry",true,false,true);
1206 }
1207
1208 }
1209
_closeRow(void)1210 void s_DocBook_Listener::_closeRow(void)
1211 {
1212 _closeCell();
1213
1214 if (_tagTop() == TT_ROW)
1215 {
1216 _tagClose(TT_ROW,"row");
1217 }
1218 }
1219
_handleDocument(void)1220 void s_DocBook_Listener::_handleDocument(void)
1221 {
1222 UT_UTF8String buf("book");
1223 PT_AttrPropIndex docApi = m_pDocument->getAttrPropIndex();
1224 const PP_AttrProp * pDAP = NULL;
1225 const gchar* szValue = 0;
1226
1227 m_pDocument->getAttrProp (docApi, &pDAP);
1228
1229 if(pDAP && pDAP->getProperty("lang", szValue))
1230 {
1231 buf += " lang=\"";
1232 buf += szValue;
1233 buf+= "\"";
1234 }
1235
1236 _tagOpen(TT_DOCUMENT,buf);
1237 }
1238
_handleMetaData(void)1239 void s_DocBook_Listener::_handleMetaData(void)
1240 {
1241 std::string metaProp, escaped;
1242
1243 _tagOpen(TT_BOOKINFO,"bookinfo");
1244 _tagOpen(TT_BIBLIOMISC,"bibliomisc",false,true,false);
1245 _tagOpen(TT_APPLICATION,"application class=\"software\"",false,false,false);
1246 m_pie->write("AbiWord");
1247 _tagClose(TT_APPLICATION,"application",false,false,false);
1248 _tagClose(TT_BIBLIOMISC,"bibliomisc",true,false,false);
1249
1250 if (m_pDocument->getMetaDataProp (PD_META_KEY_TITLE, metaProp) && metaProp.size())
1251 {
1252 escaped = UT_escapeXML(metaProp);
1253 _tagOpen(TT_TITLE,"title",false,true,false);
1254 m_pie->write(escaped.c_str());
1255 _tagClose(TT_TITLE,"title",true,false,false);
1256 }
1257 if (m_pDocument->getMetaDataProp (PD_META_KEY_CREATOR, metaProp) && metaProp.size())
1258 {
1259 escaped = UT_escapeXML(metaProp);
1260 _tagOpen(TT_AUTHOR,"author",false,true,false);
1261 _tagOpen(TT_OTHERNAME,"othername role=\"full\"",false,false,false);
1262 m_pie->write(metaProp.c_str());
1263 _tagClose(TT_OTHERNAME,"othername",false,false,false);
1264 _tagClose(TT_AUTHOR,"author",true,false,false);
1265 }
1266 if (m_pDocument->getMetaDataProp (PD_META_KEY_SUBJECT, metaProp) && metaProp.size())
1267 {
1268 escaped = UT_escapeXML(metaProp);
1269 _tagOpen(TT_SUBJECTSET,"subjectset",false,true,false);
1270 _tagOpen(TT_SUBJECT,"subject",false,false,false);
1271 _tagOpen(TT_SUBJECTTERM,"subjectterm",false,false,false);
1272 m_pie->write(escaped.c_str());
1273 _tagClose(TT_SUBJECTTERM,"subjectterm",false,false,false);
1274 _tagClose(TT_SUBJECT,"subject",false,false,false);
1275 _tagClose(TT_SUBJECTSET,"subjectset",true,false,false);
1276 }
1277 if (m_pDocument->getMetaDataProp (PD_META_KEY_DESCRIPTION, metaProp) && metaProp.size())
1278 {
1279 escaped = UT_escapeXML(metaProp);
1280 _tagOpen(TT_ABSTRACT,"abstract",false,true,false);
1281 _tagOpen(TT_BLOCK,"para",false,false,false);
1282 m_pie->write(escaped.c_str());
1283 _tagClose(TT_BLOCK,"para",false,false,false);
1284 _tagClose(TT_ABSTRACT,"abstract",true,false,false);
1285 }
1286 if (m_pDocument->getMetaDataProp (PD_META_KEY_PUBLISHER, metaProp) && metaProp.size())
1287 {
1288 escaped = UT_escapeXML(metaProp);
1289 _tagOpen(TT_PUBLISHER,"publisher",false,true,false);
1290 _tagOpen(TT_PUBLISHERNAME,"publishername",false,false,false);
1291 m_pie->write(escaped.c_str());
1292 _tagClose(TT_PUBLISHERNAME,"publishername",false,false,false);
1293 _tagClose(TT_PUBLISHER,"publisher",true,false,false);
1294 }
1295 if (m_pDocument->getMetaDataProp (PD_META_KEY_CONTRIBUTOR, metaProp) && metaProp.size())
1296 {
1297 escaped = UT_escapeXML(metaProp);
1298 _tagOpen(TT_COLLAB,"collab",false,true,false);
1299 _tagOpen(TT_COLLABNAME,"collabname",false,false,false);
1300 m_pie->write(escaped.c_str());
1301 _tagClose(TT_COLLABNAME,"collabname",false,false,false);
1302 _tagClose(TT_COLLAB,"collab",true,false,false);
1303 }
1304 if (m_pDocument->getMetaDataProp (PD_META_KEY_DATE, metaProp) && metaProp.size())
1305 {
1306 escaped = UT_escapeXML(metaProp);
1307 _tagOpen(TT_DATE,"date",false,true,false);
1308 m_pie->write(escaped.c_str());
1309 _tagClose(TT_DATE,"date",true,false,false);
1310 }
1311 if (m_pDocument->getMetaDataProp (PD_META_KEY_SOURCE, metaProp) && metaProp.size())
1312 {
1313 escaped = UT_escapeXML(metaProp);
1314 _tagOpen(TT_BIBLIOSOURCE,"bibliosource",false,true,false);
1315 m_pie->write(escaped.c_str());
1316 _tagClose(TT_BIBLIOSOURCE,"bibliosource",true,false,false);
1317 }
1318 if (m_pDocument->getMetaDataProp (PD_META_KEY_RELATION, metaProp) && metaProp.size())
1319 {
1320 escaped = UT_escapeXML(metaProp);
1321 _tagOpen(TT_BIBLIORELATION,"bibliorelation",false,true,false);
1322 m_pie->write(escaped.c_str());
1323 _tagClose(TT_BIBLIORELATION,"bibliorelation",true,false,false);
1324 }
1325 if (m_pDocument->getMetaDataProp (PD_META_KEY_COVERAGE, metaProp) && metaProp.size())
1326 {
1327 escaped = UT_escapeXML(metaProp);
1328 _tagOpen(TT_BIBLIOCOVERAGE,"bibliocoverage",false,true,false);
1329 m_pie->write(escaped.c_str());
1330 _tagClose(TT_BIBLIOCOVERAGE,"bibliocoverage",true,false,false);
1331 }
1332 if (m_pDocument->getMetaDataProp (PD_META_KEY_RIGHTS, metaProp) && metaProp.size())
1333 {
1334 escaped = UT_escapeXML(metaProp);
1335 _tagOpen(TT_LEGALNOTICE,"legalnotice",false,true,false);
1336 _tagOpen(TT_BLOCK,"para",false,false,false);
1337 m_pie->write(escaped.c_str());
1338 _tagClose(TT_BLOCK,"para",false,false,false);
1339 _tagClose(TT_LEGALNOTICE,"legalnotice",true,false,false);
1340 }
1341 if (m_pDocument->getMetaDataProp (PD_META_KEY_KEYWORDS, metaProp) && metaProp.size())
1342 {
1343 UT_UTF8String buf = "";
1344 UT_UCS4String keyword(metaProp);
1345
1346 for(UT_uint32 i = 0;i < keyword.length(); i++)
1347 {
1348 if(keyword[i] != ' ')
1349 {
1350 buf += keyword[i];
1351 }
1352 else
1353 {
1354 if(buf.empty()) //only blank space encountered
1355 {
1356 continue;
1357 }
1358 if(_tagTop() == TT_BOOKINFO)
1359 _tagOpen(TT_KEYWORDSET,"keywordset");
1360
1361 _tagOpen(TT_KEYWORD,"keyword",false,true,false);
1362 buf.escapeXML();
1363 m_pie->write(buf.utf8_str());
1364 _tagClose(TT_KEYWORD,"keyword",true,false,false);
1365 buf.clear();
1366 }
1367 }
1368
1369 if(buf.length())
1370 {
1371 if(_tagTop() == TT_BOOKINFO)
1372 _tagOpen(TT_KEYWORDSET,"keywordset");
1373
1374 _tagOpen(TT_KEYWORD,"keyword",false,true,false);
1375 buf.escapeXML();
1376 m_pie->write(buf.utf8_str());
1377 _tagClose(TT_KEYWORD,"keyword",true,false,false);
1378 }
1379
1380 if(_tagTop() == TT_KEYWORDSET)
1381 _tagClose(TT_KEYWORDSET,"keywordset");
1382 }
1383 if (m_pDocument->getMetaDataProp (PD_META_KEY_DATE_LAST_CHANGED, metaProp) && metaProp.size())
1384 {
1385 UT_ASSERT_HARMLESS(UT_TODO);
1386 }
1387
1388 _handleRevisions();
1389 _tagClose(TT_BOOKINFO,"bookinfo");
1390 }
1391
_handleRevisions(void)1392 void s_DocBook_Listener::_handleRevisions(void)
1393 {
1394 const AD_Revision * pRev = NULL;
1395 const UT_GenericVector<AD_Revision*> & vRevisions = m_pDocument->getRevisions();
1396
1397 UT_sint32 k = 0;
1398 for (k=0; k < vRevisions.getItemCount(); k++)
1399 {
1400 if(k == 0)
1401 _tagOpen(TT_REVHISTORY,"revhistory");
1402
1403 pRev = vRevisions.getNthItem(k);
1404 if(!pRev)
1405 continue;
1406
1407 UT_UTF8String s;
1408 UT_UCS4String s4;
1409
1410 UT_UTF8String_sprintf(s, "%d", pRev->getId());
1411 _tagOpen(TT_REVISION,"revision");
1412 _tagOpen(TT_REVNUMBER,"revnumber",false);
1413 m_pie->write(s.utf8_str());
1414 _tagClose(TT_REVNUMBER,"revnumber",true,false);
1415 s.clear();
1416
1417 UT_UTF8String_sprintf(s, "%d", pRev->getStartTime());
1418 _tagOpen(TT_DATE,"date",false);
1419 m_pie->write(s.utf8_str());
1420 _tagClose(TT_DATE,"date",true,false);
1421 s4 = pRev->getDescription();
1422
1423 if(s4.length())
1424 {
1425 _tagOpen(TT_REVREMARK,"revremark",false);
1426 s.clear();
1427 s = s4.utf8_str();
1428 s.escapeXML();
1429 m_pie->write(s.utf8_str());
1430 _tagClose(TT_REVREMARK,"revremark",true,false);
1431 }
1432 _tagClose(TT_REVISION,"revision");
1433 }
1434
1435 if(_tagTop() == TT_REVHISTORY)
1436 _tagClose(TT_REVHISTORY,"revhistory");
1437 }
1438
_handleImage(PT_AttrPropIndex api)1439 void s_DocBook_Listener::_handleImage(PT_AttrPropIndex api)
1440 {
1441 UT_UTF8String buf(""), escaped("");
1442 const gchar* szValue = 0;
1443 const PP_AttrProp * pAP = NULL;
1444 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1445 UT_LocaleTransactor t(LC_NUMERIC, "C");
1446
1447 if(!m_bInSection) // an image might be in a chapter heading
1448 {
1449 _closeChapterTitle();
1450 _openSection(api,1,"");
1451 }
1452 if(!m_bInParagraph) // an image might also be in a section heading
1453 {
1454 _closeSectionTitle();
1455 _openBlock(true);
1456 }
1457
1458 if(bHaveProp && pAP && pAP->getAttribute("dataid", szValue))
1459 {
1460 const gchar* dataid = g_strdup(szValue);
1461 char * temp = _stripSuffix(UT_go_basename(szValue), '_');
1462 char * fstripped = _stripSuffix(temp, '.');
1463
1464 std::string mimeType;
1465 const UT_ByteBuf * pByteBuf = 0;
1466 const char * extension = "png";
1467 const char * format = "PNG";
1468 m_pDocument->getDataItemDataByName(szValue, &pByteBuf,
1469 &mimeType, NULL);
1470 if(mimeType == "image/jpeg") {
1471 extension = "jpg";
1472 format = "JPEG";
1473 }
1474 else if(mimeType == "image/svg+xml") {
1475 extension = "svg";
1476 format = "SVG";
1477 }
1478
1479 UT_UTF8String_sprintf(buf, "%s.%s", fstripped, extension);
1480 m_utvDataIDs.push_back(dataid);
1481
1482 FREEP(temp);
1483 FREEP(fstripped);
1484
1485 _tagOpen(TT_FIGURE,"figure",false,false,false);
1486 _tagOpen(TT_TITLE,"title",false,false,false);
1487
1488 if(pAP->getAttribute("title", szValue)) //use the image's title instead of its file name, if it exists
1489 {
1490 escaped = szValue;
1491 escaped.escapeXML();
1492 m_pie->write(escaped.utf8_str());
1493 }
1494 else //fall back to the filename
1495 {
1496 escaped = buf.escapeXML();
1497 m_pie->write(escaped.utf8_str());
1498 }
1499
1500 _tagClose(TT_TITLE,"title",false,false,false);
1501 _tagOpen(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1502 _tagOpen(TT_IMAGEOBJECT,"imageobject",false,false,false);
1503
1504 escaped.clear();
1505 escaped = "imagedata fileref=\"";
1506 escaped += UT_go_basename(m_pie->getFileName());
1507 escaped += "_data/";
1508 escaped += buf.escapeXML();
1509 escaped += "\" format=\"";
1510 escaped += format;
1511 escaped += "\"";
1512
1513 if(pAP->getProperty("height", szValue))
1514 {
1515 escaped += " depth=\"";
1516 escaped += szValue;
1517 escaped += "\"";
1518 }
1519 if(pAP->getProperty("width", szValue))
1520 {
1521 escaped += " width=\"";
1522 escaped += szValue;
1523 escaped += "\"";
1524 }
1525
1526 _tagOpenClose(escaped,true,false,false);
1527 _tagClose(TT_IMAGEOBJECT,"imageobject",false,false,false);
1528
1529 if(pAP->getAttribute("alt", szValue)) //use the image's alt
1530 {
1531 buf.clear();
1532 buf = szValue;
1533 buf.escapeXML();
1534 _tagOpen(TT_TEXTOBJECT,"textobject",false,false,false);
1535 _tagOpen(TT_BLOCK,"para",false,false,false);
1536 m_pie->write(buf.utf8_str());
1537 _tagClose(TT_BLOCK,"para",false,false,false);
1538 _tagClose(TT_TEXTOBJECT,"textobject",false,false,false);
1539 }
1540 _tagClose(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1541 _tagClose(TT_FIGURE,"figure",false,false,false);
1542 }
1543 }
1544
_handlePositionedImage(PT_AttrPropIndex api)1545 void s_DocBook_Listener::_handlePositionedImage(PT_AttrPropIndex api)
1546 {
1547 UT_UTF8String buf(""), escaped("");
1548 const gchar* szValue = 0;
1549 const PP_AttrProp * pAP = NULL;
1550 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1551 UT_LocaleTransactor t(LC_NUMERIC, "C");
1552
1553 if(bHaveProp && pAP && pAP->getAttribute("strux-image-dataid", szValue))
1554 {
1555 const gchar* dataid = g_strdup(szValue);
1556 char * temp = _stripSuffix(UT_go_basename(szValue), '_');
1557 char * fstripped = _stripSuffix(temp, '.');
1558
1559 std::string mimeType;
1560 const UT_ByteBuf * pByteBuf = 0;
1561 const char * extension = "png";
1562 const char * format = "PNG";
1563 m_pDocument->getDataItemDataByName(szValue, &pByteBuf,
1564 &mimeType, NULL);
1565 if(mimeType == "image/jpeg") {
1566 extension = "jpg";
1567 format = "JPEG";
1568 }
1569 else if(mimeType == "image/svg+xml") {
1570 extension = "svg";
1571 format = "SVG";
1572 }
1573
1574 UT_UTF8String_sprintf(buf, "%s.%s", fstripped, extension);
1575 m_utvDataIDs.push_back(dataid);
1576
1577 FREEP(temp);
1578 FREEP(fstripped);
1579
1580 _tagOpen(TT_FIGURE,"figure",false,true,false);
1581 _tagOpen(TT_TITLE,"title",false,false,false);
1582
1583 if(pAP->getAttribute("title", szValue)) //use the image's title instead of its file name, if it exists
1584 {
1585 escaped = szValue;
1586 escaped.escapeXML();
1587 m_pie->write(escaped.utf8_str());
1588 }
1589 else //fall back to the filename
1590 {
1591 escaped = buf.escapeXML();
1592 m_pie->write(escaped.utf8_str());
1593 }
1594
1595 _tagClose(TT_TITLE,"title",false,false,false);
1596 _tagOpen(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1597 _tagOpen(TT_IMAGEOBJECT,"imageobject",false,false,false);
1598
1599 escaped.clear();
1600 escaped = "imagedata fileref=\"";
1601 escaped += UT_go_basename(m_pie->getFileName());
1602 escaped += "_data/";
1603 escaped += buf.escapeXML();
1604 escaped += "\" format=\"";
1605 escaped += format;
1606 escaped += "\"";
1607
1608 if(pAP->getProperty("frame-height", szValue))
1609 {
1610 escaped += " depth=\"";
1611 escaped += szValue;
1612 escaped += "\"";
1613 }
1614 if(pAP->getProperty("frame-width", szValue))
1615 {
1616 escaped += " width=\"";
1617 escaped += szValue;
1618 escaped += "\"";
1619 }
1620
1621 _tagOpenClose(escaped,true,false,false);
1622 _tagClose(TT_IMAGEOBJECT,"imageobject",false,false,false);
1623
1624 if(pAP->getAttribute("alt", szValue)) //use the image's alt
1625 {
1626 buf.clear();
1627 buf = szValue;
1628 buf.escapeXML();
1629 _tagOpen(TT_TEXTOBJECT,"textobject",false,false,false);
1630 _tagOpen(TT_BLOCK,"para",false,false,false);
1631 m_pie->write(buf.utf8_str());
1632 _tagClose(TT_BLOCK,"para",false,false,false);
1633 _tagClose(TT_TEXTOBJECT,"textobject",false,false,false);
1634 }
1635 _tagClose(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1636 _tagClose(TT_FIGURE,"figure",true,false,false);
1637 }
1638 }
1639
_handleMath(PT_AttrPropIndex api)1640 void s_DocBook_Listener::_handleMath(PT_AttrPropIndex api)
1641 {
1642 UT_UTF8String buf(""), escaped("");
1643 const gchar* szValue = 0;
1644 const PP_AttrProp * pAP = NULL;
1645 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1646 UT_LocaleTransactor t(LC_NUMERIC, "C");
1647
1648 if(!m_bInSection) // an equation might be in a chapter heading
1649 {
1650 _closeChapterTitle();
1651 _openSection(api,1,"");
1652 }
1653 if(!m_bInParagraph) // an equation might also be in a section heading
1654 {
1655 _closeSectionTitle();
1656 _openBlock(true);
1657 }
1658
1659 if(bHaveProp && pAP && pAP->getAttribute("dataid", szValue))
1660 {
1661 buf = "snapshot-png-";
1662 buf += szValue;
1663 const gchar* dataid = g_strdup(buf.utf8_str());
1664 m_utvDataIDs.push_back(dataid);
1665 buf += ".png";
1666
1667 _tagOpen(TT_INLINEEQUATION,"inlineequation",false,false,false);
1668
1669 escaped = "graphic fileref=\"";
1670 escaped += UT_go_basename(m_pie->getFileName());
1671 escaped += "_data/";
1672 escaped += buf.escapeXML();
1673 escaped += "\" format=\"PNG\"";
1674
1675 if(pAP->getProperty("height", szValue))
1676 {
1677 double dInch = static_cast<double>(atoi(szValue))/UT_LAYOUT_RESOLUTION;
1678 buf.clear();
1679 UT_UTF8String_sprintf(buf,"%fin",dInch);
1680 escaped += " depth=\"";
1681 escaped += buf;
1682 escaped += "\"";
1683 }
1684 if(pAP->getProperty("width", szValue))
1685 {
1686 double dInch = static_cast<double>(atoi(szValue))/UT_LAYOUT_RESOLUTION;
1687 buf.clear();
1688 UT_UTF8String_sprintf(buf,"%fin",dInch);
1689 escaped += " width=\"";
1690 escaped += buf;
1691 escaped += "\"";
1692 }
1693 if(pAP->getProperty("lang", szValue))
1694 {
1695 escaped += " lang=\"";
1696 escaped += szValue;
1697 escaped += "\"";
1698 }
1699
1700 _tagOpenClose(escaped,true,false,false);
1701
1702 /* TODO: save mathml somehow
1703
1704 if(pAP->getAttribute("latexid", szValue))
1705 {
1706 escaped.clear();
1707 escaped = szValue;
1708 escaped.escapeXML();
1709 _tagOpen(TT_MATHPHRASE,"mathphrase",false);
1710 m_pie->write(escaped.utf8_str()); //TODO: investigate mml support in docbook instead
1711 _tagClose(TT_MATHPHRASE,"mathphrase");
1712 }
1713 */
1714 _tagClose(TT_INLINEEQUATION,"inlineequation", false, false, false);
1715 }
1716 }
1717
_handleEmbedded(PT_AttrPropIndex api)1718 void s_DocBook_Listener::_handleEmbedded(PT_AttrPropIndex api)
1719 {
1720 UT_UTF8String buf(""), escaped("");
1721 const gchar* szValue = 0;
1722 const PP_AttrProp * pAP = NULL;
1723 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1724 UT_LocaleTransactor t(LC_NUMERIC, "C");
1725
1726 if(!m_bInSection) // a chart might be in a chapter heading
1727 {
1728 _closeChapterTitle();
1729 _openSection(api,1,"");
1730 }
1731 if(!m_bInParagraph) // a chart might also be in a section heading
1732 {
1733 _closeSectionTitle();
1734 _openBlock(true);
1735 }
1736
1737 if(bHaveProp && pAP && pAP->getAttribute("dataid", szValue))
1738 {
1739 buf = "snapshot-png-";
1740 buf += szValue;
1741 const gchar* dataid = g_strdup(buf.utf8_str());
1742 m_utvDataIDs.push_back(dataid);
1743 buf += ".png";
1744
1745 _tagOpen(TT_INFORMALFIGURE,"informalfigure",false,false,false);
1746 _tagOpen(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1747 _tagOpen(TT_IMAGEOBJECT,"imageobject",false,false,false);
1748
1749 escaped = "imagedata fileref=\"";
1750 escaped += UT_go_basename(m_pie->getFileName());
1751 escaped += "_data/";
1752 escaped += buf.escapeXML();
1753 escaped += "\" format=\"PNG\"";
1754
1755 if(pAP->getProperty("height", szValue))
1756 {
1757 escaped += " depth=\"";
1758 escaped += szValue;
1759 escaped += "\"";
1760 }
1761 if(pAP->getProperty("width", szValue))
1762 {
1763 escaped += " width=\"";
1764 escaped += szValue;
1765 escaped += "\"";
1766 }
1767 if(pAP->getProperty("lang", szValue))
1768 {
1769 escaped += " lang=\"";
1770 escaped += szValue;
1771 escaped += "\"";
1772 }
1773
1774 _tagOpenClose(escaped,true,false,false);
1775 _tagClose(TT_IMAGEOBJECT,"imageobject",false,false,false);
1776 _tagClose(TT_MEDIAOBJECT,"mediaobject",false,false,false);
1777 _tagClose(TT_INFORMALFIGURE,"informalfigure",false,false,false);
1778 }
1779 }
1780
_handleField(const PX_ChangeRecord_Object * pcro,PT_AttrPropIndex api)1781 void s_DocBook_Listener::_handleField(const PX_ChangeRecord_Object * pcro, PT_AttrPropIndex api)
1782 {
1783 UT_UTF8String buf(""), escaped("");
1784 const PP_AttrProp * pAP = NULL;
1785 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1786 const gchar * szValue = 0, * szStyle = 0;
1787
1788 if(!m_bInParagraph)
1789 _openBlock(false);
1790
1791 m_pie->populateFields ();
1792
1793 if(bHaveProp && pAP && pAP->getAttribute ("type", szValue))
1794 {
1795 if (!strcmp (szValue, "list_label"))
1796 {
1797 _openList(api);
1798 return;
1799 }
1800
1801 fd_Field * field = pcro->getField();
1802 buf = "phrase role=\""; //save the field type
1803 buf += szValue;
1804 buf += "\"";
1805
1806 if (!strcmp (szValue, "endnote_anchor")) //give the endnote <para> a unique id
1807 {
1808 if(pAP->getAttribute("endnote-id", szStyle))
1809 {
1810 buf += " id=\"endnote-id-";
1811 buf += szStyle;
1812 buf += "\"";
1813 }
1814 }
1815
1816 _tagOpen(TT_PHRASE,buf,false,false,false);
1817 buf.clear();
1818
1819 if (!strcmp (szValue, "footnote_ref"))
1820 {
1821 buf = "footnoteref linkend=\"footnote-id-";
1822
1823 if(pAP->getAttribute("footnote-id", szValue))
1824 {
1825 buf += szValue;
1826 buf += "\"";
1827 }
1828
1829 _tagOpenClose(buf,true,false,false);
1830 }
1831 else if (!strcmp (szValue, "endnote_ref"))
1832 {
1833 buf = "xref linkend=\"endnote-id-";
1834
1835 if(pAP->getAttribute("endnote-id", szValue))
1836 {
1837 buf += szValue;
1838 buf += "\"";
1839 }
1840
1841 _tagOpenClose(buf,true,false,false);
1842 }
1843
1844 buf.clear();
1845 buf = field->getValue();
1846 if(buf.length())
1847 {
1848 buf.escapeXML();
1849 m_pie->write(buf.utf8_str());
1850 }
1851
1852 _tagClose(TT_PHRASE,"phrase",false,false,false);
1853 }
1854 }
1855
_handleTOC(PT_AttrPropIndex api)1856 void s_DocBook_Listener::_handleTOC(PT_AttrPropIndex api)
1857 {
1858 std::string buf;
1859 UT_UTF8String content("toc");
1860 const gchar* szValue = 0;
1861 const PP_AttrProp * pAP = NULL;
1862 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1863
1864 /* TOCs are supposed to be at the beginning or end of a section, so we
1865 open a new section to prevent the loss of its position in the text */
1866
1867 _closeParagraph();
1868 _closeSection(m_iSectionDepth);
1869 _tagOpen(TT_SECTION,"section role=\"abi-toc\"");
1870
1871 if(bHaveProp && pAP && pAP->getProperty("toc-heading", szValue)) //user-defined
1872 {
1873 buf = UT_escapeXML(szValue ? szValue : "");
1874 }
1875 else // get the default
1876 {
1877 XAP_App::getApp()->getStringSet()->getValueUTF8(AP_STRING_ID_TOC_TocHeading, buf);
1878 }
1879
1880 // TODO: populate the TOC
1881
1882 _tagOpen(TT_TITLE,"title",false);
1883 m_pie->write(buf);
1884 _tagClose(TT_TITLE,"title",true,false);
1885 _tagOpen(TT_TOC,content,false);
1886 _tagClose(TT_TOC,"toc",true,false);
1887 _tagOpenClose("para",false);
1888 _tagClose(TT_SECTION,"section");
1889 }
1890
_handleHyperlink(PT_AttrPropIndex api)1891 void s_DocBook_Listener::_handleHyperlink(PT_AttrPropIndex api)
1892 {
1893 UT_UTF8String buf(""), escaped("");
1894 const gchar* szValue = 0;
1895 const PP_AttrProp * pAP = NULL;
1896 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1897
1898 if(bHaveProp && pAP && pAP->getAttribute("xlink:href", szValue))
1899 {
1900 if(szValue && (szValue[0] == '#'))
1901 {
1902 /* anchor */
1903 escaped = szValue + 1; // skip '#'
1904 escaped.escapeURL();
1905 buf = "link linkend=\"";
1906 buf += escaped;
1907 buf += "\"";
1908 _tagOpen(TT_LINK,buf,false,false,false);
1909 m_bExternal = false;
1910 }
1911 else if(szValue)
1912 {
1913 /* external */
1914 escaped = szValue;
1915 escaped.escapeURL();
1916 buf = "ulink url=\"";
1917 buf += escaped;
1918 buf += "\"";
1919 _tagOpen(TT_ULINK,buf,false,false,false);
1920 m_bExternal = true;
1921 }
1922 }
1923 else
1924 {
1925 if (m_bExternal && (_tagTop() == TT_ULINK))
1926 _tagClose(TT_ULINK,"ulink",false,false,false);
1927 else if(!m_bExternal && (_tagTop() == TT_LINK))
1928 _tagClose(TT_LINK,"link",false,false,false);
1929 }
1930 }
1931
_handleBookmark(PT_AttrPropIndex api)1932 void s_DocBook_Listener::_handleBookmark(PT_AttrPropIndex api)
1933 {
1934 UT_UTF8String buf(""), escaped("");
1935 const gchar* szValue = 0;
1936 const PP_AttrProp * pAP = NULL;
1937 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1938
1939 if(bHaveProp && pAP && pAP->getAttribute("type", szValue))
1940 {
1941 if (!strcmp (szValue, "start") && pAP->getAttribute("name", szValue))
1942 {
1943 buf = "anchor id=\"";
1944 escaped = szValue;
1945 escaped.escapeXML();
1946 buf += escaped;
1947 buf += "\"";
1948 _tagOpenClose(buf,true,false,false);
1949 }
1950 }
1951 }
1952
_handleHdrFtr(PT_AttrPropIndex api)1953 void s_DocBook_Listener::_handleHdrFtr(PT_AttrPropIndex api)
1954 {
1955 UT_UTF8String buf("abi-"); //prefix the type to prevent confusion on import (e.g. if there's a 'footer' style)
1956 const gchar* szValue = 0;
1957 const PP_AttrProp * pAP = NULL;
1958 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1959
1960 if(bHaveProp && pAP && pAP->getAttribute("type", szValue))
1961 buf += szValue;
1962
1963 _openSection(api,1,buf);
1964 _closeSectionTitle(); //no title
1965 }
1966
_handleFootnote(PT_AttrPropIndex api)1967 void s_DocBook_Listener::_handleFootnote(PT_AttrPropIndex api)
1968 {
1969 UT_UTF8String buf("footnote id=\"footnote-id-"); //make it an NCNAME to prevent validation errors
1970 const gchar* szValue = 0;
1971 const PP_AttrProp * pAP = NULL;
1972 bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
1973
1974 if(bHaveProp && pAP && pAP->getAttribute("footnote-id", szValue))
1975 buf += szValue;
1976 buf += "\"";
1977
1978 if(m_bInTitle && !m_bInSection) //in a chapter title
1979 {
1980 _openSection(api,1,"");
1981 }
1982
1983 if(m_bInTitle) //in a section or chapter title
1984 {
1985 _closeSectionTitle();
1986 _openBlock(true);
1987 }
1988
1989 _tagOpen(TT_FOOTNOTE,buf,false,false,false);
1990 }
1991
_decideIndent(void)1992 bool s_DocBook_Listener::_decideIndent(void)
1993 {
1994 if(m_bInTable) // don't indent in tables
1995 return false;
1996
1997 if(m_iBlockType == BT_PLAINTEXT) // <literallayout>
1998 return false;
1999
2000 if((_tagTop() == TT_FOOTNOTE) && ((m_iLastClosed == TT_PHRASE) ||
2001 (m_iLastClosed == TT_BLOCK) || (m_iLastClosed == TT_TITLE))) // the <para> right after <footnote>
2002 return false;
2003
2004 if(m_bInNote && ((m_iLastClosed == TT_PHRASE) || (m_iLastClosed == TT_BLOCK)))
2005 return false;
2006
2007 if(m_bInHdrFtr)
2008 return true;
2009
2010 return true;
2011 }
2012
_inFormattedSpan(void)2013 bool s_DocBook_Listener::_inFormattedSpan(void)
2014 {
2015 return ((_tagTop() == TT_SUPERSCRIPT) || (_tagTop() == TT_SUBSCRIPT) || (_tagTop() == TT_EMPHASIS));
2016 }
2017
_inSectionStrux(void)2018 bool s_DocBook_Listener::_inSectionStrux(void)
2019 {
2020 return ((m_bInTable) || (m_bInFrame) || (m_bInHdrFtr) || (m_bInNote));
2021 }
2022
populateStrux(pf_Frag_Strux * sdh,const PX_ChangeRecord * pcr,fl_ContainerLayout ** psfh)2023 bool s_DocBook_Listener::populateStrux(pf_Frag_Strux* sdh,
2024 const PX_ChangeRecord * pcr,
2025 fl_ContainerLayout* * psfh)
2026 {
2027 UT_ASSERT(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux);
2028 const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);
2029 *psfh = 0; // we don't need it.
2030
2031 switch (pcrx->getStruxType())
2032 {
2033 case PTX_Section:
2034 {
2035 /* open a chapter, _not_ a section; changing this causes the creation of an extra section at the top
2036 of every document */
2037 _openChapter(pcr->getIndexAP());
2038 return true;
2039 }
2040
2041 case PTX_SectionEndnote:
2042 {
2043 // don't do anything - handled in _handleField()
2044 m_bInNote = true;
2045 return true;
2046 }
2047 case PTX_EndEndnote:
2048 {
2049 m_bInNote = false;
2050 return true;
2051 }
2052
2053 case PTX_SectionHdrFtr:
2054 {
2055 _closeSection(0);
2056 _handleHdrFtr(pcr->getIndexAP());
2057 m_bInHdrFtr = true;
2058 return true;
2059 }
2060
2061 case PTX_Block:
2062 {
2063 _openParagraph (pcr -> getIndexAP ());
2064 return true;
2065 }
2066
2067 case PTX_SectionTable:
2068 {
2069 m_iTableDepth++;
2070 if(m_iTableDepth <= 2)
2071 {
2072 _closeParagraph();
2073 mTableHelper.OpenTable(sdh,pcr->getIndexAP()) ;
2074 _openTable(pcr->getIndexAP());
2075 }
2076 return true;
2077 }
2078
2079 case PTX_SectionCell:
2080 {
2081 if(m_iTableDepth > 2)
2082 return true;
2083
2084 if((m_iNestedTable == 2) && (m_iTableDepth == 1)) //the last cell had a nested table; reset the value
2085 m_iNestedTable = -1;
2086
2087 pf_Frag_Strux* nextTable = NULL, *nextCell = NULL;
2088 bool bNextTable = m_pDocument->getNextStruxOfType(sdh, PTX_SectionTable, &nextTable);
2089 bool bEndCell = m_pDocument->getNextStruxOfType(sdh, PTX_EndCell, &nextCell);
2090
2091 if(bNextTable && bEndCell && (m_iNestedTable == -1))
2092 {
2093 if(m_pDocument->getStruxPosition(nextTable) < m_pDocument->getStruxPosition(nextCell)) //nested table
2094 {
2095 _closeParagraph();
2096 mTableHelper.OpenCell(pcr->getIndexAP());
2097 m_iNestedTable = 0; //pending, so don't allow any writing
2098 return true;
2099 }
2100 }
2101
2102 if((m_iNestedTable == -1) || (m_iNestedTable == 1))
2103 {
2104 // regular cell
2105 _closeParagraph();
2106 mTableHelper.OpenCell(pcr->getIndexAP());
2107 _openCell();
2108 }
2109 return true;
2110 }
2111
2112 case PTX_EndTable:
2113 {
2114 // m_iTableDepth will be 1 if a nested table was closed
2115 // or 0 if a regular table was closed
2116 m_iTableDepth--;
2117 if(m_iTableDepth > 1)
2118 return true;
2119
2120 _closeParagraph();
2121 _closeRow();
2122 _closeTable();
2123 mTableHelper.CloseTable();
2124
2125 if(m_iNestedTable != 2) //don't allow any content after an </entrytbl>
2126 m_iNestedTable = -1;
2127 return true;
2128 }
2129
2130 case PTX_EndCell:
2131 {
2132 if(m_iTableDepth > 2)
2133 return true;
2134
2135 _closeParagraph();
2136 _closeCell();
2137 mTableHelper.CloseCell();
2138 return true;
2139 }
2140
2141 case PTX_SectionFootnote:
2142 {
2143 _handleFootnote(pcr->getIndexAP());
2144 m_bInNote = true;
2145 return true;
2146 }
2147
2148 case PTX_EndFootnote:
2149 {
2150 _closeParagraph();
2151 if(m_iLastClosed == TT_PHRASE) //<footnote> was empty - see bug 9890
2152 _tagOpenClose("para",false,false,false);
2153
2154 if(m_bInNote) // we might've closed a footnote early to workaround .doc import bugs, so check first
2155 _tagClose(TT_FOOTNOTE,"footnote",false,false,false);
2156
2157 m_bInNote = false;
2158 return true;
2159 }
2160
2161 case PTX_SectionTOC:
2162 {
2163 _handleTOC(pcr->getIndexAP());
2164 return true;
2165 }
2166
2167 case PTX_EndTOC:
2168 {
2169 // don't do anything - already handled in _handleTOC()
2170 return true;
2171 }
2172
2173 case PTX_SectionFrame:
2174 {
2175 _closeSectionTitle();
2176 _openSection(pcr->getIndexAP(), m_iSectionDepth+1, "abi-frame");
2177 m_bInFrame = true; //make sure this remains after the openSection() call
2178 return true;
2179 }
2180 case PTX_EndFrame:
2181 {
2182 _closeSection(m_iSectionDepth-1);
2183 m_bInFrame = false;
2184 return true;
2185 }
2186
2187 case PTX_EndMarginnote:
2188 case PTX_SectionMarginnote:
2189 default:
2190 UT_ASSERT_HARMLESS(UT_TODO);
2191 return true;
2192 }
2193 }
2194
change(fl_ContainerLayout *,const PX_ChangeRecord *)2195 bool s_DocBook_Listener::change(fl_ContainerLayout* /*sfh*/,
2196 const PX_ChangeRecord * /*pcr*/)
2197 {
2198 UT_ASSERT(0); // this function is not used.
2199 return false;
2200 }
2201
insertStrux(fl_ContainerLayout *,const PX_ChangeRecord *,pf_Frag_Strux *,PL_ListenerId,void (*)(pf_Frag_Strux *,PL_ListenerId,fl_ContainerLayout *))2202 bool s_DocBook_Listener::insertStrux(fl_ContainerLayout* /*sfh*/,
2203 const PX_ChangeRecord * /*pcr*/,
2204 pf_Frag_Strux* /*sdh*/,
2205 PL_ListenerId /* lid */,
2206 void (* /*pfnBindHandles*/)(pf_Frag_Strux* /* sdhNew */,
2207 PL_ListenerId /* lid */,
2208 fl_ContainerLayout* /* sfhNew */))
2209 {
2210 UT_ASSERT(0); // this function is not used.
2211 return false;
2212 }
2213
signal(UT_uint32)2214 bool s_DocBook_Listener::signal(UT_uint32 /* iSignal */)
2215 {
2216 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2217 return false;
2218 }
2219
2220
2221 /*****************************************************************/
2222 /*****************************************************************/
2223
_writeDocument(void)2224 UT_Error IE_Exp_DocBook::_writeDocument(void)
2225 {
2226 m_pListener = new s_DocBook_Listener(getDoc(),this);
2227
2228 if (!m_pListener)
2229 return UT_IE_NOMEMORY;
2230 m_pListener -> _initFile ();
2231 if (!getDoc()->tellListener(static_cast<PL_Listener *>(m_pListener)))
2232 return UT_ERROR;
2233 m_pListener -> _closeFile ();
2234
2235 DELETEP(m_pListener);
2236
2237 return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK);
2238 }
2239
2240 /*****************************************************************/
2241 /*****************************************************************/
2242
_handleDataItems(void)2243 void s_DocBook_Listener::_handleDataItems(void)
2244 {
2245 // Lifted from HTML listener
2246 const char * szName = 0;
2247 std::string mimeType;
2248 const UT_ByteBuf * pByteBuf;
2249
2250 for (UT_uint32 k=0; (m_pDocument->enumDataItems(k,NULL,&szName,&pByteBuf,
2251 &mimeType)); k++)
2252 {
2253 UT_sint32 loc = -1;
2254 for (UT_sint32 i = 0; i < m_utvDataIDs.getItemCount(); i++)
2255 {
2256 if(strcmp(const_cast<char*>(reinterpret_cast<const char*>(m_utvDataIDs[i])), szName) == 0)
2257 {
2258 loc = i;
2259 break;
2260 }
2261 }
2262
2263 if(loc > -1)
2264 {
2265 UT_UTF8String fname;
2266
2267 UT_UTF8String_sprintf(fname, "%s_data", m_pie->getFileName());
2268 /* int result = */
2269 UT_go_directory_create(fname.utf8_str(), 0750, NULL);
2270
2271 if (mimeType == "image/svg+xml")
2272 UT_UTF8String_sprintf(fname, "%s/%s_%d.svg", fname.utf8_str(), szName, loc);
2273 else if (mimeType == "application/mathml+xml")
2274 UT_UTF8String_sprintf(fname, "%s/%s_%d.mathml", fname.utf8_str(), szName, loc);
2275 else // PNG Image
2276 {
2277 char * temp = _stripSuffix(UT_go_basename(szName), '_');
2278 char * fstripped = _stripSuffix(temp, '.');
2279 FREEP(temp);
2280 const char * extension = "png";
2281 if (mimeType == "image/jpeg") {
2282 extension = "jpg";
2283 }
2284 UT_UTF8String_sprintf(fname, "%s/%s.%s", fname.utf8_str(), fstripped, extension);
2285 FREEP(fstripped);
2286 }
2287
2288
2289 GsfOutput *fp = UT_go_file_create (fname.utf8_str(), NULL);
2290
2291 if(!fp)
2292 continue;
2293
2294 gsf_output_write(fp, pByteBuf->getLength(), (const guint8*)pByteBuf->getPointer(0));
2295 gsf_output_close(fp);
2296 g_object_unref (G_OBJECT (fp));
2297 }
2298 }
2299 }
2300