Clover Coverage Report - XWiki Rendering - Parent POM 4.0-SNAPSHOT (Aggregated)
Coverage timestamp: Mon Mar 12 2012 18:03:13 CET
../../../../../../img/srcFileCovDistChart10.png 0% of files have more coverage
283   773   129   8.09
128   543   0.46   11.67
35     3.69  
3    
 
  HTMLFilter       Line # 54 260 0% 112 26 93.6% 0.9359606
  HTMLFilter.HTMLFilterContext       Line # 656 23 0% 17 0 100% 1.0
  HTMLFilter.HTMLType       Line # 766 0 - 0 0 - -1.0
 
  (92)
 
1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rendering.internal.parser.xwiki10;
21   
22    import java.util.LinkedHashMap;
23    import java.util.Map;
24    import java.util.Stack;
25    import java.util.regex.Matcher;
26    import java.util.regex.Pattern;
27   
28    import javax.inject.Inject;
29    import javax.inject.Named;
30    import javax.inject.Singleton;
31   
32    import org.slf4j.Logger;
33    import org.xwiki.component.annotation.Component;
34    import org.xwiki.component.manager.ComponentLookupException;
35    import org.xwiki.component.manager.ComponentManager;
36    import org.xwiki.component.phase.Initializable;
37    import org.xwiki.component.phase.InitializationException;
38    import org.xwiki.rendering.internal.parser.xwiki10.html.InvalidHtmlException;
39    import org.xwiki.rendering.parser.xwiki10.AbstractFilter;
40    import org.xwiki.rendering.parser.xwiki10.Filter;
41    import org.xwiki.rendering.parser.xwiki10.FilterContext;
42    import org.xwiki.rendering.parser.xwiki10.macro.HTMLElementConverter;
43    import org.xwiki.rendering.parser.xwiki10.util.CleanUtil;
44   
45    /**
46    * Add needed HTML open and close macro.
47    *
48    * @version $Id: 120aeee2cb4e0bd526c3ed7d4eee461e1d7342d6 $
49    * @since 1.8M1
50    */
51    @Component
52    @Named("htmlmacro")
53    @Singleton
 
