93765b18f72b4b57bf3c3122640c634282779769
[platform/upstream/doxygen.git] / src / xmldocvisitor.cpp
1 /******************************************************************************
2  *
3  * 
4  *
5  *
6  * Copyright (C) 1997-2015 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby 
10  * granted. No representations are made about the suitability of this software 
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18
19 #include <qfileinfo.h> 
20
21 #include "xmldocvisitor.h"
22 #include "docparser.h"
23 #include "language.h"
24 #include "doxygen.h"
25 #include "outputgen.h"
26 #include "xmlgen.h"
27 #include "dot.h"
28 #include "message.h"
29 #include "util.h"
30 #include "parserintf.h"
31 #include "filename.h"
32 #include "config.h"
33 #include "htmlentity.h"
34
35 static void visitCaption(XmlDocVisitor *parent, QList<DocNode> children)
36 {
37   QListIterator<DocNode> cli(children);
38   DocNode *n;
39   for (cli.toFirst();(n=cli.current());++cli) n->accept(parent);
40 }
41
42 static void visitPreStart(FTextStream &t, const char *cmd, const bool doCaption, 
43                           XmlDocVisitor *parent, QList<DocNode> children, 
44                           const QCString &name, bool writeType, DocImage::Type type, const QCString &width, 
45                           const QCString &height)
46 {
47   t << "<" << cmd;
48   if (writeType)
49   {
50     t << " type=\"";
51     switch(type)
52     {
53       case DocImage::Html:    t << "html"; break;
54       case DocImage::Latex:   t << "latex"; break;
55       case DocImage::Rtf:     t << "rtf"; break;
56       case DocImage::DocBook: t << "docbook"; break;
57     }
58     t << "\"";
59   }
60   if (!name.isEmpty())
61   {
62     t << " name=\"" << name << "\"";
63   }
64   if (!width.isEmpty())
65   {
66     t << " width=\"" << convertToXML(width) << "\"";
67   }
68   else if (!height.isEmpty())
69   {
70     t << " height=\"" << convertToXML(height) << "\"";
71   }
72   if (doCaption)
73   {
74     t << " caption=\"";
75     visitCaption(parent, children);
76     t << "\"";
77   }
78   t << ">";
79 }
80
81 static void visitPostEnd(FTextStream &t, const char *cmd)
82 {
83   t << "</" << cmd << ">" << endl;
84 }
85
86 XmlDocVisitor::XmlDocVisitor(FTextStream &t,CodeOutputInterface &ci) 
87   : DocVisitor(DocVisitor_XML), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE) 
88 {
89 }
90
91   //--------------------------------------
92   // visitor functions for leaf nodes
93   //--------------------------------------
94
95 void XmlDocVisitor::visit(DocWord *w)
96 {
97   if (m_hide) return;
98   filter(w->word());
99 }
100
101 void XmlDocVisitor::visit(DocLinkedWord *w)
102 {
103   if (m_hide) return;
104   startLink(w->ref(),w->file(),w->anchor());
105   filter(w->word());
106   endLink();
107 }
108
109 void XmlDocVisitor::visit(DocWhiteSpace *w)
110 {
111   if (m_hide) return;
112   if (m_insidePre)
113   {
114     m_t << w->chars();
115   }
116   else
117   {
118     m_t << " ";
119   }
120 }
121
122 void XmlDocVisitor::visit(DocSymbol *s)
123 {
124   if (m_hide) return;
125   const char *res = HtmlEntityMapper::instance()->xml(s->symbol());
126   if (res)
127   {
128     m_t << res;
129   }
130   else
131   {
132     err("XML: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
133   }
134 }
135
136 void XmlDocVisitor::visit(DocURL *u)
137 {
138   if (m_hide) return;
139   m_t << "<ulink url=\""; 
140   if (u->isEmail()) m_t << "mailto:";
141   filter(u->url());
142   m_t << "\">";
143   filter(u->url());
144   m_t << "</ulink>";
145 }
146
147 void XmlDocVisitor::visit(DocLineBreak *)
148 {
149   if (m_hide) return;
150   m_t << "<linebreak/>\n";
151 }
152
153 void XmlDocVisitor::visit(DocHorRuler *)
154 {
155   if (m_hide) return;
156   m_t << "<hruler/>\n";
157 }
158
159 void XmlDocVisitor::visit(DocStyleChange *s)
160 {
161   if (m_hide) return;
162   switch (s->style())
163   {
164     case DocStyleChange::Bold:
165       if (s->enable()) m_t << "<bold>";      else m_t << "</bold>";
166       break;
167     case DocStyleChange::Italic:
168       if (s->enable()) m_t << "<emphasis>";     else m_t << "</emphasis>";
169       break;
170     case DocStyleChange::Code:
171       if (s->enable()) m_t << "<computeroutput>";   else m_t << "</computeroutput>";
172       break;
173     case DocStyleChange::Subscript:
174       if (s->enable()) m_t << "<subscript>";    else m_t << "</subscript>";
175       break;
176     case DocStyleChange::Superscript:
177       if (s->enable()) m_t << "<superscript>";    else m_t << "</superscript>";
178       break;
179     case DocStyleChange::Center:
180       if (s->enable()) m_t << "<center>"; else m_t << "</center>";
181       break;
182     case DocStyleChange::Small:
183       if (s->enable()) m_t << "<small>";  else m_t << "</small>";
184       break;
185     case DocStyleChange::Preformatted:
186       if (s->enable()) 
187       {
188         m_t << "<preformatted>";  
189         m_insidePre=TRUE;
190       }
191       else 
192       {
193         m_t << "</preformatted>";
194         m_insidePre=FALSE;
195       }
196       break;
197     case DocStyleChange::Div:  /* HTML only */ break;
198     case DocStyleChange::Span: /* HTML only */ break;
199   }
200 }
201
202 void XmlDocVisitor::visit(DocVerbatim *s)
203 {
204   if (m_hide) return;
205   QCString lang = m_langExt;
206   if (!s->language().isEmpty()) // explicit language setting
207   {
208     lang = s->language();
209   }
210   SrcLangExt langExt = getLanguageFromFileName(lang);
211   switch(s->type())
212   {
213     case DocVerbatim::Code: // fall though
214       m_t << "<programlisting";
215       if (!s->language().isEmpty())
216           m_t << " filename=\"" << lang << "\">";
217       else
218           m_t << ">";
219       Doxygen::parserManager->getParser(lang)
220                             ->parseCode(m_ci,s->context(),s->text(),langExt,
221                                         s->isExample(),s->exampleFile());
222       m_t << "</programlisting>"; 
223       break;
224     case DocVerbatim::Verbatim: 
225       m_t << "<verbatim>";
226       filter(s->text());
227       m_t << "</verbatim>"; 
228       break;
229     case DocVerbatim::HtmlOnly: 
230     case DocVerbatim::RtfOnly: 
231     case DocVerbatim::ManOnly: 
232     case DocVerbatim::LatexOnly: 
233     case DocVerbatim::DocbookOnly:
234       /* nothing */ 
235       break;
236     case DocVerbatim::XmlOnly: 
237       m_t << s->text();
238       break;
239     case DocVerbatim::Dot:
240       visitPreStart(m_t, "dot", s->hasCaption(), this, s->children(), QCString(""), FALSE, DocImage::Html, s->width(), s->height());
241       filter(s->text());
242       visitPostEnd(m_t, "dot");
243       break;
244     case DocVerbatim::Msc:
245       visitPreStart(m_t, "msc", s->hasCaption(), this, s->children(),  QCString(""), FALSE, DocImage::Html, s->width(), s->height());
246       filter(s->text());
247       visitPostEnd(m_t, "msc");
248       break;
249     case DocVerbatim::PlantUML:
250       visitPreStart(m_t, "plantuml", s->hasCaption(), this, s->children(),  QCString(""), FALSE, DocImage::Html, s->width(), s->height());
251       filter(s->text());
252       visitPostEnd(m_t, "plantuml");
253       break;
254   }
255 }
256
257 void XmlDocVisitor::visit(DocAnchor *anc)
258 {
259   if (m_hide) return;
260   m_t << "<anchor id=\"" << anc->file() << "_1" << anc->anchor() << "\"/>";
261 }
262
263 void XmlDocVisitor::visit(DocInclude *inc)
264 {
265   if (m_hide) return;
266   SrcLangExt langExt = getLanguageFromFileName(inc->extension());
267   switch(inc->type())
268   {
269     case DocInclude::IncWithLines:
270       { 
271          m_t << "<programlisting filename=\"" << inc->file() << "\">";
272          QFileInfo cfi( inc->file() );
273          FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
274          Doxygen::parserManager->getParser(inc->extension())
275                                ->parseCode(m_ci,inc->context(),
276                                            inc->text(),
277                                            langExt,
278                                            inc->isExample(),
279                                            inc->exampleFile(),
280                                            &fd,   // fileDef,
281                                            -1,    // start line
282                                            -1,    // end line
283                                            FALSE, // inline fragment
284                                            0,     // memberDef
285                                            TRUE   // show line numbers
286                                            );
287          m_t << "</programlisting>"; 
288       }
289       break;    
290     case DocInclude::Include: 
291       m_t << "<programlisting filename=\"" << inc->file() << "\">";
292       Doxygen::parserManager->getParser(inc->extension())
293                             ->parseCode(m_ci,inc->context(),
294                                         inc->text(),
295                                         langExt,
296                                         inc->isExample(),
297                                         inc->exampleFile(),
298                                         0,     // fileDef
299                                         -1,    // startLine
300                                         -1,    // endLine
301                                         TRUE,  // inlineFragment
302                                         0,     // memberDef
303                                         FALSE  // show line numbers
304                                        );
305       m_t << "</programlisting>"; 
306       break;
307     case DocInclude::DontInclude: 
308       break;
309     case DocInclude::HtmlInclude: 
310       m_t << "<htmlonly>";
311       filter(inc->text());
312       m_t << "</htmlonly>";
313       break;
314     case DocInclude::LatexInclude:
315       m_t << "<latexonly>";
316       filter(inc->text());
317       m_t << "</latexonly>";
318       break;
319     case DocInclude::VerbInclude: 
320       m_t << "<verbatim>";
321       filter(inc->text());
322       m_t << "</verbatim>"; 
323       break;
324     case DocInclude::Snippet:
325       m_t << "<programlisting filename=\"" << inc->file() << "\">";
326       Doxygen::parserManager->getParser(inc->extension())
327                             ->parseCode(m_ci,
328                                         inc->context(),
329                                         extractBlock(inc->text(),inc->blockId()),
330                                         langExt,
331                                         inc->isExample(),
332                                         inc->exampleFile()
333                                        );
334       m_t << "</programlisting>"; 
335       break;
336     case DocInclude::SnipWithLines:
337       {
338          m_t << "<programlisting filename=\"" << inc->file() << "\">";
339          QFileInfo cfi( inc->file() );
340          FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
341          Doxygen::parserManager->getParser(inc->extension())
342                                ->parseCode(m_ci,
343                                            inc->context(),
344                                            extractBlock(inc->text(),inc->blockId()),
345                                            langExt,
346                                            inc->isExample(),
347                                            inc->exampleFile(), 
348                                            &fd,
349                                            lineBlock(inc->text(),inc->blockId()),
350                                            -1,    // endLine
351                                            FALSE, // inlineFragment
352                                            0,     // memberDef
353                                            TRUE   // show line number
354                                           );
355          m_t << "</programlisting>"; 
356       }
357       break;
358     case DocInclude::SnippetDoc: 
359     case DocInclude::IncludeDoc: 
360       err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
361           "Please create a bug report\n",__FILE__);
362       break;
363   }
364 }
365
366 void XmlDocVisitor::visit(DocIncOperator *op)
367 {
368   //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
369   //    op->type(),op->isFirst(),op->isLast(),op->text().data());
370   if (op->isFirst()) 
371   {
372     if (!m_hide)
373     {
374       m_t << "<programlisting filename=\"" << op->includeFileName() << "\">";
375     }
376     pushEnabled();
377     m_hide = TRUE;
378   }
379   SrcLangExt langExt = getLanguageFromFileName(m_langExt);
380   if (op->type()!=DocIncOperator::Skip) 
381   {
382     popEnabled();
383     if (!m_hide) 
384     {
385       Doxygen::parserManager->getParser(m_langExt)
386                             ->parseCode(m_ci,op->context(),
387                                         op->text(),langExt,op->isExample(),
388                                         op->exampleFile());
389     }
390     pushEnabled();
391     m_hide=TRUE;
392   }
393   if (op->isLast())  
394   {
395     popEnabled();
396     if (!m_hide) m_t << "</programlisting>"; 
397   }
398   else
399   {
400     if (!m_hide) m_t << endl;
401   }
402 }
403
404 void XmlDocVisitor::visit(DocFormula *f)
405 {
406   if (m_hide) return;
407   m_t << "<formula id=\"" << f->id() << "\">";
408   filter(f->text());
409   m_t << "</formula>";
410 }
411
412 void XmlDocVisitor::visit(DocIndexEntry *ie)
413 {
414   if (m_hide) return;
415   m_t << "<indexentry>"
416            "<primaryie>";
417   filter(ie->entry());
418   m_t << "</primaryie>"
419            "<secondaryie></secondaryie>"
420          "</indexentry>";
421 }
422
423 void XmlDocVisitor::visit(DocSimpleSectSep *sep)
424 {
425   if (sep->parent() && sep->parent()->kind()==DocNode::Kind_SimpleSect)
426   {
427     visitPost((DocSimpleSect*)sep->parent()); // end current section
428     visitPre((DocSimpleSect*)sep->parent());  // start new section
429   }
430 }
431
432 void XmlDocVisitor::visit(DocCite *cite)
433 {
434   if (m_hide) return;
435   if (!cite->file().isEmpty()) startLink(cite->ref(),cite->file(),cite->anchor());
436   filter(cite->text());
437   if (!cite->file().isEmpty()) endLink();
438 }
439
440 //--------------------------------------
441 // visitor functions for compound nodes
442 //--------------------------------------
443
444 void XmlDocVisitor::visitPre(DocAutoList *l)
445 {
446   if (m_hide) return;
447   if (l->isEnumList())
448   {
449     m_t << "<orderedlist>\n";
450   }
451   else
452   {
453     m_t << "<itemizedlist>\n";
454   }
455 }
456
457 void XmlDocVisitor::visitPost(DocAutoList *l)
458 {
459   if (m_hide) return;
460   if (l->isEnumList())
461   {
462     m_t << "</orderedlist>\n";
463   }
464   else
465   {
466     m_t << "</itemizedlist>\n";
467   }
468 }
469
470 void XmlDocVisitor::visitPre(DocAutoListItem *)
471 {
472   if (m_hide) return;
473   m_t << "<listitem>";
474 }
475
476 void XmlDocVisitor::visitPost(DocAutoListItem *) 
477 {
478   if (m_hide) return;
479   m_t << "</listitem>";
480 }
481
482 void XmlDocVisitor::visitPre(DocPara *) 
483 {
484   if (m_hide) return;
485   m_t << "<para>";
486 }
487
488 void XmlDocVisitor::visitPost(DocPara *)
489 {
490   if (m_hide) return;
491   m_t << "</para>";
492 }
493
494 void XmlDocVisitor::visitPre(DocRoot *)
495 {
496   //m_t << "<hr><h4><font color=\"red\">New parser:</font></h4>\n";
497 }
498
499 void XmlDocVisitor::visitPost(DocRoot *)
500 {
501   //m_t << "<hr><h4><font color=\"red\">Old parser:</font></h4>\n";
502 }
503
504 void XmlDocVisitor::visitPre(DocSimpleSect *s)
505 {
506   if (m_hide) return;
507   m_t << "<simplesect kind=\"";
508   switch(s->type())
509   {
510     case DocSimpleSect::See: 
511       m_t << "see"; break;
512     case DocSimpleSect::Return: 
513       m_t << "return"; break;
514     case DocSimpleSect::Author: 
515       m_t << "author"; break;
516     case DocSimpleSect::Authors: 
517       m_t << "authors"; break;
518     case DocSimpleSect::Version: 
519       m_t << "version"; break;
520     case DocSimpleSect::Since: 
521       m_t << "since"; break;
522     case DocSimpleSect::Date: 
523       m_t << "date"; break;
524     case DocSimpleSect::Note: 
525       m_t << "note"; break;
526     case DocSimpleSect::Warning:
527       m_t << "warning"; break;
528     case DocSimpleSect::Pre:
529       m_t << "pre"; break;
530     case DocSimpleSect::Post:
531       m_t << "post"; break;
532     case DocSimpleSect::Copyright:
533       m_t << "copyright"; break;
534     case DocSimpleSect::Invar:
535       m_t << "invariant"; break;
536     case DocSimpleSect::Remark:
537       m_t << "remark"; break;
538     case DocSimpleSect::Attention:
539       m_t << "attention"; break;
540     case DocSimpleSect::User: 
541       m_t << "par"; break;
542     case DocSimpleSect::Rcs: 
543       m_t << "rcs"; break;
544     case DocSimpleSect::Unknown:  break;
545   }
546   m_t << "\">";
547 }
548
549 void XmlDocVisitor::visitPost(DocSimpleSect *)
550 {
551   if (m_hide) return;
552   m_t << "</simplesect>\n";
553 }
554
555 void XmlDocVisitor::visitPre(DocTitle *)
556 {
557   if (m_hide) return;
558   m_t << "<title>";
559 }
560
561 void XmlDocVisitor::visitPost(DocTitle *)
562 {
563   if (m_hide) return;
564   m_t << "</title>";
565 }
566
567 void XmlDocVisitor::visitPre(DocSimpleList *)
568 {
569   if (m_hide) return;
570   m_t << "<itemizedlist>\n";
571 }
572
573 void XmlDocVisitor::visitPost(DocSimpleList *)
574 {
575   if (m_hide) return;
576   m_t << "</itemizedlist>\n";
577 }
578
579 void XmlDocVisitor::visitPre(DocSimpleListItem *)
580 {
581   if (m_hide) return;
582   m_t << "<listitem>";
583 }
584
585 void XmlDocVisitor::visitPost(DocSimpleListItem *) 
586 {
587   if (m_hide) return;
588   m_t << "</listitem>\n";
589 }
590
591 void XmlDocVisitor::visitPre(DocSection *s)
592 {
593   if (m_hide) return;
594   m_t << "<sect" << s->level() << " id=\"" << s->file();
595   if (!s->anchor().isEmpty()) m_t << "_1" << s->anchor();
596   m_t << "\">" << endl;
597   m_t << "<title>";
598   filter(convertCharEntitiesToUTF8(s->title()));
599   m_t << "</title>" << endl;
600 }
601
602 void XmlDocVisitor::visitPost(DocSection *s) 
603 {
604   m_t << "</sect" << s->level() << ">\n";
605 }
606
607 void XmlDocVisitor::visitPre(DocHtmlList *s)
608 {
609   if (m_hide) return;
610   if (s->type()==DocHtmlList::Ordered) 
611     m_t << "<orderedlist>\n"; 
612   else 
613     m_t << "<itemizedlist>\n";
614 }
615
616 void XmlDocVisitor::visitPost(DocHtmlList *s) 
617 {
618   if (m_hide) return;
619   if (s->type()==DocHtmlList::Ordered) 
620     m_t << "</orderedlist>\n"; 
621   else 
622     m_t << "</itemizedlist>\n";
623 }
624
625 void XmlDocVisitor::visitPre(DocHtmlListItem *)
626 {
627   if (m_hide) return;
628   m_t << "<listitem>\n";
629 }
630
631 void XmlDocVisitor::visitPost(DocHtmlListItem *) 
632 {
633   if (m_hide) return;
634   m_t << "</listitem>\n";
635 }
636
637 void XmlDocVisitor::visitPre(DocHtmlDescList *)
638 {
639   if (m_hide) return;
640   m_t << "<variablelist>\n";
641 }
642
643 void XmlDocVisitor::visitPost(DocHtmlDescList *) 
644 {
645   if (m_hide) return;
646   m_t << "</variablelist>\n";
647 }
648
649 void XmlDocVisitor::visitPre(DocHtmlDescTitle *)
650 {
651   if (m_hide) return;
652   m_t << "<varlistentry><term>";
653 }
654
655 void XmlDocVisitor::visitPost(DocHtmlDescTitle *) 
656 {
657   if (m_hide) return;
658   m_t << "</term></varlistentry>\n";
659 }
660
661 void XmlDocVisitor::visitPre(DocHtmlDescData *)
662 {
663   if (m_hide) return;
664   m_t << "<listitem>";
665 }
666
667 void XmlDocVisitor::visitPost(DocHtmlDescData *) 
668 {
669   if (m_hide) return;
670   m_t << "</listitem>\n";
671 }
672
673 void XmlDocVisitor::visitPre(DocHtmlTable *t)
674 {
675   if (m_hide) return;
676   m_t << "<table rows=\"" << t->numRows() 
677       << "\" cols=\"" << t->numColumns() << "\">" ;
678 }
679
680 void XmlDocVisitor::visitPost(DocHtmlTable *) 
681 {
682   if (m_hide) return;
683   m_t << "</table>\n";
684 }
685
686 void XmlDocVisitor::visitPre(DocHtmlRow *)
687 {
688   if (m_hide) return;
689   m_t << "<row>\n";
690 }
691
692 void XmlDocVisitor::visitPost(DocHtmlRow *) 
693 {
694   if (m_hide) return;
695   m_t << "</row>\n";
696 }
697
698 void XmlDocVisitor::visitPre(DocHtmlCell *c)
699 {
700   if (m_hide) return;
701   if (c->isHeading()) m_t << "<entry thead=\"yes\">"; else m_t << "<entry thead=\"no\">";
702 }
703
704 void XmlDocVisitor::visitPost(DocHtmlCell *) 
705 {
706   if (m_hide) return;
707   m_t << "</entry>"; 
708 }
709
710 void XmlDocVisitor::visitPre(DocHtmlCaption *)
711 {
712   if (m_hide) return;
713   m_t << "<caption>";
714 }
715
716 void XmlDocVisitor::visitPost(DocHtmlCaption *) 
717 {
718   if (m_hide) return;
719   m_t << "</caption>\n";
720 }
721
722 void XmlDocVisitor::visitPre(DocInternal *)
723 {
724   if (m_hide) return;
725   m_t << "<internal>";
726 }
727
728 void XmlDocVisitor::visitPost(DocInternal *) 
729 {
730   if (m_hide) return;
731   m_t << "</internal>" << endl;
732 }
733
734 void XmlDocVisitor::visitPre(DocHRef *href)
735 {
736   if (m_hide) return;
737   m_t << "<ulink url=\"";
738   filter(href->url());
739   m_t << "\">";
740 }
741
742 void XmlDocVisitor::visitPost(DocHRef *) 
743 {
744   if (m_hide) return;
745   m_t << "</ulink>";
746 }
747
748 void XmlDocVisitor::visitPre(DocHtmlHeader *header)
749 {
750   if (m_hide) return;
751   m_t << "<heading level=\"" << header->level() << "\">";
752 }
753
754 void XmlDocVisitor::visitPost(DocHtmlHeader *) 
755 {
756   if (m_hide) return;
757   m_t << "</heading>\n";
758 }
759
760 void XmlDocVisitor::visitPre(DocImage *img)
761 {
762   if (m_hide) return;
763
764   QCString baseName=img->name();
765   int i;
766   if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1)
767   {
768     baseName=baseName.right(baseName.length()-i-1);
769   }
770   visitPreStart(m_t, "image", FALSE, this, img->children(), baseName, TRUE, img->type(), img->width(), img->height());
771
772   // copy the image to the output dir
773   FileDef *fd;
774   bool ambig;
775   if ((fd=findFileDef(Doxygen::imageNameDict,img->name(),ambig)))
776   {
777     QFile inImage(fd->absFilePath());
778     QFile outImage(Config_getString(XML_OUTPUT)+"/"+baseName.data());
779     if (inImage.open(IO_ReadOnly))
780     {
781       if (outImage.open(IO_WriteOnly))
782       {
783         char *buffer = new char[inImage.size()];
784         inImage.readBlock(buffer,inImage.size());
785         outImage.writeBlock(buffer,inImage.size());
786         outImage.flush();
787         delete[] buffer;
788       }
789     }
790   }
791 }
792
793 void XmlDocVisitor::visitPost(DocImage *) 
794 {
795   if (m_hide) return;
796   visitPostEnd(m_t, "image");
797 }
798
799 void XmlDocVisitor::visitPre(DocDotFile *df)
800 {
801   if (m_hide) return;
802   visitPreStart(m_t, "dotfile", FALSE, this, df->children(), df->file(), FALSE, DocImage::Html, df->width(), df->height());
803 }
804
805 void XmlDocVisitor::visitPost(DocDotFile *) 
806 {
807   if (m_hide) return;
808   visitPostEnd(m_t, "dotfile");
809 }
810
811 void XmlDocVisitor::visitPre(DocMscFile *df)
812 {
813   if (m_hide) return;
814   visitPreStart(m_t, "mscfile", FALSE, this, df->children(), df->file(), FALSE, DocImage::Html, df->width(), df->height());
815 }
816
817 void XmlDocVisitor::visitPost(DocMscFile *) 
818 {
819   if (m_hide) return;
820   visitPostEnd(m_t, "mscfile");
821 }
822
823 void XmlDocVisitor::visitPre(DocDiaFile *df)
824 {
825   if (m_hide) return;
826   visitPreStart(m_t, "diafile", FALSE, this, df->children(), df->file(), FALSE, DocImage::Html, df->width(), df->height());
827 }
828
829 void XmlDocVisitor::visitPost(DocDiaFile *)
830 {
831   if (m_hide) return;
832   visitPostEnd(m_t, "diafile");
833 }
834
835 void XmlDocVisitor::visitPre(DocLink *lnk)
836 {
837   if (m_hide) return;
838   startLink(lnk->ref(),lnk->file(),lnk->anchor());
839 }
840
841 void XmlDocVisitor::visitPost(DocLink *) 
842 {
843   if (m_hide) return;
844   endLink();
845 }
846
847 void XmlDocVisitor::visitPre(DocRef *ref)
848 {
849   if (m_hide) return;
850   if (!ref->file().isEmpty()) 
851   {
852     startLink(ref->ref(),ref->file(),ref->isSubPage() ? QCString() : ref->anchor());
853   }
854   if (!ref->hasLinkText()) filter(ref->targetTitle());
855 }
856
857 void XmlDocVisitor::visitPost(DocRef *ref) 
858 {
859   if (m_hide) return;
860   if (!ref->file().isEmpty()) endLink();
861   //m_t << " ";
862 }
863
864 void XmlDocVisitor::visitPre(DocSecRefItem *ref)
865 {
866   if (m_hide) return;
867   m_t << "<tocitem id=\"" << ref->file() << "_1" << ref->anchor() << "\">";
868 }
869
870 void XmlDocVisitor::visitPost(DocSecRefItem *) 
871 {
872   if (m_hide) return;
873   m_t << "</tocitem>" << endl;
874 }
875
876 void XmlDocVisitor::visitPre(DocSecRefList *)
877 {
878   if (m_hide) return;
879   m_t << "<toclist>" << endl;
880 }
881
882 void XmlDocVisitor::visitPost(DocSecRefList *) 
883 {
884   if (m_hide) return;
885   m_t << "</toclist>" << endl;
886 }
887
888 //void XmlDocVisitor::visitPre(DocLanguage *l)
889 //{
890 //  if (m_hide) return;
891 //  m_t << "<language langid=\"" << l->id() << "\">";
892 //}
893 //
894 //void XmlDocVisitor::visitPost(DocLanguage *) 
895 //{
896 //  if (m_hide) return;
897 //  m_t << "</language>" << endl;
898 //}
899
900 void XmlDocVisitor::visitPre(DocParamSect *s)
901 {
902   if (m_hide) return;
903   m_t << "<parameterlist kind=\"";
904   switch(s->type())
905   {
906     case DocParamSect::Param: 
907       m_t << "param"; break;
908     case DocParamSect::RetVal: 
909       m_t << "retval"; break;
910     case DocParamSect::Exception: 
911       m_t << "exception"; break;
912     case DocParamSect::TemplateParam: 
913       m_t << "templateparam"; break;
914     default:
915       ASSERT(0);
916   }
917   m_t << "\">";
918 }
919
920 void XmlDocVisitor::visitPost(DocParamSect *)
921 {
922   if (m_hide) return;
923   m_t << "</parameterlist>" << endl;
924 }
925
926 void XmlDocVisitor::visitPre(DocParamList *pl)
927 {
928   if (m_hide) return;
929   m_t << "<parameteritem>" << endl;
930   m_t << "<parameternamelist>" << endl;
931   //QStrListIterator li(pl->parameters());
932   //const char *s;
933   QListIterator<DocNode> li(pl->parameters());
934   DocNode *param;
935   for (li.toFirst();(param=li.current());++li)
936   {
937     if (pl->paramTypes().count()>0)
938     {
939       QListIterator<DocNode> li(pl->paramTypes());
940       DocNode *type;
941       for (li.toFirst();(type=li.current());++li)
942       {
943         m_t << "<parametertype>";
944         if (type->kind()==DocNode::Kind_Word)
945         {
946           visit((DocWord*)type); 
947         }
948         else if (type->kind()==DocNode::Kind_LinkedWord)
949         {
950           visit((DocLinkedWord*)type); 
951         }
952         m_t << "</parametertype>" << endl;
953       }
954     }
955     m_t << "<parametername";
956     if (pl->direction()!=DocParamSect::Unspecified)
957     {
958       m_t << " direction=\"";
959       if (pl->direction()==DocParamSect::In)
960       {
961         m_t << "in";
962       }
963       else if (pl->direction()==DocParamSect::Out)
964       {
965         m_t << "out";
966       }
967       else if (pl->direction()==DocParamSect::InOut)
968       {
969         m_t << "inout";
970       }
971       m_t << "\"";
972     }
973     m_t << ">";
974     if (param->kind()==DocNode::Kind_Word)
975     {
976       visit((DocWord*)param); 
977     }
978     else if (param->kind()==DocNode::Kind_LinkedWord)
979     {
980       visit((DocLinkedWord*)param); 
981     }
982     m_t << "</parametername>" << endl;
983   }
984   m_t << "</parameternamelist>" << endl;
985   m_t << "<parameterdescription>" << endl;
986 }
987
988 void XmlDocVisitor::visitPost(DocParamList *)
989 {
990   if (m_hide) return;
991   m_t << "</parameterdescription>" << endl;
992   m_t << "</parameteritem>" << endl;
993 }
994
995 void XmlDocVisitor::visitPre(DocXRefItem *x)
996 {
997   if (m_hide) return;
998   if (x->title().isEmpty()) return;
999   m_t << "<xrefsect id=\"";
1000   m_t << x->file() << "_1" << x->anchor();
1001   m_t << "\">";
1002   m_t << "<xreftitle>";
1003   filter(x->title());
1004   m_t << "</xreftitle>";
1005   m_t << "<xrefdescription>";
1006 }
1007
1008 void XmlDocVisitor::visitPost(DocXRefItem *x)
1009 {
1010   if (m_hide) return;
1011   if (x->title().isEmpty()) return;
1012   m_t << "</xrefdescription>";
1013   m_t << "</xrefsect>";
1014 }
1015
1016 void XmlDocVisitor::visitPre(DocInternalRef *ref)
1017 {
1018   if (m_hide) return;
1019   startLink(0,ref->file(),ref->anchor());
1020 }
1021
1022 void XmlDocVisitor::visitPost(DocInternalRef *) 
1023 {
1024   if (m_hide) return;
1025   endLink();
1026   m_t << " ";
1027 }
1028
1029 void XmlDocVisitor::visitPre(DocCopy *c)
1030 {
1031   if (m_hide) return;
1032   m_t << "<copydoc link=\"" << convertToXML(c->link()) << "\">";
1033 }
1034
1035 void XmlDocVisitor::visitPost(DocCopy *)
1036 {
1037   if (m_hide) return;
1038   m_t << "</copydoc>" << endl;
1039 }
1040
1041 void XmlDocVisitor::visitPre(DocText *)
1042 {
1043 }
1044
1045 void XmlDocVisitor::visitPost(DocText *)
1046 {
1047 }
1048
1049 void XmlDocVisitor::visitPre(DocHtmlBlockQuote *)
1050 {
1051   if (m_hide) return;
1052   m_t << "<blockquote>";
1053 }
1054
1055 void XmlDocVisitor::visitPost(DocHtmlBlockQuote *)
1056 {
1057   if (m_hide) return;
1058   m_t << "</blockquote>";
1059 }
1060
1061 void XmlDocVisitor::visitPre(DocVhdlFlow *)
1062 {
1063 }
1064
1065 void XmlDocVisitor::visitPost(DocVhdlFlow *)
1066 {
1067 }
1068
1069 void XmlDocVisitor::visitPre(DocParBlock *)
1070 {
1071   if (m_hide) return;
1072   m_t << "<parblock>";
1073 }
1074
1075 void XmlDocVisitor::visitPost(DocParBlock *)
1076 {
1077   if (m_hide) return;
1078   m_t << "</parblock>";
1079 }
1080
1081
1082 void XmlDocVisitor::filter(const char *str)
1083
1084   m_t << convertToXML(str);
1085 }
1086
1087 void XmlDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor)
1088 {
1089   //printf("XmlDocVisitor: file=%s anchor=%s\n",file.data(),anchor.data());
1090   m_t << "<ref refid=\"" << file;
1091   if (!anchor.isEmpty()) m_t << "_1" << anchor;
1092   m_t << "\" kindref=\"";
1093   if (!anchor.isEmpty()) m_t << "member"; else m_t << "compound";
1094   m_t << "\"";
1095   if (!ref.isEmpty()) m_t << " external=\"" << ref << "\"";
1096   m_t << ">";
1097 }
1098
1099 void XmlDocVisitor::endLink()
1100 {
1101   m_t << "</ref>";
1102 }
1103
1104 void XmlDocVisitor::pushEnabled()
1105 {
1106   m_enabled.push(new bool(m_hide));
1107 }
1108
1109 void XmlDocVisitor::popEnabled()
1110 {
1111   bool *v=m_enabled.pop();
1112   ASSERT(v!=0);
1113   m_hide = *v;
1114   delete v;
1115 }
1116