* Bug 15259 fixed: <latex alt='..'> provides formula as text
[scilab.git] / scilab / modules / helptools / src / java / org / scilab / modules / helptools / HTMLDocbookTagConverter.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - Calixte DENIZET
4  * Copyright (C) 2016 - 2018 - Samuel GOUGEON
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.helptools;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.Date;
24 import java.util.Map;
25 import java.util.Stack;
26 import java.util.regex.Pattern;
27
28 import org.scilab.modules.commons.ScilabCommonsUtils;
29 import org.scilab.modules.helptools.XML.HTMLXMLCodeHandler;
30 import org.scilab.modules.helptools.XML.XMLLexer;
31 import org.scilab.modules.helptools.c.CLexer;
32 import org.scilab.modules.helptools.c.HTMLCCodeHandler;
33 import org.scilab.modules.helptools.external.HTMLMathMLHandler;
34 import org.scilab.modules.helptools.external.HTMLSVGHandler;
35 import org.scilab.modules.helptools.external.HTMLScilabHandler;
36 import org.scilab.modules.helptools.image.Image;
37 import org.scilab.modules.helptools.image.ImageConverter;
38 import org.scilab.modules.helptools.java.JavaLexer;
39 import org.scilab.modules.helptools.scilab.AbstractScilabCodeHandler;
40 import org.scilab.modules.helptools.scilab.HTMLScilabCodeHandler;
41 import org.scilab.modules.helptools.scilab.ScilabLexer;
42 import org.scilab.modules.localization.Messages;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
45
46 /**
47  * Class to convert DocBook to HTML
48  * @author Calixte DENIZET
49  */
50 public class HTMLDocbookTagConverter extends DocbookTagConverter implements TemplateFiller {
51
52     public static enum GenerationType { WEB, JAVAHELP, CHM, HTML };
53
54     private static final String SCILAB_URI = "http://www.scilab.org";
55     private static final String LATEXBASENAME = "_LaTeX_";
56     private static final String VERSION = Messages.gettext("Version");
57     private static final String DESCRIPTION = Messages.gettext("Description");
58
59     private final StringBuilder buffer = new StringBuilder(8192);
60     private int latexCompt = 1;
61     private boolean hasExamples;
62     private int warnings;
63     private int nbFiles;
64
65     private final String imageDir;
66     protected String urlBase;
67     protected boolean linkToTheWeb;
68     protected final String outName;
69     protected String outImages;
70
71     protected final Map<String, String> mapId;
72     protected final Map<String, String> tocitem;
73     protected final HTMLDocbookLinkResolver.TreeId tree;
74     protected final Map<String, HTMLDocbookLinkResolver.TreeId> mapTreeId;
75     protected final Map<String, String> mapIdPurpose;
76     protected final Map<String, String> mapIdRefname;
77
78     protected final TemplateHandler templateHandler;
79
80     protected final ScilabLexer scilabLexer;
81     protected final XMLLexer xmlLexer;
82     protected final CLexer cLexer;
83     protected final JavaLexer javaLexer;
84
85     protected String bookTitle = "";
86     protected String partTitle = "";
87     protected String chapterTitle = "";
88     protected String sectionTitle = "";
89     protected String fileSubtitle = "";
90
91     protected String refpurpose = "";
92     protected String refname = "";
93     protected String version;
94     protected String appendToProgramListing;
95     protected String appendForExecToProgramListing;
96     protected String prependToProgramListing;
97     protected String currentId;
98     protected String indexFilename = "index" /*UUID.randomUUID().toString()*/ + ".html";
99     protected final String language;
100
101     protected final boolean isToolbox;
102     protected final Backend type;
103
104     /**
105      * Constructor
106      * @param inName the name of the input stream
107      * @param sciDocMain provide useful doc generation properties
108      * @param imgConvert the shared image converter for all generation
109      */
110     public HTMLDocbookTagConverter(String inName, SciDocMain sciDocMain, ImageConverter imgConvert) throws IOException, SAXException {
111         super(inName, imgConvert);
112
113         this.version = sciDocMain.getConf().getVersion();
114         this.imageDir = sciDocMain.getImagedir();
115         this.outName = sciDocMain.getOutputDirectory() + File.separator;
116         this.outImages = this.outName;
117
118         imgConvert.setDocbookTagConverter(this);
119         HTMLDocbookLinkResolver resolver = new HTMLDocbookLinkResolver(inName);
120
121         mapId = resolver.getMapId();
122         tocitem = resolver.getToc();
123         tree = resolver.getTree();
124         mapTreeId = resolver.getMapTreeId();
125         mapIdPurpose = resolver.getMapIdPurpose();
126         mapIdRefname = resolver.getMapIdRefname();
127
128         this.isToolbox = sciDocMain.isToolbox();
129         this.language = sciDocMain.getLanguage();
130         this.type = sciDocMain.getFormat();
131
132         if (isToolbox) {
133             urlBase = sciDocMain.getConf().getWebSiteURL() + language + "/";
134             linkToTheWeb = true;
135         } else {
136             urlBase = null;
137             linkToTheWeb = false;
138         }
139
140         if (isToolbox) {// we generate a toolbox's help
141             HTMLScilabCodeHandler.setLinkWriter(new AbstractScilabCodeHandler.LinkWriter() {
142                 public String getLink(String id) {
143                     if (id.length() > 0 && id.charAt(0) == '%') {
144                         id = id.replace("%", "percent");
145                     }
146                     String link = mapId.get(id);
147                     if (link == null) {
148                         return HTMLDocbookTagConverter.this.urlBase + id;
149                     } else {
150                         return link;
151                     }
152                 }
153             });
154         } else {// we generate Scilab's help
155             HTMLScilabCodeHandler.setLinkWriter(new AbstractScilabCodeHandler.LinkWriter() {
156                 public String getLink(String id) {
157                     if (id.length() > 0 && id.charAt(0) == '%') {
158                         id = id.replace("%", "percent");
159                     }
160                     return mapId.get(id);
161                 }
162             });
163         }
164
165         scilabLexer = new ScilabLexer(sciDocMain.getConf().getBuiltins(), sciDocMain.getConf().getMacros());
166         xmlLexer = new XMLLexer();
167         cLexer = new CLexer();
168         javaLexer = new JavaLexer();
169
170         final String template = sciDocMain.getConf().getTemplate(sciDocMain.getFormat().toString().toLowerCase());
171         File tpl = new File(template);
172         if (!tpl.isFile()) {
173             final String msg = "Could not find template document: " + template;
174             System.err.println(msg);
175             throw new RuntimeException();
176         }
177         templateHandler = new TemplateHandler(this, tpl, language);
178     }
179
180     public static boolean containsCJK(CharSequence seq) {
181         if (seq == null) {
182             return false;
183         }
184
185         for (int i = 0; i < seq.length(); i++) {
186             Character.UnicodeBlock block = Character.UnicodeBlock.of(seq.charAt(i));
187             if (block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
188                     || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
189                     || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
190                     || block == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS
191                     || block == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
192                     || block == Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT
193                     || block == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
194                     || block == Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS) {
195                 return true;
196             }
197         }
198
199         return false;
200     }
201
202     public static boolean containsCyrillic(CharSequence seq) {
203         if (seq == null) {
204             return false;
205         }
206
207         for (int i = 0; i < seq.length(); i++) {
208             Character.UnicodeBlock block = Character.UnicodeBlock.of(seq.charAt(i));
209             if (block == Character.UnicodeBlock.CYRILLIC || block == Character.UnicodeBlock.CYRILLIC_SUPPLEMENTARY) {
210                 return true;
211             }
212         }
213
214         return false;
215     }
216
217     /**
218      * Replace special chars
219      */
220     public static final String replaceEntity(final String str) {
221         return str.replaceAll("&", "&amp;").replaceAll("<", "&#0060;").replaceAll(">", "&#0062;").replaceAll("\"", "&#0034;").replaceAll("\'", "&#0039;");
222     }
223
224     /**
225      * Get the type of the generation
226      * @return the generation type
227      */
228     public final Backend getGenerationType() {
229         return type;
230     }
231
232     public String getLanguage() {
233         return language;
234     }
235
236     @Override
237     public void registerAllExternalXMLHandlers() {
238         super.registerAllExternalXMLHandlers();
239
240         registerExternalXMLHandler(new HTMLMathMLHandler(outImages, imageDir));
241         registerExternalXMLHandler(new HTMLSVGHandler(outImages, imageDir));
242         registerExternalXMLHandler(new HTMLScilabHandler(outImages, imageDir));
243     }
244
245     @Override
246     public void install() {
247         super.install();
248
249         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/scilab_code.css"), new File(outName + "/scilab_code.css"));
250         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/xml_code.css"), new File(outName + "/xml_code.css"));
251         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/c_code.css"), new File(outName + "/c_code.css"));
252         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/style.css"), new File(outName + "/style.css"));
253     }
254
255     /**
256      * @return the buffer used
257      */
258     public StringBuilder getBuffer() {
259         return buffer;
260     }
261
262     /**
263      * @param tag the tag name
264      * @param contents the contents to enclose between opening and closing tags
265      */
266     public String encloseContents(final String tag, final String contents) {
267         buffer.setLength(0);
268         buffer.append("<");
269         buffer.append(tag);
270         buffer.append(">");
271         if (contents != null) {
272             buffer.append(contents);
273         }
274         buffer.append("</");
275         buffer.append(tag);
276         buffer.append(">");
277
278         return buffer.toString();
279     }
280
281     /**
282      * @param tag the tag name
283      * @param attrs the attributes {attr1, value1, attr2, value2, ...}
284      * @param contents the contents to enclose between opening and closing tags
285      */
286     public String encloseContents(final String tag, final String[] attrs, final String contents) {
287         buffer.setLength(0);
288         buffer.append("<");
289         buffer.append(tag);
290         if (attrs != null) {
291             for (int i = 0; i < attrs.length; i += 2) {
292                 if (attrs[i + 1] != null && !attrs[i + 1].isEmpty()) {
293                     buffer.append(" ");
294                     buffer.append(attrs[i]);
295                     buffer.append("=\"");
296                     buffer.append(attrs[i + 1]);
297                     buffer.append("\"");
298                 }
299             }
300         }
301
302         buffer.append(">");
303         if (contents != null) {
304             buffer.append(contents);
305         }
306         buffer.append("</");
307         buffer.append(tag);
308         buffer.append(">");
309
310         return buffer.toString();
311     }
312
313     /**
314      * @param tag the tag name
315      * @param clazz the css class name
316      * @param contents the contents to enclose between opening and closing tags
317      */
318     public String encloseContents(final String tag, final String clazz, final String contents) {
319         buffer.setLength(0);
320         buffer.append("<");
321         buffer.append(tag);
322         buffer.append(" class=\"");
323         buffer.append(clazz);
324         buffer.append("\">");
325         if (contents != null) {
326             buffer.append(contents);
327         }
328         buffer.append("</");
329         buffer.append(tag);
330         buffer.append(">");
331
332         return buffer.toString();
333     }
334
335     /**
336      * {@inheritDoc}
337      */
338     public boolean isEscapable(final String tagName, final String uri) {
339         return !"latex".equals(tagName) && !"screen".equals(tagName) && !"programlisting".equals(tagName) && !"code".equals(tagName) && !"synopsis".equals(tagName) && !(uri.equals(SCILAB_URI) && tagName.equals("image"));
340     }
341
342     /**
343      * {@inheritDoc}
344      */
345     public boolean isTrimable(final String tagName) {
346         return !"screen".equals(tagName) && !"programlisting".equals(tagName) && !"code".equals(tagName) && !"synopsis".equals(tagName);
347     }
348
349     /**
350      * @param fileName the file to create
351      * @param subtitle the subtitle of the file
352      * @param contents the contents of the file
353      */
354     public void createHTMLFile(final String id, final String fileName, final String subtitle, final String contents) {
355         if (!hasError) {
356             fileSubtitle = subtitle;
357             nbFiles++;
358             templateHandler.generateFileFromTemplate(outName + fileName, id, contents);
359         }
360     }
361
362
363
364     /**
365      * @param code the code to translate
366      * @param img image information
367      * @param fileName the filename
368      * @param attrs the attribute of the image
369      * @return the HTML code to insert the image
370      */
371     public String generateCode(Image img, String fileName, Map<String, String> attrs, final String tooltipString) {
372         String style = attrs.get("style");
373         String top = "";
374         boolean display = style != null && style.equals("display");
375
376         if (!display) {
377             top = "top:" + img.descent + "px;";
378         }
379
380         String alignAttr = attrs.get("align");
381         String align = "";
382         String div = "div";
383         if (alignAttr != null) {
384             align = " style=\'text-align:" + alignAttr + "\'";
385         } else if (display) {
386             align = " style=\'text-align:center\'";
387         } else {
388             div = "span";
389         }
390
391         return "<" + div + align + "><img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/></" + div + ">";
392     }
393
394     /**
395      * {@inheritDoc}
396      */
397     public String makeTitle(final String id) {
398         if (refname.length() > 0) {
399             return tocitem.get(id);
400         }
401
402         return "";
403     }
404
405     /**
406      * {@inheritDoc}
407      */
408     public String makeSubtitle(final String id) {
409         return fileSubtitle;
410     }
411
412     /**
413      * {@inheritDoc}
414      */
415     public String makePrevious(final String id) {
416         buffer.setLength(0);
417         buffer.append("<span class=\"previous\">");
418         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
419         if (leaf == null) {
420             return "";
421         }
422         HTMLDocbookLinkResolver.TreeId prev = leaf.getPrevious();
423         if (prev.parent != null) {
424             buffer.append("<a href=\"");
425             buffer.append(mapId.get(prev.id));
426             buffer.append("\">&lt;&lt; ");
427             buffer.append(tocitem.get(prev.id));
428             buffer.append("</a></span>\n");
429
430             return buffer.toString();
431         }
432
433         return "";
434     }
435
436     /**
437      * {@inheritDoc}
438      */
439     public String makePath(final String id) {
440         buffer.setLength(0);
441         buffer.append("<span class=\"path\" dir=\"ltr\">");
442         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
443         if (leaf == null) {
444             return "";
445         }
446         String str = tocitem.get(id);
447         leaf = leaf.parent;
448         while (leaf != null && !leaf.isRoot()) {
449             str = "<a href=\"" + mapId.get(leaf.id) + "\">" + tocitem.get(leaf.id) + "</a> &gt; " + str;
450             leaf = leaf.parent;
451         }
452
453         str = "<a href=\"" + indexFilename  + "\">" + bookTitle + "</a> &gt;&gt; " + str;
454         buffer.append(str);
455         buffer.append("</span>\n");
456
457         return buffer.toString();
458     }
459
460     /**
461      * {@inheritDoc}
462      */
463     public String makeTop(final String id) {
464         buffer.setLength(0);
465         buffer.append("<span class=\"top\">");
466         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
467         if (leaf == null) {
468             return "";
469         }
470
471         leaf = leaf.parent;
472         if (leaf != null) {
473             buffer.append("<a href=\"");
474             if (!leaf.isRoot()) {
475                 buffer.append(mapId.get(leaf.id));
476                 buffer.append("\">");
477                 buffer.append(tocitem.get(leaf.id));
478             } else {
479                 buffer.append(indexFilename);
480                 buffer.append("\">");
481                 buffer.append(bookTitle);
482             }
483             buffer.append("</a></span>\n");
484         } else {
485             return "";
486         }
487
488         return buffer.toString();
489     }
490
491     /**
492      * {@inheritDoc}
493      */
494     public String makeNext(final String id) {
495         buffer.setLength(0);
496         buffer.append("<span class=\"next\">");
497         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
498         if (leaf == null) {
499             return "";
500         }
501         HTMLDocbookLinkResolver.TreeId next = leaf.getNext();
502         if (next != null) {
503             buffer.append("<a href=\"");
504             buffer.append(mapId.get(next.id));
505             buffer.append("\">");
506             buffer.append(tocitem.get(next.id));
507             buffer.append(" &gt;&gt;</a></span>\n");
508
509             return buffer.toString();
510         }
511
512         return "";
513     }
514
515     /**
516      * {@inheritDoc}
517      */
518     public String makeStart(final String id) {
519         buffer.setLength(0);
520         buffer.append("<span class=\"start\">");
521         buffer.append("<a href=\"");
522         buffer.append(indexFilename);
523         buffer.append("\">");
524         buffer.append(bookTitle);
525         buffer.append("</a></span>\n");
526
527         return buffer.toString();
528     }
529
530     /**
531      * {@inheritDoc}
532      */
533     public String makeTocList(final String id) {
534         buffer.setLength(0);
535         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
536         if (leaf == null) {
537             return "";
538         }
539
540         HTMLDocbookLinkResolver.TreeId parent = leaf.parent;
541         buffer.append("<ul class=\"toc\">\n");
542         String str = "";
543         while (parent != null && !parent.isRoot()) {
544             str = "<li class=\"parent\"><a href=\"" + mapId.get(parent.id) + "\">" + tocitem.get(parent.id) + "</a></li>\n" + str;
545             parent = parent.parent;
546         }
547         buffer.append("<li class=\"root\"><a href=\"");
548         buffer.append(indexFilename);
549         buffer.append("\">");
550         buffer.append(bookTitle);
551         buffer.append("</a></li>\n");
552         buffer.append(str);
553
554         parent = leaf.parent;
555
556         for (HTMLDocbookLinkResolver.TreeId c : parent.children) {
557             if (c == leaf) {
558                 buffer.append("<li class=\"list-active\"><a href=\"");
559             } else {
560                 buffer.append("<li><a href=\"");
561             }
562             buffer.append(mapId.get(c.id));
563             buffer.append("\">");
564             buffer.append(tocitem.get(c.id));
565             buffer.append("</a></li>\n");
566         }
567         buffer.append("</ul>\n");
568
569         return buffer.toString();
570     }
571
572     /**
573      * {@inheritDoc}
574      */
575     public String makeLastModified(final String id) {
576         buffer.setLength(0);
577         try {
578             buffer.append("<span class=\"lastmodified\">");
579             buffer.append(new Date(new File(new URI(currentFileName)).lastModified()).toString());
580             buffer.append("</span>\n");
581         } catch (URISyntaxException e) {
582             e.printStackTrace();
583         }
584         return buffer.toString();
585     }
586
587     /**
588      * {@inheritDoc}
589      */
590     public String makeGenerationDate(final String id) {
591         buffer.setLength(0);
592         buffer.append("<span class=\"generationdate\">");
593         buffer.append(new Date(System.currentTimeMillis()).toString());
594         buffer.append("</span>\n");
595
596         return buffer.toString();
597     }
598
599     /**
600      * {@inheritDoc}
601      */
602     public String makeVersion(final String id) {
603         buffer.setLength(0);
604         buffer.append("<span class=\"version\">");
605         buffer.append(version);
606         buffer.append("</span>\n");
607
608         return buffer.toString();
609     }
610
611     private boolean isLinkedImage() {
612         Stack<DocbookElement> stack = getStack();
613         return stack.size() >= 3 && stack.get(stack.size() - 3).getName().equals("link");
614     }
615
616     @Override
617     public String generateImageCode(String code, String fileName, Map<String, String> attrs) {
618         String alignAttr = attrs.get("align");
619         boolean addDiv = getGenerationType() != Backend.JAVAHELP || !isLinkedImage();
620         final StringBuilder buffer = new StringBuilder(128);
621         if (addDiv && alignAttr != null) {
622             buffer.append("<div style=\'text-align:").append(alignAttr).append("\'>");
623         }
624         buffer.append("<img src=\'").append(fileName).append("\'/>");
625         if (addDiv && alignAttr != null) {
626             buffer.append("</div>");
627         }
628
629         if (getGenerationType() == Backend.WEB) {
630             /* Prepare the code for the html inclusion */
631             code = convertCode(code);
632             /* Provide a tooltip */
633             return "<div rel='tooltip' title='" + code + "'>" + buffer.toString() + "</div>";
634         } else {
635             /* No tooltip in the javahelp browser ...
636              * too limited html capabilities */
637             return buffer.toString();
638         }
639     }
640
641     @Override
642     public String generateImageCode(Image img, String fileName, Map<String, String> attrs) {
643         String style = attrs.get("style");
644         String top = "";
645         boolean display = style != null && style.equals("display");
646
647         if (!display) {
648             top = "top:" + img.descent + "px;";
649         }
650
651         String alignAttr = attrs.get("align");
652         String align = "";
653         String div = "div";
654         if (alignAttr != null) {
655             align = " style=\'text-align:" + alignAttr + "\'";
656         } else if (display) {
657             align = " style=\'text-align:center\'";
658         } else {
659             div = "span";
660         }
661
662         if (getGenerationType() == Backend.JAVAHELP && isLinkedImage()) {
663             // Java HTML renderer is not good... so when  the image is linked, we remove the div
664             return "<img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/>>";
665         } else {
666             return "<" + div + align + "><img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/></" + div + ">";
667         }
668     }
669
670     @Override
671     public String generateImageCode(String fileName, Map<String, String> attrs) {
672         String idAttr    = attrs.get("id");
673         String alignAttr = attrs.get("align");   // mixes align and valign imagedata attributes
674         String widthAttr = attrs.get("width");
675         String heightAttr= attrs.get("height");  // officially named "depth" as imagedata attribute
676         String styleAttr = attrs.get("style");
677         String altAttr = attrs.get("alt");       // for example: LaTeX content as text
678         boolean addDiv = getGenerationType() != Backend.JAVAHELP || !isLinkedImage();
679         final StringBuilder buffer = new StringBuilder(128);
680         if (addDiv && alignAttr != null) {
681             buffer.append("<div style=\'text-align:").append(alignAttr).append("\'>\n");
682         }
683         buffer.append("<img src=\'").append(fileName).append("\' ");
684         if (!addDiv && alignAttr != null) {
685             buffer.append("align=\'").append(alignAttr).append("\' ");
686         }
687         if (idAttr != null){
688             buffer.append("id=\'").append(idAttr).append("\' ");
689         }
690         if (widthAttr != null){   // To avoid misshaping: setting width priority > setting height
691             buffer.append("width=\'").append(widthAttr).append("\' ");
692         }
693         else {
694             if (heightAttr != null) {
695                 buffer.append("height=\'").append(heightAttr).append("\' ");
696             }
697         }
698         if (styleAttr != null) {
699             buffer.append("style=\'").append(styleAttr).append("\' ");
700         }
701         if (altAttr != null) {
702             altAttr = altAttr.replaceAll("\'", "&apos;").replaceAll("\"", "&quot;");
703             buffer.append("alt=\'").append(altAttr).append("\'");
704         }
705         buffer.append("/>\n");
706         if (addDiv && alignAttr != null) {
707             buffer.append("</div>\n");
708         }
709
710         return buffer.toString();
711     }
712
713     public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
714         latexCompt = 1;
715         return super.resolveEntity(publicId, systemId);
716     }
717
718     /**
719      * Handle a refentry
720      * @param attributes the tag attributes
721      * @param contents the tag contents
722      * @return the HTML code
723      * @throws SAXEception if an error is encountered
724      */
725     public String handleRefentry(final Map<String, String> attributes, final String contents) throws SAXException {
726         String id = attributes.get("id");
727         if (id != null) {
728             currentId = id;
729         }
730         String fileName = mapId.get(currentId);
731         String needsExampleAttr = attributes.get("needs-examples");
732         createHTMLFile(currentId, fileName, refpurpose, contents);
733         if (!hasExamples && (needsExampleAttr == null || !needsExampleAttr.equals("no"))) {
734             warnings++;
735             //System.err.println("Warning (should be fixed): no example in " + currentFileName);
736         } else {
737             hasExamples = false;
738         }
739         String rp = encloseContents("span", "refentry-description", refpurpose);
740         String str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "refentry"}, refname) + " &#8212; " + rp);
741         refpurpose = "";
742         refname = "";
743         currentId = null;
744
745         return str;
746     }
747
748     /**
749      * Handle a section
750      * @param attributes the tag attributes
751      * @param contents the tag contents
752      * @return the HTML code
753      * @throws SAXEception if an error is encountered
754      */
755     public String handleSection(final Map<String, String> attributes, final String contents) throws SAXException {
756         String fileName = attributes.get("id") + ".html";
757         String str = encloseContents("ul", "list-refentry", contents);
758         String title = encloseContents("h3", "title-section", sectionTitle);
759         createHTMLFile(attributes.get("id"), fileName, sectionTitle, title + "\n" + str);
760
761         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "section"}, sectionTitle) + "\n" + str);
762         sectionTitle = "";
763
764         return str;
765     }
766
767     /**
768      * Handle a book
769      * @param attributes the tag attributes
770      * @param contents the tag contents
771      * @return the HTML code
772      * @throws SAXEception if an error is encountered
773      */
774     public String handleBook(final Map<String, String> attributes, final String contents) throws SAXException {
775         String str = encloseContents("ul", "list-part", contents);
776         String btitle;
777         if (bookTitle.trim().equalsIgnoreCase("Scilab")) {
778             btitle = version;
779         } else {
780             btitle = bookTitle;
781         }
782         String title = encloseContents("h3", "book-title", btitle);
783         createHTMLFile("index", indexFilename, btitle, title + "\n" + str);
784
785         if (warnings != 0) {
786             System.err.println("Total files without example: " + warnings);
787             System.err.println("Total generated html files: " + nbFiles);
788         }
789
790         return encloseContents("li", encloseContents("a", new String[] {"href", indexFilename, "class", "part"}, bookTitle) + "\n" + str);
791     }
792
793     /**
794      * Handle a part
795      * @param attributes the tag attributes
796      * @param contents the tag contents
797      * @return the HTML code
798      * @throws SAXEception if an error is encountered
799      */
800     public String handlePart(final Map<String, String> attributes, final String contents) throws SAXException {
801         String fileName = attributes.get("id") + ".html";
802         String str = encloseContents("ul", "list-chapter", contents);
803         String title = encloseContents("h3", "title-part", partTitle);
804         createHTMLFile(attributes.get("id"), fileName, partTitle, title + "\n" + str);
805         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "part"}, partTitle) + "\n" + str);
806         partTitle = "";
807
808         return str;
809     }
810
811     /**
812      * Handle a chapter
813      * @param attributes the tag attributes
814      * @param contents the tag contents
815      * @return the HTML code
816      * @throws SAXEception if an error is encountered
817      */
818     public String handleChapter(final Map<String, String> attributes, final String contents) throws SAXException {
819         String fileName = attributes.get("id") + ".html";
820         String str = encloseContents("ul", "list-refentry", contents);
821         String title = encloseContents("h3", "title-chapter", chapterTitle);
822         createHTMLFile(attributes.get("id"), fileName, chapterTitle, title + "\n" + str);
823
824         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "chapter"}, chapterTitle) + "\n" + str);
825         chapterTitle = "";
826
827         return str;
828     }
829
830     // partiellement merdique car le style de title depend du noeud pere.
831     /**
832      * Handle a title
833      * @param attributes the tag attributes
834      * @param contents the tag contents
835      * @return the HTML code
836      * @throws SAXEception if an error is encountered
837      */
838     public String handleTitle(final Map<String, String> attributes, final String contents) throws SAXException {
839         String clazz = "title";
840         String parent = getParentTagName();
841         if (parent.equals("chapter")) {
842             chapterTitle = contents;
843         } else if (parent.equals("part")) {
844             partTitle = contents;
845         } else if (parent.equals("info")) {
846             bookTitle = contents;
847         } else if (parent.equals("section")) {
848             sectionTitle = contents;
849         } else if (parent.equals("refsection") && Pattern.matches("^[ \\t]*ex[ea]mpl[eo].*", contents.toLowerCase())) {
850             hasExamples = true;
851             return encloseContents("h3", clazz, contents);
852         } else if (parent.equals("refsect1")) {
853             return encloseContents("h3", clazz, contents);
854         } else if (parent.equals("refsect2")) {
855             return encloseContents("h4", clazz, contents);
856         } else if (parent.equals("refsect3")) {
857             return encloseContents("h5", clazz, contents);
858         } else {
859             return encloseContents("h3", clazz, contents);
860         }
861
862         return null;
863     }
864
865     /**
866      * Handle a para
867      * @param attributes the tag attributes
868      * @param contents the tag contents
869      * @return the HTML code
870      * @throws SAXEception if an error is encountered
871      */
872     public String handlePara(final Map<String, String> attributes, final String contents) throws SAXException {
873         return encloseContents("p", "para", contents);
874     }
875
876     /**
877      * Handle a literal
878      * @param attributes the tag attributes
879      * @param contents the tag contents
880      * @return the HTML code
881      * @throws SAXEception if an error is encountered
882      */
883     public String handleLiteral(final Map<String, String> attributes, final String contents) throws SAXException {
884       return encloseContents("code", new String[] {"class", "literal", "dir", "ltr"}, contents);
885     }
886
887     /**
888      * Handle a literallayout
889      * @param attributes the tag attributes
890      * @param contents the tag contents
891      * @return the HTML code
892      * @throws SAXEception if an error is encountered
893      */
894     public String handleLiterallayout(final Map<String, String> attributes, final String contents) throws SAXException {
895
896         //replace \n by <br>
897         String s = contents.replace("\n", "<BR>");
898         //replace spaces by &nbsp;
899         s = s.replace(" ", "&nbsp;");
900
901         return encloseContents("code", new String[] {"class", "literallayout", "dir", "ltr"}, s);
902     }
903
904     /**
905      * Handle a varname
906      * @param attributes the tag attributes
907      * @param contents the tag contents
908      * @return the HTML code
909      * @throws SAXEception if an error is encountered
910      */
911     public String handleVarname(final Map<String, String> attributes, final String contents) throws SAXException {
912         return encloseContents("code", "varname", contents);
913     }
914
915     /**
916      * Handle a command
917      * @param attributes the tag attributes
918      * @param contents the tag contents
919      * @return the HTML code
920      * @throws SAXEception if an error is encountered
921      */
922     public String handleCommand(final Map<String, String> attributes, final String contents) throws SAXException {
923         return encloseContents("code", "command", contents);
924     }
925
926     /**
927      * Handle a code
928      * @param attributes the tag attributes
929      * @param contents the tag contents
930      * @return the HTML code
931      * @throws SAXEception if an error is encountered
932      */
933     public String handleCode(final Map<String, String> attributes, final String contents) throws SAXException {
934         return encloseContents("code", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));//encloseContents("code", "code", contents);
935     }
936
937     /**
938      * Handle a function
939      * @param attributes the tag attributes
940      * @param contents the tag contents
941      * @return the HTML code
942      * @throws SAXEception if an error is encountered
943      */
944     public String handleFunction(final Map<String, String> attributes, final String contents) throws SAXException {
945         return encloseContents("code", "function", contents);
946     }
947
948     /**
949      * Handle a constant
950      * @param attributes the tag attributes
951      * @param contents the tag contents
952      * @return the HTML code
953      * @throws SAXEception if an error is encountered
954      */
955     public String handleConstant(final Map<String, String> attributes, final String contents) throws SAXException {
956         return encloseContents("code", "constant", contents);
957     }
958
959     /**
960      * Handle an option
961      * @param attributes the tag attributes
962      * @param contents the tag contents
963      * @return the HTML code
964      * @throws SAXEception if an error is encountered
965      */
966     public String handleOption(final Map<String, String> attributes, final String contents) throws SAXException {
967         return encloseContents("code", "option", contents);
968     }
969
970     /**
971      * Handle a refnamediv
972      * @param attributes the tag attributes
973      * @param contents the tag contents
974      * @return the HTML code
975      * @throws SAXEception if an error is encountered
976      */
977     public String handleRefnamediv(final Map<String, String> attributes, final String contents) throws SAXException {
978         String id = attributes.get("id");
979         if (id != null) {
980             currentId = id;
981         }
982
983         return encloseContents("div", "refnamediv", contents);
984     }
985
986     /**
987      * Handle a refname
988      * @param attributes the tag attributes
989      * @param contents the tag contents
990      * @return the HTML code
991      * @throws SAXEception if an error is encountered
992      */
993     public String handleRefname(final Map<String, String> attributes, final String contents) throws SAXException {
994         refname = contents;
995         return encloseContents("h1", "refname", contents);
996     }
997
998     /**
999      * Handle a refpurpose
1000      * @param attributes the tag attributes
1001      * @param contents the tag contents
1002      * @return the HTML code
1003      * @throws SAXEception if an error is encountered
1004      */
1005     public String handleRefpurpose(final Map<String, String> attributes, final String contents) throws SAXException {
1006         refpurpose = contents;
1007         return encloseContents("p", "refpurpose", contents);
1008     }
1009
1010     /**
1011      * Handle a refsynopsisdiv
1012      * @param attributes the tag attributes
1013      * @param contents the tag contents
1014      * @return the HTML code
1015      * @throws SAXEception if an error is encountered
1016      */
1017     public String handleRefsynopsisdiv(final Map<String, String> attributes, final String contents) throws SAXException {
1018         String id = attributes.get("id");
1019         if (id != null) {
1020             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsynopsisdiv", contents);
1021         } else {
1022             return encloseContents("div", "refsynopsisdiv", contents);
1023         }
1024     }
1025
1026     /**
1027      * Handle a synopsis
1028      * @param attributes the tag attributes
1029      * @param contents the tag contents
1030      * @return the HTML code
1031      * @throws SAXEception if an error is encountered
1032      */
1033     public String handleSynopsis(final Map<String, String> attributes, final String contents) throws SAXException {
1034         String id = attributes.get("id");
1035         String str = encloseContents("div", "synopsis", encloseContents("pre", SynopsisLexer.convert(refname, contents)));
1036         if (id != null) {
1037             return "<a name=\"" + id + "\"></a>" + str;
1038         } else {
1039             return str;
1040         }
1041     }
1042
1043     /**
1044      * Handle a info
1045      * @param attributes the tag attributes
1046      * @param contents the tag contents
1047      * @return the HTML code
1048      * @throws SAXEception if an error is encountered
1049      */
1050     public String handleInfo(final Map<String, String> attributes, final String contents) throws SAXException {
1051         String id = attributes.get("id");
1052         if (id != null) {
1053             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "info", contents);
1054         } else {
1055             return encloseContents("div", "info", contents);
1056         }
1057     }
1058
1059     /**
1060      * Handle a refsection
1061      * @param attributes the tag attributes
1062      * @param contents the tag contents
1063      * @return the HTML code
1064      * @throws SAXEception if an error is encountered
1065      */
1066     public String handleRefsection(final Map<String, String> attributes, final String contents) throws SAXException {
1067         String id = attributes.get("id");
1068         if (id != null) {
1069             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsection", contents);
1070         } else {
1071             return encloseContents("div", "refsection", contents);
1072         }
1073     }
1074
1075     /**
1076      * Handle a refsect1
1077      * @param attributes the tag attributes
1078      * @param contents the tag contents
1079      * @return the HTML code
1080      * @throws SAXEception if an error is encountered
1081      */
1082     public String handleRefsect1(final Map<String, String> attributes, final String contents) throws SAXException {
1083         String id = attributes.get("id");
1084         if (id != null) {
1085             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect1", contents);
1086         } else {
1087             return encloseContents("div", "refsect1", contents);
1088         }
1089     }
1090
1091     /**
1092      * Handle a refsect2
1093      * @param attributes the tag attributes
1094      * @param contents the tag contents
1095      * @return the HTML code
1096      * @throws SAXEception if an error is encountered
1097      */
1098     public String handleRefsect2(final Map<String, String> attributes, final String contents) throws SAXException {
1099         String id = attributes.get("id");
1100         if (id != null) {
1101             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect2", contents);
1102         } else {
1103             return encloseContents("div", "refsect2", contents);
1104         }
1105     }
1106
1107     /**
1108      * Handle a refsect3
1109      * @param attributes the tag attributes
1110      * @param contents the tag contents
1111      * @return the HTML code
1112      * @throws SAXEception if an error is encountered
1113      */
1114     public String handleRefsect3(final Map<String, String> attributes, final String contents) throws SAXException {
1115         String id = attributes.get("id");
1116         if (id != null) {
1117             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect3", contents);
1118         } else {
1119             return encloseContents("div", "refsect3", contents);
1120         }
1121     }
1122
1123     /**
1124      * Handle an anchor
1125      * @param attributes the tag attributes
1126      * @param contents the tag contents
1127      * @return the HTML code
1128      * @throws SAXEception if an error is encountered
1129      */
1130     public String handleAnchor(final Map<String, String> attributes, final String contents) throws SAXException {
1131         String id = attributes.get("id");
1132         if (id != null) {
1133             return "<a name=\"" + id + "\">" + contents + "</a>";
1134         } else {
1135             return contents;
1136         }
1137     }
1138
1139     /**
1140      * Handle a progamlisting
1141      * @param attributes the tag attributes
1142      * @param contents the tag contents
1143      * @return the HTML code
1144      * @throws SAXEception if an error is encountered
1145      */
1146     public String handleProgramlisting(final Map<String, String> attributes, final String contents) throws SAXException {
1147         String id = attributes.get("id");
1148         String role = attributes.get("role");
1149         String str;
1150         if (role == null) {
1151             String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1152             if (prependToProgramListing != null) {
1153                 code = prependToProgramListing + code;
1154             }
1155             if (appendToProgramListing != null) {
1156                 code += appendToProgramListing;
1157             }
1158             str = encloseContents("div", "programlisting", code);
1159         } else {
1160             if (role.equals("xml")) {
1161                 str = encloseContents("div", "programlisting", encloseContents("pre", "xmlcode", xmlLexer.convert(HTMLXMLCodeHandler.getInstance(), contents)));
1162             } else if (role.equals("c") || role.equals("cpp") || role.equals("code_gateway")) {
1163                 hasExamples = true;
1164                 str = encloseContents("div", "programlisting", encloseContents("pre", "ccode", cLexer.convert(HTMLCCodeHandler.getInstance(), contents)));
1165             } else if (role.equals("java")) {
1166                 hasExamples = true;
1167                 str = encloseContents("div", "programlisting", encloseContents("pre", "ccode", javaLexer.convert(HTMLCCodeHandler.getInstance(), contents)));
1168             } else if (role.equals("exec")) {
1169                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1170                 if (prependToProgramListing != null) {
1171                     code = prependToProgramListing + code;
1172                 }
1173                 if (appendForExecToProgramListing != null) {
1174                     code += appendForExecToProgramListing;
1175                 }
1176                 str = encloseContents("div", "programlisting", code);
1177             } else if (role.equals("no-scilab-exec")) {
1178                 hasExamples = true;
1179                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1180                 str = encloseContents("div", "programlisting", code);
1181             } else {
1182                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1183                 if (prependToProgramListing != null) {
1184                     code = prependToProgramListing + code;
1185                 }
1186                 if (appendToProgramListing != null) {
1187                     code += appendToProgramListing;
1188                 }
1189                 str = encloseContents("div", "programlisting", code);
1190             }
1191         }
1192         if (id != null) {
1193             return "<a name=\"" + id + "\"></a>" + str;
1194         } else {
1195             return str;
1196         }
1197     }
1198
1199     /**
1200      * Handle a screen
1201      * @param attributes the tag attributes
1202      * @param contents the tag contents
1203      * @return the HTML code
1204      * @throws SAXEception if an error is encountered
1205      */
1206     public String handleScreen(final Map<String, String> attributes, final String contents) throws SAXException {
1207         String id = attributes.get("id");
1208         String str = encloseContents("div", "screen", encloseContents("pre", contents.replace("<", "&lt;")));
1209         if (id != null) {
1210             return "<a name=\"" + id + "\"></a>" + str;
1211         } else {
1212             return str;
1213         }
1214     }
1215
1216     /**
1217      * Handle a pubdate
1218      * @param attributes the tag attributes
1219      * @param contents the tag contents
1220      * @return the HTML code
1221      * @throws SAXEception if an error is encountered
1222      */
1223     public String handlePubdate(final Map<String, String> attributes, final String contents) throws SAXException {
1224         return null;
1225     }
1226
1227     /**
1228      * Handle a simplelist
1229      * @param attributes the tag attributes
1230      * @param contents the tag contents
1231      * @return the HTML code
1232      * @throws SAXEception if an error is encountered
1233      */
1234     public String handleSimplelist(final Map<String, String> attributes, final String contents) throws SAXException {
1235         String style = "itemizedlist";
1236
1237         return encloseContents("ul", style, contents);
1238     }
1239
1240     /**
1241      * Handle a member
1242      * @param attributes the tag attributes
1243      * @param contents the tag contents
1244      * @return the HTML code
1245      * @throws SAXEception if an error is encountered
1246      */
1247     public String handleMember(final Map<String, String> attributes, final String contents) throws SAXException {
1248         return encloseContents("li", "member", contents);
1249     }
1250
1251     /**
1252      * Handle a link
1253      * @param attributes the tag attributes
1254      * @param contents the tag contents
1255      * @return the HTML code
1256      * @throws SAXEception if an error is encountered
1257      */
1258     public String handleLink(final Map<String, String> attributes, final String contents) throws SAXException {
1259         String link = attributes.get("linkend");
1260         if (link == null) {
1261             throw new SAXException("No linkend attribute in tag link");
1262         }
1263
1264         String type = attributes.get("type");
1265         String id;
1266         if (type != null && type.equals("scilab")) {
1267             if (this.type == Backend.JAVAHELP || this.type == Backend.HTML) {
1268                 id = resolvScilabLink(link);
1269             } else {
1270                 return contents;
1271             }
1272         } else if (type != null && type.equals("remote")) {
1273             id = makeRemoteLink(link);
1274         } else {
1275             id = mapId.get(link);
1276         }
1277
1278         if (id == null) {
1279             if (isToolbox) {
1280                 if (this.type == Backend.HTML) {
1281                     id = urlBase + link;
1282                     if (linkToTheWeb) {
1283                         id += ".html";
1284                     }
1285                 }
1286                 if (this.type == Backend.JAVAHELP) {
1287                     id = urlBase + link;
1288                 }
1289             } else {
1290                 warnings++;
1291                 System.err.println("Warning (should be fixed): invalid internal link to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1292                 return null;
1293             }
1294         }
1295
1296         Stack<DocbookElement> stack = getStack();
1297         String refnameTarget = mapIdRefname.get(link);
1298         String str;
1299         if (contents != null && !contents.isEmpty()) {
1300             str = contents;
1301         } else {
1302             str = refnameTarget;
1303         }
1304
1305         if (str == null) {
1306             warnings++;
1307             System.err.println("Warning (should be fixed): empty link (no text will be printed) to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1308         }
1309
1310         String href = encloseContents("a", new String[] {"href", id, "class", "link"}, str);
1311
1312         int s = stack.size();
1313         if (s >= 3) {
1314             DocbookElement elem = stack.get(s - 3);
1315             if (elem.getName().equals("refsection")) {
1316                 String role = elem.getAttributes().get("role");
1317                 if (role != null && role.equals("see also")) {
1318                     String purpose = mapIdPurpose.get(link);
1319                     if (purpose != null) {
1320                         return href + " &#8212; " + purpose;
1321                     } else {
1322                         return href;
1323                     }
1324                 }
1325             }
1326         }
1327
1328         return href;
1329     }
1330
1331     /**
1332      * Rewrite a link when its type is "scilab"
1333      * @param link the link
1334      * @return the modified link with protocol scilab:// for example
1335      */
1336     protected String resolvScilabLink(String link) {
1337         int pos = link.indexOf("/");
1338         if (pos == -1) {
1339             return null;
1340         }
1341
1342         String first = link.substring(0, pos);
1343         String second = link.substring(pos + 1);
1344         String[] toks = first.split("\\.");
1345         if (toks == null || toks.length != 2) {
1346             return null;
1347         }
1348
1349         if (!linkToTheWeb) {
1350             return urlBase + link;
1351         } else {
1352             if (toks[0].equals("scilab") && toks[1].equals("help")) {
1353                 return urlBase + second + ".html";
1354             } else {
1355                 return "#";
1356             }
1357         }
1358     }
1359
1360     /**
1361      * Make a remote link
1362      * @param link the link
1363      * @return the good link
1364      */
1365     protected String makeRemoteLink(String link) {
1366         return link;
1367     }
1368
1369     /**
1370      * Handle an ulink
1371      * @param attributes the tag attributes
1372      * @param contents the tag contents
1373      * @return the HTML code
1374      * @throws SAXEception if an error is encountered
1375      */
1376     public String handleUlink(final Map<String, String> attributes, final String contents) throws SAXException {
1377         String link = attributes.get("url");
1378         if (link == null) {
1379             throw new SAXException("No url attribute in tag ulink");
1380         }
1381
1382         return encloseContents("a", new String[] {"href", link, "class", "ulink"}, contents);
1383     }
1384
1385     /**
1386      * Handle a xref
1387      * @param attributes the tag attributes
1388      * @param contents the tag contents
1389      * @return the HTML code
1390      * @throws SAXEception if an error is encountered
1391      */
1392     public String handleXref(final Map<String, String> attributes, final String contents) throws SAXException {
1393         String link = attributes.get("linkend");
1394         if (link == null) {
1395             throw new SAXException("No linkend attribute in tag link");
1396         }
1397
1398         String id = mapId.get(link);
1399         if (id == null) {
1400             warnings++;
1401             System.err.println("Warning (should be fixed): invalid internal link to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1402             return null;
1403         }
1404
1405         return encloseContents("a", new String[] {"href", id, "class", "xref"}, contents);
1406     }
1407
1408     /**
1409      * Handle a latex (not really a docbook tag...)
1410      * @param attributes the tag attributes
1411      * @param contents the tag contents
1412      * @return the HTML code
1413      * @throws SAXEception if an error is encountered
1414      */
1415     public String handleLatex(final Map<String, String> attributes, final String contents) throws SAXException {
1416         boolean isLocalized = "true".equals(attributes.get("localized"));
1417         File f;
1418         if (isLocalized) {
1419             f = new File(outImages + "/" + imageDir, LATEXBASENAME + currentBaseName + "_" + language + "_" + (latexCompt++) + ".png");
1420         } else {
1421             if ("ru_RU".equals(language) && HTMLDocbookTagConverter.containsCyrillic(contents)) {
1422                 System.err.println("Warning: LaTeX code in " + getCurrentFileName() + " contains cyrillic character. The tag <latex> should contain the attribute scilab:localized=\"true\"");
1423             } else if ("ja_JP".equals(language) && HTMLDocbookTagConverter.containsCJK(contents)) {
1424                 System.err.println("Warning: LaTeX code in " + getCurrentFileName() + " contains CJK character. The tag <latex> should contain the attribute scilab:localized=\"true\"");
1425             }
1426             f = new File(outImages + "/" + imageDir, LATEXBASENAME + currentBaseName + "_" + (latexCompt++) + ".png");
1427         }
1428
1429         String parent = getParentTagName();
1430         if (parent.equals("para") && !attributes.containsKey("style")) {
1431             attributes.put("style", "text");
1432         }
1433         String fs = attributes.get("fontsize");
1434         if (fs == null) {
1435             attributes.put("fontsize", "16");
1436         }
1437
1438         return getImageConverter().getImageByCode(currentFileName, contents, attributes, "image/latex", f, imageDir + "/" + f.getName(), getBaseImagePath(), locator.getLineNumber(), language, isLocalized);
1439     }
1440
1441     /**
1442      * Handle a term
1443      * @param attributes the tag attributes
1444      * @param contents the tag contents
1445      * @return the HTML code
1446      * @throws SAXEception if an error is encountered
1447      */
1448     public String handleTerm(final Map<String, String> attributes, final String contents) throws SAXException {
1449         String id = attributes.get("id");
1450         if (id != null) {
1451             return "<a name=\"" + id + "\"></a>" + encloseContents("span", "term", contents);
1452         } else {
1453             return encloseContents("span", "term", contents);
1454         }
1455     }
1456
1457     /**
1458      * Handle a listitem
1459      * @param attributes the tag attributes
1460      * @param contents the tag contents
1461      * @return the HTML code
1462      * @throws SAXEception if an error is encountered
1463      */
1464     public String handleListitem(final Map<String, String> attributes, final String contents) throws SAXException {
1465         String parent = getParentTagName();
1466         if (parent.equals("varlistentry")) {
1467             return encloseContents("dd", contents);
1468         }
1469         return encloseContents("li", contents);
1470     }
1471
1472     /**
1473      * Handle a varlistentry
1474      * @param attributes the tag attributes
1475      * @param contents the tag contents
1476      * @return the HTML code
1477      * @throws SAXEception if an error is encountered
1478      */
1479     public String handleVarlistentry(final Map<String, String> attributes, final String contents) throws SAXException {
1480         return encloseContents("dt", contents);
1481     }
1482
1483     /**
1484      * Handle a variablelist
1485      * @param attributes the tag attributes
1486      * @param contents the tag contents
1487      * @return the HTML code
1488      * @throws SAXEception if an error is encountered
1489      */
1490     public String handleVariablelist(final Map<String, String> attributes, final String contents) throws SAXException {
1491         return encloseContents("dl", contents);
1492     }
1493
1494     /**
1495      * Handle an itemizedlist
1496      * @param attributes the tag attributes
1497      * @param contents the tag contents
1498      * @return the HTML code
1499      * @throws SAXEception if an error is encountered
1500      */
1501     public String handleItemizedlist(final Map<String, String> attributes, final String contents) throws SAXException {
1502         String id = attributes.get("id");
1503         if (id != null) {
1504             return "<a name=\"" + id + "\"></a>" + encloseContents("ul", "itemizedlist", contents);
1505         } else {
1506             return encloseContents("ul", "itemizedlist", contents);
1507         }
1508     }
1509
1510     /**
1511      * Handle an emphasis
1512      * @param attributes the tag attributes
1513      * @param contents the tag contents
1514      * @return the HTML code
1515      * @throws SAXEception if an error is encountered
1516      */
1517     public String handleEmphasis(final Map<String, String> attributes, final String contents) throws SAXException {
1518         String role = attributes.get("role");
1519         if (role != null) {
1520             if (role.equals("bold")) {
1521                 return encloseContents("b", contents);
1522             }
1523             if (role.equals("italic")) {
1524                 return encloseContents("i", contents);
1525             }
1526         }
1527
1528         return encloseContents("em", contents);
1529     }
1530
1531     /**
1532      * Handle a tr
1533      * @param attributes the tag attributes
1534      * @param contents the tag contents
1535      * @return the HTML code
1536      * @throws SAXEception if an error is encountered
1537      */
1538     public String handleTr(final Map<String, String> attributes, final String contents) throws SAXException {
1539         String bgcolor = attributes.get("bgcolor");
1540         String valign = attributes.get("valign");
1541         String id = attributes.get("id");
1542
1543         return encloseContents("tr", new String[] {"id", id, "bgcolor", bgcolor, "valign", valign}, contents);
1544     }
1545
1546     /**
1547      * Handle a td
1548      * @param attributes the tag attributes
1549      * @param contents the tag contents
1550      * @return the HTML code
1551      * @throws SAXEception if an error is encountered
1552      */
1553     public String handleTd(final Map<String, String> attributes, final String contents) throws SAXException {
1554         String align   = attributes.get("align");
1555         String valign  = attributes.get("valign");
1556         String bgcolor = attributes.get("bgcolor");
1557         String colspan = attributes.get("colspan");
1558         String rowspan = attributes.get("rowspan");
1559         String style   = attributes.get("style");   /*  for style="white-space:nowrap" */
1560
1561         return encloseContents("td", new String[] {"align", align, "valign", valign, "bgcolor", bgcolor, "colspan", colspan, "rowspan", rowspan, "style", style}, contents);
1562     }
1563
1564     /**
1565      * Handle an informaltable
1566      * @param attributes the tag attributes
1567      * @param contents the tag contents
1568      * @return the HTML code
1569      * @throws SAXEception if an error is encountered
1570      */
1571     public String handleInformaltable(final Map<String, String> attributes, final String contents) throws SAXException {
1572         String id = attributes.get("id");
1573         String border = attributes.get("border");
1574         String cellpadding = attributes.get("cellpadding");
1575         String width = attributes.get("width");
1576         if (id != null) {
1577             return "<a name=\"" + id + "\"></a>" + encloseContents("table", new String[] {"class", "informaltable", "border", border, "cellpadding", cellpadding, "width", width}, contents);
1578         } else {
1579             return encloseContents("table", new String[] {"class", "informaltable", "border", border, "cellpadding", cellpadding, "width", width}, contents);
1580         }
1581     }
1582
1583     /**
1584      * Handle an imagedata
1585      * @param attributes the tag attributes
1586      * @param contents the tag contents
1587      * @return the HTML code
1588      * @throws SAXEception if an error is encountered
1589      */
1590     public String handleImagedata(final Map<String, String> attributes, final String contents) throws SAXException {
1591         String fileref = attributes.get("fileref");
1592         if (fileref == null) {
1593             if (contents == null || contents.length() == 0) {
1594                 throw new SAXException("No fileref attribute or no data in tag imagedata");
1595             }
1596
1597             return contents;
1598         }
1599
1600         try {
1601             String path = new File(new URI(currentFileName)).getParent();
1602             File file = ImageConverter.imageExists(path, fileref);
1603             if (file != null) {
1604                 throw new SAXException("The given fileref is not on an existing image file:\n" + fileref + " [" + file + "]");
1605             }
1606
1607             return getImageConverter().getImageByFile(attributes, path, fileref, outImages, imageDir, getBaseImagePath());
1608         }  catch (URISyntaxException e) {
1609             System.err.println(e);
1610         }
1611
1612         return null;
1613     }
1614
1615     /**
1616      * Handle an imageobject
1617      * @param attributes the tag attributes
1618      * @param contents the tag contents
1619      * @return the HTML code
1620      * @throws SAXEception if an error is encountered
1621      */
1622     public String handleImageobject(final Map<String, String> attributes, final String contents) throws SAXException {
1623         return contents;
1624     }
1625
1626     /**
1627      * Handle an textobject (as an alternative to imageobject)
1628      * @param attributes the tag attributes
1629      * @param contents the tag contents
1630      * @return the HTML code
1631      * @throws SAXEception if an error is encountered
1632      */
1633     public String handleTextobject(final Map<String, String> attributes, final String contents) throws SAXException {
1634         return "<!-- " + contents + " -->";
1635     }
1636
1637     /**
1638      * Handle an inlinemediaobject
1639      * @param attributes the tag attributes
1640      * @param contents the tag contents
1641      * @return the HTML code
1642      * @throws SAXEception if an error is encountered
1643      */
1644     public String handleInlinemediaobject(final Map<String, String> attributes, final String contents) throws SAXException {
1645         return encloseContents("span", contents);
1646     }
1647
1648     /**
1649      * Handle a screenshot
1650      * @param attributes the tag attributes
1651      * @param contents the tag contents
1652      * @return the HTML code
1653      * @throws SAXEception if an error is encountered
1654      */
1655     public String handleScreenshot(final Map<String, String> attributes, final String contents) throws SAXException {
1656         String id = attributes.get("id");
1657         if (id != null) {
1658             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "screenshot", contents);
1659         } else {
1660             return encloseContents("div", "screenshot", contents);
1661         }
1662     }
1663
1664     /**
1665      * Handle a mediaobject
1666      * @param attributes the tag attributes
1667      * @param contents the tag contents
1668      * @return the HTML code
1669      * @throws SAXEception if an error is encountered
1670      */
1671     public String handleMediaobject(final Map<String, String> attributes, final String contents) throws SAXException {
1672         String id = attributes.get("id");
1673         String c = contents.replaceFirst("top:([0-9]+)px;", "");
1674         if (id != null) {
1675             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "mediaobject", c);
1676         } else {
1677             return encloseContents("div", "mediaobject", c);
1678         }
1679     }
1680
1681     /**
1682      * Handle an informalequation
1683      * @param attributes the tag attributes
1684      * @param contents the tag contents
1685      * @return the HTML code
1686      * @throws SAXEception if an error is encountered
1687      */
1688     public String handleInformalequation(final Map<String, String> attributes, final String contents) throws SAXException {
1689         String id = attributes.get("id");
1690         if (id != null) {
1691             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "informalequation", contents);
1692         } else {
1693             return encloseContents("div", "informalequation", contents);
1694         }
1695     }
1696
1697     /**
1698      * Handle an orderedlist
1699      * @param attributes the tag attributes
1700      * @param contents the tag contents
1701      * @return the HTML code
1702      * @throws SAXEception if an error is encountered
1703      */
1704     public String handleOrderedlist(final Map<String, String> attributes, final String contents) throws SAXException {
1705         String numeration = "1";
1706         String numAttr = attributes.get("numeration");
1707         if (numAttr != null) {
1708             if (numAttr.equals("loweralpha")) {
1709                 numeration = "a";
1710             } else if (numAttr.equals("upperalpha")) {
1711                 numeration = "A";
1712             } else if (numAttr.equals("lowerroman")) {
1713                 numeration = "i";
1714             } else if (numAttr.equals("upperroman")) {
1715                 numeration = "I";
1716             }
1717         }
1718
1719         String id = attributes.get("id");
1720         if (id != null) {
1721             return "<a name=\"" + id + "\"></a>" + encloseContents("ol", new String[] {"type", numeration}, contents);
1722         } else {
1723             return encloseContents("ol", new String[] {"type", numeration}, contents);
1724         }
1725     }
1726
1727     /**
1728      * Handle a subscript
1729      * @param attributes the tag attributes
1730      * @param contents the tag contents
1731      * @return the HTML code
1732      * @throws SAXEception if an error is encountered
1733      */
1734     public String handleSubscript(final Map<String, String> attributes, final String contents) throws SAXException {
1735         return encloseContents("sub", contents);
1736     }
1737
1738     /**
1739      * Handle a superscript
1740      * @param attributes the tag attributes
1741      * @param contents the tag contents
1742      * @return the HTML code
1743      * @throws SAXEception if an error is encountered
1744      */
1745     public String handleSuperscript(final Map<String, String> attributes, final String contents) throws SAXException {
1746         return encloseContents("sup", contents);
1747     }
1748
1749     /**
1750      * Handle a replaceable
1751      * @param attributes the tag attributes
1752      * @param contents the tag contents
1753      * @return the HTML code
1754      * @throws SAXEception if an error is encountered
1755      */
1756     public String handleReplaceable(final Map<String, String> attributes, final String contents) throws SAXException {
1757         return encloseContents("span", "replaceable", contents);
1758     }
1759
1760     /**
1761      * Handle a question
1762      * @param attributes the tag attributes
1763      * @param contents the tag contents
1764      * @return the HTML code
1765      * @throws SAXEception if an error is encountered
1766      */
1767     public String handleQuestion(final Map<String, String> attributes, final String contents) throws SAXException {
1768         return encloseContents("dt", encloseContents("strong", contents));
1769     }
1770
1771     /**
1772      * Handle an answer
1773      * @param attributes the tag attributes
1774      * @param contents the tag contents
1775      * @return the HTML code
1776      * @throws SAXEception if an error is encountered
1777      */
1778     public String handleAnswer(final Map<String, String> attributes, final String contents) throws SAXException {
1779         return encloseContents("dd", contents);
1780     }
1781
1782     /**
1783      * Handle a qandaentry
1784      * @param attributes the tag attributes
1785      * @param contents the tag contents
1786      * @return the HTML code
1787      * @throws SAXEception if an error is encountered
1788      */
1789     public String handleQandaentry(final Map<String, String> attributes, final String contents) throws SAXException {
1790         return encloseContents("dl", contents);
1791     }
1792
1793     /**
1794      * Handle a qandaset
1795      * @param attributes the tag attributes
1796      * @param contents the tag contents
1797      * @return the HTML code
1798      * @throws SAXEception if an error is encountered
1799      */
1800     public String handleQandaset(final Map<String, String> attributes, final String contents) throws SAXException {
1801         return encloseContents("div", "qandaset", contents);
1802     }
1803
1804     /**
1805      * Handle a caption
1806      * @param attributes the tag attributes
1807      * @param contents the tag contents
1808      * @return the HTML code
1809      * @throws SAXEception if an error is encountered
1810      */
1811     public String handleCaption(final Map<String, String> attributes, final String contents) throws SAXException {
1812         return encloseContents("caption", encloseContents("b", contents));
1813     }
1814
1815     /**
1816      * Handle a tbody
1817      * @param attributes the tag attributes
1818      * @param contents the tag contents
1819      * @return the HTML code
1820      * @throws SAXEception if an error is encountered
1821      */
1822     public String handleTbody(final Map<String, String> attributes, final String contents) throws SAXException {
1823         return encloseContents("tbody", "tbody", contents);
1824     }
1825
1826     /**
1827      * Handle a table
1828      * @param attributes the tag attributes
1829      * @param contents the tag contents
1830      * @return the HTML code
1831      * @throws SAXEception if an error is encountered
1832      */
1833     public String handleTable(final Map<String, String> attributes, final String contents) throws SAXException {
1834         String id = attributes.get("id");
1835         String bgcolor = attributes.get("bgcolor");
1836         String border = attributes.get("border");
1837         String cellpadding = attributes.get("cellpadding");
1838
1839         if (id != null) {
1840             return "<a name=\"" + id + "\"></a>" + encloseContents("table", new String[] {"class", "doctable", "bgcolor", bgcolor, "border", border, "cellpadding", cellpadding}, contents);
1841         } else {
1842             return encloseContents("table", new String[] {"class", "doctable", "bgcolor", bgcolor, "border", border, "cellpadding", cellpadding}, contents);
1843         }
1844     }
1845
1846     /**
1847      * Handle a surname
1848      * @param attributes the tag attributes
1849      * @param contents the tag contents
1850      * @return the HTML code
1851      * @throws SAXEception if an error is encountered
1852      */
1853     public String handleSurname(final Map<String, String> attributes, final String contents) throws SAXException {
1854         return encloseContents("span", "surname", contents);
1855     }
1856
1857     /**
1858      * Handle a firstname
1859      * @param attributes the tag attributes
1860      * @param contents the tag contents
1861      * @return the HTML code
1862      * @throws SAXEception if an error is encountered
1863      */
1864     public String handleFirstname(final Map<String, String> attributes, final String contents) throws SAXException {
1865         return encloseContents("span", "firstname", contents);
1866     }
1867
1868     /**
1869      * Handle a bibliomset
1870      * @param attributes the tag attributes
1871      * @param contents the tag contents
1872      * @return the HTML code
1873      * @throws SAXEception if an error is encountered
1874      */
1875     public String handleBibliomset(final Map<String, String> attributes, final String contents) throws SAXException {
1876         String id = attributes.get("id");
1877         if (id != null) {
1878             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "bibliomset", contents);
1879         } else {
1880             return encloseContents("div", "bibliomset", contents);
1881         }
1882     }
1883
1884     /**
1885      * Handle a bibliomixed
1886      * @param attributes the tag attributes
1887      * @param contents the tag contents
1888      * @return the HTML code
1889      * @throws SAXEception if an error is encountered
1890      */
1891     public String handleBibliomixed(final Map<String, String> attributes, final String contents) throws SAXException {
1892         String id = attributes.get("id");
1893         if (id != null) {
1894             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "bibliomixed", contents);
1895         } else {
1896             return encloseContents("div", "bibliomixed", contents);
1897         }
1898     }
1899
1900     /**
1901      * Handle a th
1902      * @param attributes the tag attributes
1903      * @param contents the tag contents
1904      * @return the HTML code
1905      * @throws SAXEception if an error is encountered
1906      */
1907     public String handleTh(final Map<String, String> attributes, final String contents) throws SAXException {
1908         String align = attributes.get("align");
1909         String valign = attributes.get("valign");
1910         String style   = attributes.get("style");   /*  for style="white-space:nowrap" */
1911
1912         return encloseContents("th", new String[] {"align", align, "valign", valign, "style", style}, contents);
1913     }
1914
1915     /**
1916      * Handle a revhistory
1917      * @param attributes the tag attributes
1918      * @param contents the tag contents
1919      * @return the HTML code
1920      * @throws SAXEception if an error is encountered
1921      */
1922     public String handleRevhistory(final Map<String, String> attributes, final String contents) throws SAXException {
1923         String id = attributes.get("id");
1924         String str = "<table class=\"revhistory\"><tr class=\"title\"><td>" + VERSION + "</td><td>" + DESCRIPTION + "</td></tr>" + contents + "</table>";
1925         if (id != null) {
1926             return "<a name=\"" + id + "\"></a>" + str;
1927         } else {
1928             return str;
1929         }
1930     }
1931
1932     /**
1933      * Handle a revision
1934      * @param attributes the tag attributes
1935      * @param contents the tag contents
1936      * @return the HTML code
1937      * @throws SAXEception if an error is encountered
1938      */
1939     public String handleRevision(final Map<String, String> attributes, final String contents) throws SAXException {
1940         return encloseContents("tr", new String[] {"valign", "top"}, contents);
1941     }
1942
1943     /**
1944      * Handle a revnumber
1945      * @param attributes the tag attributes
1946      * @param contents the tag contents
1947      * @return the HTML code
1948      * @throws SAXEception if an error is encountered
1949      */
1950     public String handleRevnumber(final Map<String, String> attributes, final String contents) throws SAXException {
1951         return encloseContents("td", "revnumber", contents);
1952     }
1953
1954     /**
1955      * Handle a revremark
1956      * @param attributes the tag attributes
1957      * @param contents the tag contents
1958      * @return the HTML code
1959      * @throws SAXEception if an error is encountered
1960      */
1961     public String handleRevremark(final Map<String, String> attributes, final String contents) throws SAXException {
1962         return encloseContents("td", "revremark", contents);
1963     }
1964
1965     /**
1966      * Handle a revdescription
1967      * @param attributes the tag attributes
1968      * @param contents the tag contents
1969      * @return the HTML code
1970      * @throws SAXEception if an error is encountered
1971      */
1972     public String handleRevdescription(final Map<String, String> attributes, final String contents) throws SAXException {
1973         return encloseContents("td", "revdescription", contents);
1974     }
1975
1976     /**
1977      * Handle a note
1978      * @param attributes the tag attributes
1979      * @param contents the tag contents
1980      * @return the HTML code
1981      * @throws SAXEception if an error is encountered
1982      */
1983     public String handleNote(final Map<String, String> attributes, final String contents) throws SAXException {
1984         String id = attributes.get("id");
1985         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabNote.png\"/></td><td valign=\"top\">" + encloseContents("div", "note", contents) + "</td></tr></table>";
1986         if (id != null) {
1987             return "<a name=\"" + id + "\"></a>" + code;
1988         } else {
1989             return code;
1990         }
1991     }
1992
1993     /**
1994      * Handle a warning
1995      * @param attributes the tag attributes
1996      * @param contents the tag contents
1997      * @return the HTML code
1998      * @throws SAXEception if an error is encountered
1999      */
2000     public String handleWarning(final Map<String, String> attributes, final String contents) throws SAXException {
2001         String id = attributes.get("id");
2002         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabWarning.png\"/></td><td valign=\"top\">" + encloseContents("div", "warning", contents) + "</td></tr></table>";
2003         if (id != null) {
2004             return "<a name=\"" + id + "\"></a>" + code;
2005         } else {
2006             return code;
2007         }
2008     }
2009
2010     /**
2011      * Handle a caution
2012      * @param attributes the tag attributes
2013      * @param contents the tag contents
2014      * @return the HTML code
2015      * @throws SAXEception if an error is encountered
2016      */
2017     public String handleCaution(final Map<String, String> attributes, final String contents) throws SAXException {
2018         String id = attributes.get("id");
2019         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabCaution.png\"/></td><td valign=\"top\">" + encloseContents("div", "caution", contents) + "</td></tr></table>";
2020         if (id != null) {
2021             return "<a name=\"" + id + "\"></a>" + code;
2022         } else {
2023             return code;
2024         }
2025     }
2026
2027     /**
2028      * Handle a tip
2029      * @param attributes the tag attributes
2030      * @param contents the tag contents
2031      * @return the HTML code
2032      * @throws SAXEception if an error is encountered
2033      */
2034     public String handleTip(final Map<String, String> attributes, final String contents) throws SAXException {
2035         String id = attributes.get("id");
2036         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabTip.png\"/></td><td valign=\"top\">" + encloseContents("div", "tip", contents) + "</td></tr></table>";
2037         if (id != null) {
2038             return "<a name=\"" + id + "\"></a>" + code;
2039         } else {
2040             return code;
2041         }
2042     }
2043
2044     /**
2045      * Handle a important
2046      * @param attributes the tag attributes
2047      * @param contents the tag contents
2048      * @return the HTML code
2049      * @throws SAXEception if an error is encountered
2050      */
2051     public String handleImportant(final Map<String, String> attributes, final String contents) throws SAXException {
2052         String id = attributes.get("id");
2053         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabImportant.png\"/></td><td valign=\"top\">" + encloseContents("div", "important", contents) + "</td></tr></table>";
2054         if (id != null) {
2055             return "<a name=\"" + id + "\"></a>" + code;
2056         } else {
2057             return code;
2058         }
2059     }
2060
2061     private static final String convertCode(String code) {
2062         if (code == null || code.length() == 0) {
2063             return "";
2064         }
2065
2066         StringBuffer buffer = new StringBuffer(2 * code.length());
2067         int start = 0;
2068         int end = code.length() - 1;
2069         char c = code.charAt(0);
2070
2071         // first we trim
2072         while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
2073             if (start < end) {
2074                 c = code.charAt(++start);
2075             } else {
2076                 break;
2077             }
2078         }
2079         c = code.charAt(end);
2080         while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
2081             if (end > 0) {
2082                 c = code.charAt(--end);
2083             } else {
2084                 break;
2085             }
2086         }
2087
2088         // replace chars by their html entities equivalent
2089         for (int j = start; j <= end; j++) {
2090             c = code.charAt(j);
2091             switch (c) {
2092                 case '&':
2093                     buffer.append("&amp;");
2094                     break;
2095                 case '<':
2096                     buffer.append("&lt;");
2097                     break;
2098                 case '>':
2099                     buffer.append("&gt;");
2100                     break;
2101                 case '\n':
2102                     buffer.append("<br />");
2103                     break;
2104                 case '\'':
2105                     buffer.append("&#039;");
2106                     break;
2107                 case '\"':
2108                     buffer.append("&quot;");
2109                     break;
2110                 default:
2111                     buffer.append(c);
2112             }
2113         }
2114
2115         return buffer.toString();
2116     }
2117 }