54    public class HTMLFilter extends AbstractFilter implements Initializable
55    {
56    public static final String HTMLOPEN_SUFFIX = "htmlopen";
57   
58    public static final String HTMLCLOSE_SUFFIX = "htmlclose";
59   
60    public static final String HTMLOPEN_SPATTERN =
61    "(?:" + FilterContext.XWIKI1020TOKEN_OP + FilterContext.XWIKI1020TOKENS_SF_SPATTERN + HTMLOPEN_SUFFIX + "\\d+"
62    + FilterContext.XWIKI1020TOKEN_CP + ")";
63   
64    public static final String HTMLCLOSE_SPATTERN =
65    "(?:" + FilterContext.XWIKI1020TOKEN_OP + FilterContext.XWIKI1020TOKENS_SF_SPATTERN + HTMLCLOSE_SUFFIX + "\\d+"
66    + FilterContext.XWIKI1020TOKEN_CP + ")";
67   
68    public static final String EMPTYLINEVELOCITY_SPATTERN =
69    "((?:" + FilterContext.XWIKI1020TOKENI_PATTERN + ")|[^" + FilterContext.XWIKI1020TOKEN_CP + "])\n("
70    + VelocityFilter.NLGROUP_SPATTERN + ")\n" + "(" + FilterContext.XWIKI1020TOKENI_PATTERN + "|[^"
71    + FilterContext.XWIKI1020TOKEN_OP + "]|$)";
72   
73    public static final Pattern EMPTYLINEVELOCITY_PATTERN = Pattern.compile(EMPTYLINEVELOCITY_SPATTERN);
74   
75    public static final Pattern LINEBREAK_PATTERN = Pattern.compile(Pattern.quote("\\\\"));
76   
77    /**
78    * Used to lookup macros converters.
79    */
80    @Inject
81    private ComponentManager componentManager;
82   
83    @Inject
84    @Named("escape20")
85    private Filter escape20SyntaxFilter;
86   
87    /**
88    * The logger to log.
89    */
90    @Inject
91    private Logger logger;
92   
 
93  92 toggle @Override
94    public void initialize() throws InitializationException
95    {
96  92 setPriority(3000);
97    }
98   
 
99  92 toggle @Override
100    public String filter(String content, FilterContext filterContext)
101    {
102  92 StringBuffer result = new StringBuffer();
103  92 char[] array = content.toCharArray();
104   
105  92 HTMLFilterContext context = new HTMLFilterContext(filterContext);
106   
107  92 StringBuffer beforeHtmlBuffer = new StringBuffer();
108  92 StringBuffer htmlBuffer = new StringBuffer();
109  92 StringBuffer afterHtmlBuffer = new StringBuffer();
110   
111  92 boolean inHTMLMacro = false;
112   
113  92 int i = 0;
114  11264 for (; i < array.length;) {
115  11172 char c = array[i];
116   
117  11172 context.setConversion(false);
118  11172 context.pushType();
119  11172 context.setHTML(false);
120  11172 context.setVelocityOpen(false);
121  11172 context.setVelocityClose(false);
122  11172 context.setInline(true);
123   
124  11172 StringBuffer nonHtmlbuffer = inHTMLMacro ? afterHtmlBuffer : beforeHtmlBuffer;
125   
126  11172 if (c == '<') {
127  40 try {
128  40 StringBuffer htmlBlock = new StringBuffer();
129   
130  40 int start = i;
131  40 i = getHTMLBlock(array, i, null, htmlBlock, context);
132   
133  37 StringBuffer buffer;
134  37 String str;
135  37 if (context.isHTML()) {
136  26 if (!inHTMLMacro) {
137  22 inHTMLMacro = true;
138    } else {
139  4 htmlBuffer.append(afterHtmlBuffer);
140  4 afterHtmlBuffer.setLength(0);
141    }
142   
143  26 buffer = htmlBuffer;
144  26 str = context.cleanContent(new String(array, start, i - start));
145    } else {
146  11 buffer = nonHtmlbuffer;
147  11 str = htmlBlock.toString();
148    }
149   
150  37 if (context.isVelocityOpen()) {
151  1 VelocityFilter.appendVelocityOpen(buffer, filterContext, false);
152    }
153   
154  37 if (context.isConversion()) {
155  12 if (!context.isInline()) {
156  7 if (htmlBuffer.length() > 0 || buffer.length() > 0) {
157  5 CleanUtil.setTrailingNewLines(buffer, 2);
158    }
159    }
160    }
161   
162  37 buffer.append(str);
163   
164  37 if (context.isVelocityClose()) {
165  2 VelocityFilter.appendVelocityClose(buffer, filterContext, false);
166    }
167    } catch (InvalidHtmlException e) {
168  3 this.logger.debug("Invalid HTML block at char [" + i + "]", e);
169   
170  3 nonHtmlbuffer.append(c);
171  3 ++i;
172    }
173    } else {
174  11132 nonHtmlbuffer.append(c);
175  11132 ++i;
176    }
177    }
178   
179  92 String beforeHtmlContent = beforeHtmlBuffer.toString();
180  92 String htmlContent = htmlBuffer.toString();
181  92 String afterHtmlContent = afterHtmlBuffer.toString();
182   
183    // Include velocity content as HTML content since lot of velocity generates html
184  92 if (htmlContent.length() > 0) {
185  22 Matcher velocityBeforeMatcher = VelocityFilter.VELOCITYOPEN_PATTERN.matcher(beforeHtmlBuffer);
186  22 if (velocityBeforeMatcher.find()) {
187  3 htmlContent = beforeHtmlContent.substring(velocityBeforeMatcher.start()) + htmlContent;
188  3 beforeHtmlContent = beforeHtmlContent.substring(0, velocityBeforeMatcher.start());
189    }
190  22 Matcher velocityAfterMatcher = VelocityFilter.VELOCITYCLOSE_PATTERN.matcher(afterHtmlContent);
191  22 if (velocityAfterMatcher.find()) {
192  3 htmlContent = htmlContent + afterHtmlContent.substring(0, velocityAfterMatcher.end());
193  3 afterHtmlContent = afterHtmlContent.substring(velocityAfterMatcher.end());
194    }
195    } else {
196  70 Matcher velocityContentMatcher = VelocityFilter.VELOCITYCONTENT_PATTERN.matcher(beforeHtmlBuffer);
197   
198  70 if (velocityContentMatcher.find()) {
199  35 htmlContent = velocityContentMatcher.group(0);
200  35 afterHtmlContent = beforeHtmlContent.substring(velocityContentMatcher.end());
201  35 beforeHtmlContent = beforeHtmlContent.substring(0, velocityContentMatcher.start());
202    }
203    }
204   
205  92 if (htmlContent.length() > 0) {
206  57 boolean multilines = filterContext.unProtect(htmlContent).indexOf("\n") != -1;
207   
208    // Make sure html macro does not start in a block and ends in another by "eating" them
209  57 if (multilines && htmlContent.indexOf("\n\n") != -1) {
210  10 int beforeIndex = beforeHtmlContent.lastIndexOf("\n\n");
211   
212  10 if (beforeIndex == -1) {
213  7 htmlContent = beforeHtmlContent + htmlContent;
214  7 beforeHtmlContent = "";
215    } else {
216  3 htmlContent = beforeHtmlContent.substring(beforeIndex + 2) + htmlContent;
217  3 beforeHtmlContent = beforeHtmlContent.substring(0, beforeIndex + 2);
218    }
219   
220  10 int afterIndex = afterHtmlContent.indexOf("\n\n");
221   
222  10 if (afterIndex == -1) {
223  5 htmlContent += afterHtmlContent;
224  5 afterHtmlContent = "";
225    } else {
226  5 htmlContent += afterHtmlContent.substring(0, afterIndex);
227  5 afterHtmlContent = afterHtmlContent.substring(afterIndex);
228    }
229    }
230   
231    // velocity open
232  57 Matcher velocityOpenMatcher = VelocityFilter.VELOCITYOPEN_PATTERN.matcher(htmlContent);
233  57 boolean velocityOpen = velocityOpenMatcher.find();
234  57 htmlContent = velocityOpenMatcher.replaceFirst("");
235   
236    // velocity close
237  57 Matcher velocityCloseMatcher = VelocityFilter.VELOCITYCLOSE_PATTERN.matcher(htmlContent);
238  57 boolean velocityClose = velocityCloseMatcher.find();
239  57 htmlContent = velocityCloseMatcher.replaceFirst("");
240   
241    // Make sure empty lines are taken into account
242  57 htmlContent = forceEmptyLines(htmlContent);
243    // Make sure \\ line breaks are taken into account
244  57 htmlContent = forceLineBreak(htmlContent);
245   
246    // Print
247   
248    // print before html
249  57 result.append(beforeHtmlContent);
250   
251    // print html
252    // open html content
253  57 if (velocityOpen) {
254  39 VelocityFilter.appendVelocityOpen(result, filterContext, multilines);
255    }
256   
257  57 appendHTMLOpen(result, filterContext, multilines);
258   
259    // print html content
260  57 result.append(filterContext.addProtectedContent(escape20SyntaxFilter.filter(htmlContent, filterContext),
261    false));
262   
263  57 appendHTMLClose(result, filterContext, multilines);
264   
265    // close html content
266  57 if (velocityClose) {
267  39 VelocityFilter.appendVelocityClose(result, filterContext, multilines);
268    }
269   
270    // print after html
271  57 result.append(afterHtmlContent);
272    } else {
273  35 result = beforeHtmlBuffer;
274    }
275   
276  92 return result.toString();
277    }
278   
 
279  57 toggle private String forceEmptyLines(String htmlContent)
280    {
281  57 return EMPTYLINEVELOCITY_PATTERN.matcher(htmlContent).replaceAll("$1\n$4<p/>\n$5");
282    }
283   
 
284  57 toggle private String forceLineBreak(String htmlContent)
285    {
286  57 return LINEBREAK_PATTERN.matcher(htmlContent).replaceAll("<br/>");
287    }
288   
 
289  73 toggle private int getHTMLBlock(char[] array, int currentIndex, StringBuffer elementName, StringBuffer htmlBlock,
290    HTMLFilterContext context) throws InvalidHtmlException
291    {
292  73 int i = currentIndex + 1;
293   
294  73 context.setType(null);
295   
296  73 if (i < array.length) {
297  73 if (array[i] == '/') {
298  26 i = getEndElement(array, currentIndex, elementName, htmlBlock, context);
299  47 } else if (array[i] == '!' && i + 2 < array.length && array[i + 1] == '-' && array[i + 2] == '-') {
300  2 i = getComment(array, currentIndex, htmlBlock, context);
301    } else {
302  45 i = getElement(array, currentIndex, elementName, htmlBlock, context);
303    }
304    }
305   
306  69 return i;
307    }
308   
 
309  2 toggle private int getComment(char[] array, int currentIndex, StringBuffer commentBlock, HTMLFilterContext context)
310    {
311  2 context.setType(HTMLType.COMMENT);
312  2 context.setHTML(true);
313   
314  2 int i = currentIndex + 4;
315   
316  36 for (; i < array.length && (array[i - 1] != '>' || array[i - 2] != '-' || array[i - 3] != '-'); ++i) {
317    }
318   
319  2 commentBlock.append(array, currentIndex, i - currentIndex);
320   
321  2 return i;
322    }
323   
 
324  45 toggle private int getElement(char[] array, int currentIndex, StringBuffer elementNameBuffer, StringBuffer element,
325    HTMLFilterContext context) throws InvalidHtmlException
326    {
327    // If white space it's not html
328  45 if (Character.isWhitespace(array[currentIndex + 1])) {
329  2 throw new InvalidHtmlException();
330    }
331   
332    // get begin element
333  43 StringBuffer beginElement = new StringBuffer();
334  43 Map<String, String> parameterMap = new LinkedHashMap<String, String>();
335  43 if (elementNameBuffer == null) {
336  36 elementNameBuffer = new StringBuffer();
337    }
338  43 int i = getBeginElement(array, currentIndex, elementNameBuffer, beginElement, parameterMap, context);
339   
340  42 String elementName = elementNameBuffer.toString();
341   
342    // force <br> as full element instead of just begin element
343  42 if (context.peekType() == HTMLType.BEGIN && "br".equals(elementName)) {
344  1 context.setType(HTMLType.ELEMENT);
345    }
346   
347    // Get content
348  42 StringBuffer elementContent = null;
349  42 if (context.peekType() == HTMLType.BEGIN) {
350  31 elementContent = new StringBuffer();
351  31 context.pushType();
352  31 i = getElementContent(array, i, elementName, elementContent, null, context);
353  31 context.popType();
354    }
355   
356    // Convert
357  42 String convertedElement =
358  42 convertElement(elementName, elementContent != null ? elementContent.toString() : null, parameterMap,
359    context);
360   
361    // Print
362  42 if (convertedElement != null) {
363  13 element.append(convertedElement);
364    } else {
365  29 context.setHTML(true);
366    }
367   
368  42 context.setType(HTMLType.ELEMENT);
369   
370  42 return i;
371    }
372   
 
373  42 toggle private String convertElement(String name, String content, Map<String, String> parameters, HTMLFilterContext context)
374    {
375  42 String convertedElement = null;
376   
377  42 context.setConversion(false);
378   
379  42 try {
380  42 HTMLElementConverter currentMacro = this.componentManager.lookup(HTMLElementConverter.class, name);
381   
382  14 convertedElement = currentMacro.convert(name, parameters, content, context);
383   
384  14 if (convertedElement != null) {
385  13 context.setConversion(true);
386  13 context.setInline(currentMacro.isInline());
387    }
388    } catch (ComponentLookupException e) {
389  28 this.logger.debug("Can't find macro converter [" + name + "]", e);
390    } catch (Exception e) {
391  0 this.logger.debug("Failed to convert macro [" + name + "]", e);
392    }
393   
394  42 return convertedElement;
395    }
396   
 
397  31 toggle private int getElementContent(char[] array, int currentIndex, String currentElement, StringBuffer elementContent,
398    StringBuffer endElement, HTMLFilterContext context)
399    {
400  31 int i = currentIndex;
401   
402  313 for (; i < array.length;) {
403  307 char c = array[i];
404   
405  307 context.setConversion(false);
406   
407  307 StringBuffer htmlBlock = new StringBuffer();
408   
409  307 String elementName;
410  307 if (c == '<') {
411  33 try {
412  33 StringBuffer elementNameBuffer = new StringBuffer();
413  33 i = getHTMLBlock(array, i, elementNameBuffer, htmlBlock, context);
414  32 elementName = elementNameBuffer.toString();
415   
416  32 if (context.peekType() == HTMLType.END
417    && (currentElement.equals(elementName) || currentElement.startsWith(elementName))) {
418  25 if (endElement != null) {
419  0 endElement.append(htmlBlock);
420    }
421  25 break;
422    }
423   
424  7 if (context.peekType() != null) {
425  7 elementContent.append(htmlBlock);
426    } else {
427  0 elementContent.append(c);
428  0 ++i;
429    }
430    } catch (InvalidHtmlException e) {
431  1 this.logger.debug("Invalid HTML block at char [" + i + "]", e);
432  1 ++i;
433    }
434    } else {
435  274 elementContent.append(c);
436  274 ++i;
437    }
438    }
439   
440  31 return i;
441    }
442   
 
443  43 toggle private int getBeginElement(char[] array, int currentIndex, StringBuffer elementName, StringBuffer beginElement,
444    Map<String, String> parameterMap, HTMLFilterContext context) throws InvalidHtmlException
445    {
446  43 int i = currentIndex + 1;
447   
448    // If end of the content it's not html
449  43 if (i == array.length) {
450  0 throw new InvalidHtmlException();
451    }
452   
453    // If not a letter it's not html
454    // TODO: should maybe try to match a list of html elements instead. Is it possible to find an exhaustive list ?
455  43 if (!Character.isLetter(array[i])) {
456  1 throw new InvalidHtmlException();
457    }
458   
459    // get element name
460  42 i = getElementName(array, i, elementName, context);
461   
462    // skip white spaces
463  42 i = getWhiteSpaces(array, i, null);
464   
465    // get parameters
466  42 i = getElementParameters(array, i, null, parameterMap);
467   
468    // skip white spaces
469  42 i = getWhiteSpaces(array, i, null);
470   
471    //
472  42 if (i == array.length) {
473  1 context.setType(HTMLType.ELEMENT);
474  41 } else if (array[i] == '/' && i + 1 < array.length && array[i + 1] == '>') {
475  9 context.setType(HTMLType.ELEMENT);
476  9 i += 2;
477    } else {
478  32 context.setType(HTMLType.BEGIN);
479  32 i += 1;
480    }
481   
482  42 beginElement.append(array, currentIndex, i - currentIndex);
483   
484  42 return i;
485    }
486   
 
487  26 toggle private int getEndElement(char[] array, int currentIndex, StringBuffer elementName, StringBuffer endElement,
488    HTMLFilterContext context) throws InvalidHtmlException
489    {
490  26 int i = currentIndex + 2;
491   
492    // If white space it's not html
493  26 if (i == array.length || Character.isWhitespace(array[i])) {
494  1 throw new InvalidHtmlException();
495    }
496   
497    // get element name
498  25 i = getElementName(array, i, elementName, context);
499   
500    // skip white spaces
501  25 i = getWhiteSpaces(array, i, null);
502   
503  25 if (array[i] == '>') {
504  25 ++i;
505    }
506   
507  25 context.setType(HTMLType.END);
508   
509  25 if (endElement != null) {
510  25 endElement.append(array, currentIndex, i - currentIndex);
511    }
512   
513  25 return i;
514    }
515   
 
516  67 toggle private int getElementName(char[] array, int currentIndex, StringBuffer elementName, HTMLFilterContext context)
517    {
518  67 int i = currentIndex;
519   
520  440 for (; i < array.length && !Character.isWhitespace(array[i]); ++i) {
521  429 if (array[i] == '>') {
522  48 context.setType(HTMLType.BEGIN);
523  48 break;
524  381 } else if (array[i] == '/' && i + 1 < array.length && array[i + 1] == '>') {
525  8 context.setType(HTMLType.END);
526  8 break;
527    }
528    }
529   
530  67 if (elementName != null) {
531  67 elementName.append(array, currentIndex, i - currentIndex);
532    }
533   
534  67 return i;
535    }
536   
 
537  185 toggle private int getWhiteSpaces(char[] array, int currentIndex, StringBuffer htmlBlock)
538    {
539  185 int i = currentIndex;
540   
541  197 for (; i < array.length && Character.isWhitespace(array[i]); ++i) {
542    }
543   
544  185 if (htmlBlock != null) {
545  0 htmlBlock.append(array, currentIndex, i - currentIndex);
546    }
547   
548  185 return i;
549    }
550   
 
551  42 toggle private int getElementParameters(char[] array, int currentIndex, StringBuffer parametersBlock,
552    Map<String, String> parameterMap)
553    {
554  42 int i = currentIndex;
555   
556  54 for (; i < array.length;) {
557    // Skip white spaces
558  53 i = getWhiteSpaces(array, i, null);
559   
560  53 if (i < array.length) {
561    // If '>' it's the end of parameters
562  53 if (array[i] == '>') {
563  32 break;
564  21 } else if (array[i] == '/' && i + 1 < array.length && array[i + 1] == '>') {
565  9 break;
566    }
567   
568    // Skip parameter
569  12 i = getElementParameter(array, i, null, parameterMap);
570    }
571    }
572   
573  42 if (parametersBlock != null) {
574  0 parametersBlock.append(array, currentIndex, i - currentIndex);
575    }
576   
577  42 return i;
578    }
579   
 
580  12 toggle private int getElementParameter(char[] array, int currentIndex, StringBuffer parameterBlock,
581    Map<String, String> parameterMap)
582    {
583  12 int i = currentIndex;
584   
585    // Get key
586  12 StringBuffer keyBlock = new StringBuffer();
587  72 for (; i < array.length && array[i] != '>' && array[i] != '=' && !Character.isWhitespace(array[i]); ++i) {
588  60 keyBlock.append(array[i]);
589    }
590   
591    // Skip white spaces
592  12 i = getWhiteSpaces(array, i, null);
593   
594    // Equal sign
595  12 if (i < array.length && array[i] == '=') {
596  11 ++i;
597   
598    // Skip white spaces
599  11 i = getWhiteSpaces(array, i, null);
600   
601    // Get value
602  11 StringBuffer valueBlock = new StringBuffer();
603  11 i = getElementParameterValue(array, i, valueBlock);
604   
605    // Add a new parameter to the list
606  11 parameterMap.put(keyBlock.toString(), valueBlock.toString());
607    }
608   
609  12 if (parameterBlock != null) {
610  0 parameterBlock.append(array, currentIndex, i - currentIndex);
611    }
612   
613  12 return i;
614    }
615   
 
616  11 toggle private int getElementParameterValue(char[] array, int currentIndex, StringBuffer valueBlock)
617    {
618  11 int i = currentIndex;
619   
620  11 char escaped = 0;
621   
622  11 if (array[i] == '"' || array[i] == '\'') {
623  11 escaped = array[i];
624  11 ++i;
625    }
626   
627  152 for (; i < array.length && array[i] != '>'; ++i) {
628  152 if (escaped == 0) {
629  0 if (Character.isWhitespace(array[i])) {
630  0 break;
631    }
632    } else {
633  152 if (array[i] == escaped) {
634  11 ++i;
635  11 break;
636    }
637    }
638    }
639   
640  11 valueBlock.append(array, currentIndex, i - currentIndex);
641   
642  11 return i;
643    }
644   
 
645  58 toggle public static void appendHTMLOpen(StringBuffer result, FilterContext filterContext, boolean nl)
646    {
647  58 result.append(filterContext.addProtectedContent("{{html clean=\"false\" wiki=\"true\"}}" + (nl ? "\n" : ""),
648    HTMLOPEN_SUFFIX, true));
649    }
650   
 
651  58 toggle public static void appendHTMLClose(StringBuffer result, FilterContext filterContext, boolean nl)
652    {
653  58 result.append(filterContext.addProtectedContent((nl ? "\n" : "") + "{{/html}}", HTMLCLOSE_SUFFIX, true));
654    }
655   
 
656    public static class HTMLFilterContext
657    {
658    private boolean conversion = false;
659   
660    private Stack<HTMLType> type = new Stack<HTMLType>();
661   
662    private boolean html = false;
663   
664    private FilterContext filterContext;
665   
666    private boolean velocityOpen;
667   
668    private boolean velocityClose;
669   
670    private boolean inline;
671   
 
672  92 toggle public HTMLFilterContext(FilterContext filterContext)
673    {
674  92 this.filterContext = filterContext;
675    }
676   
 
677  37 toggle public boolean isConversion()
678    {
679  37 return this.conversion;
680    }
681   
 
682  11534 toggle public void setConversion(boolean conversion)
683    {
684  11534 this.conversion = conversion;
685    }
686   
 
687  23 toggle public FilterContext getFilterContext()
688    {
689  23 return this.filterContext;
690    }
691   
 
692  123 toggle public HTMLType peekType()
693    {
694  123 return type.peek();
695    }
696   
 
697  11203 toggle public void pushType()
698    {
699  11203 this.type.push(null);
700    }
701   
 
702  31 toggle public HTMLType popType()
703    {
704  31 return this.type.pop();
705    }
706   
 
707  241 toggle public void setType(HTMLType type)
708    {
709  241 this.type.set(this.type.size() - 1, type);
710    }
711   
 
712  37 toggle public boolean isHTML()
713    {
714  37 return html;
715    }
716   
 
717  11203 toggle public void setHTML(boolean isHTML)
718    {
719  11203 this.html = isHTML;
720    }
721   
 
722  81 toggle public boolean isVelocityOpen()
723    {
724  81 return velocityOpen;
725    }
726   
 
727  11216 toggle public void setVelocityOpen(boolean velocityOpen)
728    {
729  11216 this.velocityOpen = velocityOpen;
730    }
731   
 
732  81 toggle public boolean isVelocityClose()
733    {
734  81 return velocityClose;
735    }
736   
 
737  11216 toggle public void setVelocityClose(boolean velocityClose)
738    {
739  11216 this.velocityClose = velocityClose;
740    }
741   
 
742  12 toggle public boolean isInline()
743    {
744  12 return this.inline;
745    }
746   
 
747  11185 toggle public void setInline(boolean inline)
748    {
749  11185 this.inline = inline;
750    }
751   
 
752  44 toggle public String cleanContent(String content)
753    {
754  44 Matcher velocityOpenMatcher = VelocityFilter.VELOCITYOPEN_PATTERN.matcher(content);
755  44 setVelocityOpen(isVelocityOpen() | velocityOpenMatcher.find());
756  44 String cleanedContent = velocityOpenMatcher.replaceFirst("");
757   
758  44 Matcher velocityCloseMatcher = VelocityFilter.VELOCITYCLOSE_PATTERN.matcher(cleanedContent);
759  44 setVelocityClose(isVelocityClose() | velocityCloseMatcher.find());
760  44 cleanedContent = velocityCloseMatcher.replaceFirst("");
761   
762  44 return cleanedContent;
763    }
764    }
765   
 
766    enum HTMLType
767    {
768    ELEMENT,
769    BEGIN,
770    END,
771    COMMENT
772    }
773    }