View Javadoc

1   /*
2    * Copyright (c) 2001 - 2005 ivata limited.
3    * All rights reserved.
4    * -----------------------------------------------------------------------------
5    * ivata masks may be redistributed under the GNU General Public
6    * License as published by the Free Software Foundation;
7    * version 2 of the License.
8    *
9    * These programs are free software; you can redistribute them and/or
10   * modify them under the terms of the GNU General Public License
11   * as published by the Free Software Foundation; version 2 of the License.
12   *
13   * These programs are distributed in the hope that they will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16   *
17   * See the GNU General Public License in the file LICENSE.txt for more
18   * details.
19   *
20   * If you would like a copy of the GNU General Public License write to
21   *
22   * Free Software Foundation, Inc.
23   * 59 Temple Place - Suite 330
24   * Boston, MA 02111-1307, USA.
25   *
26   *
27   * To arrange commercial support and licensing, contact ivata at
28   *                  http://www.ivata.com/contact.jsp
29   * -----------------------------------------------------------------------------
30   * $Log: CharacterEntityFormat.java,v $
31   * Revision 1.3  2005/04/11 14:45:38  colinmacleod
32   * Changed HTMLFormat from an abstract class
33   * into an interface.
34   *
35   * Revision 1.2  2005/04/09 18:04:18  colinmacleod
36   * Changed copyright text to GPL v2 explicitly.
37   *
38   * Revision 1.1  2005/01/06 22:41:01  colinmacleod
39   * Moved up a version number.
40   * Changed copyright notices to 2005.
41   * Updated the documentation:
42   *   - started working on multiproject:site docu.
43   *   - changed the logo.
44   * Added checkstyle and fixed LOADS of style issues.
45   * Added separate thirdparty subproject.
46   * Added struts (in web), util and webgui (in webtheme) from ivata op.
47   *
48   * Revision 1.4  2004/11/03 17:07:21  colinmacleod
49   * Fixed bug in entity matching.
50   *
51   * Revision 1.3  2004/03/21 21:16:37  colinmacleod
52   * Shortened name to ivata op.
53   *
54   * Revision 1.2  2004/02/01 22:07:32  colinmacleod
55   * Added full names to author tags
56   *
57   * Revision 1.1.1.1  2004/01/27 20:59:47  colinmacleod
58   * Moved ivata op to SourceForge.
59   *
60   * Revision 1.2  2003/10/15 14:13:39  colin
61   * Fixes for XDoclet.
62   *
63   * Revision 1.3  2003/02/26 08:15:03  colin
64   * Fixed bug in append routine.
65   *
66   * Revision 1.2  2003/02/26 08:13:43  colin
67   * added toString to entity StringBuffer - not supported in JDK 1.3
68   *
69   * Revision 1.1  2003/02/24 19:33:32  colin
70   * Moved to new subproject.
71   *
72   * Revision 1.5  2003/02/04 17:43:46  colin
73   * copyright notice
74   *
75   * Revision 1.4  2002/09/06 15:08:34  colin
76   * split off the character entity map into a new file
77   *
78   * Revision 1.3  2002/09/04 08:10:36  colin
79   * fixed bug when entities are converted by browser
80   *
81   * Revision 1.1  2002/06/21 11:58:37  colin
82   * restructured com.ivata.mask.jsp into
83   * format, JavaScript, theme and tree.
84   * -----------------------------------------------------------------------------
85   */
86  package com.ivata.mask.web.format;
87  /***
88   * Convert characters to their HTML character entity equivalents.
89   *
90   * @since ivata masks 0.4 (2002-06-19)
91   * @author Colin MacLeod
92   * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
93   * @version $Revision: 1.3 $
94   */
95  public class CharacterEntityFormat implements HTMLFormat {
96      /***
97       * Maintain the mapping via this translation array.
98       */
99      static final String[][] ENTITIES = {
100     // quotation mark = APL quote
101             // NOTE: JBuilder compiler wouldn't accept the Unicode value here
102             // (\u0022): probably an internal compiler problem with the string
103             // quotes
104             {"\"", "quot" }, //\u0022
105             {"\"", "#34"}, //\u0022
106             // ampersand
107             {"\u0026", "amp"}, {"\u0026", "#38"}, {"&", "amp"},
108             {"\u0027", "#39"},
109             // less-than sign
110             {"\u003C", "lt"}, {"\u003C", "#60"}, {"<", "lt"},
111             // greater-than sign
112             {"\u003E", "gt"}, {"\u003E", "#62"}, {">", "gt"},
113             // Latin capital ligature OE
114             {"\u0152", "OElig"}, {"\u0152", "#338"},
115             // Latin small ligature oe
116             {"\u0153", "oelig"}, {"\u0153", "#339"},
117             // Latin capital letter S with caron
118             {"\u0160", "Scaron"}, {"\u0160", "#352"},
119             // Latin small letter s with caron
120             {"\u0161", "scaron"}, {"\u0161", "#353"},
121             // Latin capital letter Y with diaeresis
122             {"\u0178", "Yuml"}, {"\u0178", "#376"},
123             // Latin small f with hook = function = florin
124             {"\u0192", "fnof"}, {"\u0192", "#402"},
125             // modifier letter circumflex accent
126             {"\u02C6", "circ"}, {"\u02C6", "#710"},
127             // small tilde
128             {"\u02DC", "tilde"}, {"\u02DC", "#732"},
129             // greek capital letter alpha
130             {"\u0391", "Alpha"}, {"\u0391", "#913"},
131             // greek capital letter beta
132             {"\u0392", "Beta"}, {"\u0392", "#914"},
133             // greek capital letter gamma
134             {"\u0393", "Gamma"}, {"\u0393", "#915"},
135             // greek capital letter delta
136             {"\u0394", "Delta"}, {"\u0394", "#916"},
137             // greek capital letter epsilon
138             {"\u0395", "Epsilon"}, {"\u0395", "#917"},
139             // greek capital letter zeta
140             {"\u0396", "Zeta"}, {"\u0396", "#918"},
141             // greek capital letter eta
142             {"\u0397", "Eta"}, {"\u0397", "#919"},
143             // greek capital letter theta
144             {"\u0398", "Theta"}, {"\u0398", "#920"},
145             // greek capital letter iota
146             {"\u0399", "Iota"}, {"\u0399", "#921"},
147             // greek capital letter kappa
148             {"\u039A", "Kappa"}, {"\u039A", "#922"},
149             // greek capital letter lambda
150             {"\u039B", "Lambda"}, {"\u039B", "#923"},
151             // greek capital letter mu
152             {"\u039C", "Mu"}, {"\u039C", "#924"},
153             // greek capital letter nu
154             {"\u039D", "Nu"}, {"\u039D", "#925"},
155             // greek capital letter xi
156             {"\u039E", "Xi"}, {"\u039E", "#926"},
157             // greek capital letter omicron
158             {"\u039F", "Omicron"}, {"\u039F", "#927"},
159             // greek capital letter pi
160             {"\u03A0", "Pi"}, {"\u03A0", "#928"},
161             // greek capital letter rho
162             {"\u03A1", "Rho"}, {"\u03A1", "#929"},
163             // greek capital letter sigma
164             {"\u03A3", "Sigma"}, {"\u03A3", "#931"},
165             // greek capital letter tau
166             {"\u03A4", "Tau"}, {"\u03A4", "#932"},
167             // greek capital letter upsilon
168             {"\u03A5", "Upsilon"}, {"\u03A5", "#933"},
169             // greek capital letter phi
170             {"\u03A6", "Phi"}, {"\u03A6", "#934"},
171             // greek capital letter chi
172             {"\u03A7", "Chi"}, {"\u03A7", "#935"},
173             // greek capital letter psi
174             {"\u03A8", "Psi"}, {"\u03A8", "#936"},
175             // greek capital letter omega
176             {"\u03A9", "Omega"}, {"\u03A9", "#937"},
177             // greek small letter alpha
178             {"\u03B1", "alpha"}, {"\u03B1", "#945"},
179             // greek small letter beta
180             {"\u03B2", "beta"}, {"\u03B2", "#946"},
181             // greek small letter gamma
182             {"\u03B3", "gamma"}, {"\u03B3", "#947"},
183             // greek small letter delta
184             {"\u03B4", "delta"}, {"\u03B4", "#948"},
185             // greek small letter epsilon
186             {"\u03B5", "epsilon"}, {"\u03B5", "#949"},
187             // greek small letter zeta
188             {"\u03B6", "zeta"}, {"\u03B6", "#950"},
189             // greek small letter eta
190             {"\u03B7", "eta"}, {"\u03B7", "#951"},
191             // greek small letter theta
192             {"\u03B8", "theta"}, {"\u03B8", "#952"},
193             // greek small letter iota
194             {"\u03B9", "iota"}, {"\u03B9", "#953"},
195             // greek small letter kappa
196             {"\u03BA", "kappa"}, {"\u03BA", "#954"},
197             // greek small letter lambda
198             {"\u03BB", "lambda"}, {"\u03BB", "#955"},
199             // greek small letter mu
200             {"\u03BC", "mu"}, {"\u03BC", "#956"},
201             // greek small letter nu
202             {"\u03BD", "nu"}, {"\u03BD", "#957"},
203             // greek small letter xi
204             {"\u03BE", "xi"}, {"\u03BE", "#958"},
205             // greek small letter omicron
206             {"\u03BF", "omicron"}, {"\u03BF", "#959"},
207             // greek small letter pi
208             {"\u03C0", "pi"}, {"\u03C0", "#960"},
209             // greek small letter rho
210             {"\u03C1", "rho"}, {"\u03C1", "#961"},
211             // greek small letter final sigma
212             {"\u03C2", "sigmaf"}, {"\u03C2", "#962"},
213             // greek small letter sigma
214             {"\u03C3", "sigma"}, {"\u03C3", "#963"},
215             // greek small letter tau
216             {"\u03C4", "tau"}, {"\u03C4", "#964"},
217             // greek small letter upsilon
218             {"\u03C5", "upsilon"}, {"\u03C5", "#965"},
219             // greek small letter phi
220             {"\u03C6", "phi"}, {"\u03C6", "#966"},
221             // greek small letter chi
222             {"\u03C7", "chi"}, {"\u03C7", "#967"},
223             // greek small letter psi
224             {"\u03C8", "psi"}, {"\u03C8", "#968"},
225             // greek small letter omega
226             {"\u03C9", "omega"}, {"\u03C9", "#969"},
227             // greek small letter theta symbol
228             {"\u03D1", "thetasym"}, {"\u03D1", "#977"},
229             // greek upsilon with hook symbol
230             {"\u03D2", "upsih"}, {"\u03D2", "#978"},
231             // greek pi symbol
232             {"\u03D6", "piv"}, {"\u03D6", "#982"},
233             // en space
234             {"\u2002", "ensp"}, {"\u2002", "#8194"},
235             // em space
236             {"\u2003", "emsp"}, {"\u2003", "#8195"},
237             // thin space
238             {"\u2009", "thinsp"}, {"\u2009", "#8201"},
239             // zero width non-joiner
240             {"\u200C", "zwnj"}, {"\u200C", "#8204"},
241             // zero width joiner
242             {"\u200D", "zwj"}, {"\u200D", "#8205"},
243             // left-to-right mark
244             {"\u200E", "lrm"}, {"\u200E", "#8206"},
245             // right-to-left mark
246             {"\u200F", "rlm"}, {"\u200F", "#8207"},
247             // en dash
248             {"\u2013", "ndash"}, {"\u2013", "#8211"},
249             // em dash
250             {"\u2014", "mdash"}, {"\u2014", "#8212"},
251             // left single quotation mark
252             {"\u2018", "lsquo"}, {"\u2018", "#8216"},
253             // right single quotation mark
254             {"\u2019", "rsquo"}, {"\u2019", "#8217"},
255             // single low-9 quotation mark
256             {"\u201A", "sbquo"}, {"\u201A", "#8218"},
257             // left double quotation mark
258             {"\u201C", "ldquo"}, {"\u201C", "#8220"},
259             // right double quotation mark
260             {"\u201D", "rdquo"}, {"\u201D", "#8221"},
261             // double low-9 quotation mark
262             {"\u201E", "bdquo"}, {"\u201E", "#8222"},
263             // dagger
264             {"\u2020", "dagger"}, {"\u2020", "#8224"},
265             // double dagger
266             {"\u2021", "Dagger"}, {"\u2021", "#8225"},
267             // bullet = black small circle
268             {"\u2022", "bull"}, {"\u2022", "#8226"},
269             // horizontal ellipsis = three dot leader
270             {"\u2026", "hellip"}, {"\u2026", "#8230"},
271             // per mille sign
272             {"\u2030", "permil"}, {"\u2030", "#8240"},
273             // double prime = seconds = inches
274             {"\u2033", "Prime"}, {"\u2033", "#8243"},
275             // single left-pointing angle quotation mark
276             {"\u2039", "lsaquo"}, {"\u2039", "#8249"},
277             // single right-pointing angle quotation mark
278             {"\u203A", "rsaquo"}, {"\u203A", "#8250"},
279             // prime = minutes = feet
280             {"\u2032", "prime"}, {"\u2032", "#8242"},
281             // overline = spacing overscore
282             {"\u203E", "oline"}, {"\u203E", "#8254"},
283             // fraction slash
284             {"\u2044", "frasl"}, {"\u2044", "#8260"},
285             // euro sign
286             {"\u20AC", "euro"}, {"\u20AC", "#8364"},
287             // script capital P = power set = Weierstrass p
288             {"\u2118", "weierp"}, {"\u2118", "#8472"},
289             // blackletter capital I = imaginary part
290             {"\u2111", "image"}, {"\u2111", "#8465"},
291             // blackletter capital R = real part symbol
292             {"\u211C", "real"}, {"\u211C", "#8476"},
293             // trade mark sign
294             {"\u2122", "trade"}, {"\u2122", "#8482"},
295             // alef symbol = first transfinite cardinal
296             {"\u2135", "alefsym"}, {"\u2135", "#8501"},
297             // leftwards arrow
298             {"\u2190", "larr"}, {"\u2190", "#8592"},
299             // upwards arrow
300             {"\u2191", "uarr"}, {"\u2191", "#8593"},
301             // rightwards arrow
302             {"\u2192", "rarr"}, {"\u2192", "#8594"},
303             // downwards arrow
304             {"\u2193", "darr"}, {"\u2193", "#8595"},
305             // left right arrow
306             {"\u2194", "harr"}, {"\u2194", "#8596"},
307             // downwards arrow with corner leftwards = carriage return
308             {"\u21B5", "crarr"}, {"\u21B5", "#8629"},
309             // leftwards double arrow
310             {"\u21D0", "lArr"}, {"\u21D0", "#8656"},
311             // upwards double arrow
312             {"\u21D1", "uArr"}, {"\u21D1", "#8657"},
313             // rightwards double arrow
314             {"\u21D2", "rArr"}, {"\u21D2", "#8658"},
315             // downwards double arrow
316             {"\u21D3", "hArr"}, {"\u21D3", "#8659"},
317             // left right double arrow
318             {"\u21D4", "hArr"}, {"\u21D4", "#8660"},
319             // for all
320             {"\u2200", "forall"}, {"\u2200", "#8704"},
321             // partial differential
322             {"\u2202", "part"}, {"\u2202", "#8706"},
323             // there exists
324             {"\u2203", "exist"}, {"\u2203", "#8707"},
325             // empty set = null set = diameter
326             {"\u2205", "empty"}, {"\u2205", "#8709"},
327             // nabla = backward difference
328             {"\u2207", "nabla"}, {"\u2207", "#8711"},
329             // element of
330             {"\u2208", "isin"}, {"\u2208", "#8712"},
331             // not an element of
332             {"\u2209", "notin"}, {"\u2209", "#8713"},
333             // contains as member
334             {"\u220B", "ni"}, {"\u220B", "#8715"},
335             // n-ary product = product sign
336             {"\u220F", "prod"}, {"\u220F", "#8719"},
337             // n-ary sumation
338             {"\u2211", "sum"}, {"\u2211", "#8721"},
339             // minus sign
340             {"\u2212", "minus"}, {"\u2212", "#8722"},
341             // asterisk operator
342             {"\u2217", "lowast"}, {"\u2217", "#8727"},
343             // square root = radical sign
344             {"\u221A", "radic"}, {"\u221A", "#8730"},
345             // proportional to
346             {"\u221D", "prop"}, {"\u221D", "#8733"},
347             // infinity
348             {"\u221E", "infin"}, {"\u221E", "#8734"},
349             // angle
350             {"\u2220", "ang"}, {"\u2220", "#8736"},
351             // logical and = wedge
352             {"\u2227", "and"}, {"\u2227", "#8743"},
353             // logical or = vee
354             {"\u2228", "or"}, {"\u2228", "#8744"},
355             // intersection = cap
356             {"\u2229", "cap"}, {"\u2229", "#8745"},
357             // union = cup
358             {"\u222A", "cup"}, {"\u222A", "#8746"},
359             // integral
360             {"\u222B", "int"}, {"\u222B", "#8747"},
361             // therefore
362             {"\u2234", "there4"}, {"\u2234", "#8756"},
363             // tilde operator = varies with = similar to
364             {"\u223C", "sim"}, {"\u223C", "#8764"},
365             // approximately equal to
366             {"\u2245", "cong"}, {"\u2245", "#8773"},
367             // almost equal to = asymptotic to
368             {"\u2248", "asymp"}, {"\u2248", "#8776"},
369             // not equal to
370             {"\u2260", "ne"}, {"\u2260", "#8800"},
371             // identical to
372             {"\u2261", "equiv"}, {"\u2261", "#8801"},
373             // less-than or equal to
374             {"\u2264", "le"}, {"\u2264", "#8804"},
375             // greater-than or equal to
376             {"\u2265", "ge"}, {"\u2265", "#8805"},
377             // subset of
378             {"\u2282", "sub"}, {"\u2282", "#8834"},
379             // superset of
380             {"\u2283", "sup"}, {"\u2283", "#8835"},
381             // not a subset of
382             {"\u2284", "nsub"}, {"\u2284", "#8836"},
383             // subset of or equal to
384             {"\u2286", "sube"}, {"\u2286", "#8838"},
385             // superset of or equal to
386             {"\u2287", "supe"}, {"\u2287", "#8839"},
387             // circled plus = direct sum
388             {"\u2295", "oplus"}, {"\u2295", "#8853"},
389             // circled times = vector product
390             {"\u2297", "otimes"}, {"\u2297", "#8855"},
391             // up tack = orthogonal to = perpendicular
392             {"\u22A5", "perp"}, {"\u22A5", "#8869"},
393             // dot operator
394             {"\u22C5", "sdot"}, {"\u22C5", "#8901"},
395             // left ceiling = apl upstile
396             {"\u2308", "lceil"}, {"\u2308", "#8968"},
397             // right ceiling
398             {"\u2309", "rceil"}, {"\u2309", "#8969"},
399             // left floor = apl downstile
400             {"\u230A", "lfloor"}, {"\u230A", "#8970"},
401             // right floor
402             {"\u230B", "rfloor"}, {"\u230B", "#8971"},
403             // left-pointing angle bracket = bra
404             {"\u2329", "lang"}, {"\u2329", "#9001"},
405             // right-pointing angle bracket = ket
406             {"\u232A", "rang"}, {"\u232A", "#9002"},
407             // lozenge
408             {"\u25CA", "loz"}, {"\u25CA", "#9674"},
409             // black spade suit
410             {"\u2660", "spades"}, {"\u2660", "#9824"},
411             // black club suit = shamrock
412             {"\u2663", "clubs"}, {"\u2663", "#9827"},
413             // black heart suit = valentine
414             {"\u2665", "hearts"}, {"\u2665", "#9829"},
415             // black diamond suit
416             {"\u2666", "diams"}, {"\u2666", "#9830"} };
417     /***
418      * This array stores all of the character entities we want to convert.
419      */
420     private static String[] entitiesArray = null;
421     /***
422      * Each character in this array maps to an entity in
423      * <code>entitiesArray</code>.
424      */
425     private static String entityMapString;
426     /***
427      * This is tag is placed after anything which should not be converted. It is
428      * used by other formats.
429      */
430     private static final String KEEP_END = "</KEEP:>";
431     /***
432      * This is tag is placed before anything which should not be converted. It
433      * is used by other formats.
434      */
435     private static final String KEEP_START = "<KEEP:>";
436     /***
437      * Just what it says on the tin - no character entity string can be longer
438      * than this limit.
439      */
440     private static final int MAXIMUM_ENTITY_LENGTH = 15;
441     /***
442      * Refer to {@link #isReverse}.
443      */
444     private boolean reverse = false;
445     /***
446      * <p>
447      * Default constructor.
448      * </p>
449      */
450     public CharacterEntityFormat() {
451         // this will speed up the conversion of HTML entities
452         // we put them into the array of array of strings to make it more
453         // manageable :-)
454         if (entitiesArray == null) {
455             int length = CharacterEntityFormat.ENTITIES.length;
456             StringBuffer temporaryBuffer = new StringBuffer();
457             entitiesArray = new String[length];
458             for (int n = 0; n < length; ++n) {
459                 temporaryBuffer.append(CharacterEntityFormat.ENTITIES[n][0]);
460                 entitiesArray[n] = "&" + CharacterEntityFormat.ENTITIES[n][1]
461                         + ";";
462                 // this code can be used to calculate the maximum entity length
463                 /*
464                  * if (entities[n][1].length() > MAXIMUM_ENTITY_LENGTH) {
465                  * MAXIMUM_ENTITY_LENGTH = entities[n][1].length(); }
466                  */
467             }
468             entityMapString = temporaryBuffer.toString();
469         }
470     }
471     /***
472      * <p>
473      * Convert the character entities in the text provided.
474      * </p>
475      *
476      * @param hTMLText a text to convert all the character entities in
477      * @return formatted text where all of the characters are converted to the
478      *      appropriate character entities.
479      */
480     public final String format(final String hTMLText) {
481         StringBuffer returnBuffer = new StringBuffer();
482         int length = hTMLText.length();
483         int index;
484         int indexStart = hTMLText.indexOf(KEEP_START);
485         int indexEnd;
486         for (int n = 0; n < length; ++n) {
487             // if we have reached the next keep section (and there is one)
488             if ((indexStart > -1) && (indexStart == n)) {
489                 // find the end of the keep section
490                 if ((indexEnd = hTMLText.indexOf(KEEP_END, indexStart)) != -1) {
491                     int keepEndPosition = KEEP_END.length() + 1;
492                     returnBuffer.append(hTMLText.substring(indexStart
493                             + keepEndPosition, indexEnd));
494                     n = indexEnd + keepEndPosition;
495                     indexStart = hTMLText.indexOf(KEEP_START, n);
496                 } else {
497                     //  no end tag -> ignore
498                     indexStart = -1;
499                 }
500             } else {
501                 int semiIndex = n;
502                 char ch = hTMLText.charAt(n);
503                 StringBuffer entity = null;
504                 // is there a character entity at this point?
505                 if (ch == '&') {
506                     // look ahead for the semicolon
507                     for (entity = new StringBuffer(MAXIMUM_ENTITY_LENGTH);
508                                 (semiIndex < length)
509                             && ((semiIndex - n + 1) <= MAXIMUM_ENTITY_LENGTH);
510                                 ++semiIndex) {
511                         char semi = hTMLText.charAt(semiIndex);
512                         // add the character to the buffer
513                         entity.append(semi);
514                         // if we found a semi-colon, that's great. this is a
515                         // real entity.
516                         if (semi == ';') {
517                             break;
518                         }
519                         // if this is not alphanumeric or hash, remove the
520                         // entity buffer
521                         if ((semi != '&') && (semi != '#')
522                                 && !Character.isLetterOrDigit(semi)) {
523                             entity = null;
524                             break;
525                         }
526                     }
527                 }
528                 // if we go in reverse direction, look for character entities
529                 if (reverse) {
530                     // if there was an entity, try to convert it
531                     if (entity == null) {
532                         returnBuffer.append(ch);
533                     } else if (entity.toString().equalsIgnoreCase("nbsp")) {
534                         // this is a special case - it only translates one way
535                         returnBuffer.append(' ');
536                         n = semiIndex;
537                     } else {
538                         String compare = entity.toString();
539                         for (int arrayIndex = 0;
540                                 arrayIndex < entitiesArray.length;
541                                 ++arrayIndex) {
542                             if (entitiesArray[arrayIndex].equals(compare)) {
543                                 returnBuffer.append(entityMapString
544                                         .charAt(arrayIndex));
545                                 entity = null;
546                                 n = semiIndex;
547                                 break;
548                             }
549                         }
550                         if (entity != null) {
551                             returnBuffer.append(ch);
552                         }
553                     }
554                 } else if (entity == null) {
555                     // see if we should convert the character
556                     if ((index = entityMapString.indexOf(ch)) == -1) {
557                         returnBuffer.append(ch);
558                     } else {
559                         returnBuffer.append(entitiesArray[index]);
560                     }
561                 } else {
562                     // if this is not reverse direction, and an entity was found
563                     // then skip past it no matter what
564                     n = semiIndex;
565                     returnBuffer.append(entity.toString());
566                 }
567             }
568         }
569         return returnBuffer.toString();
570     }
571     /***
572      * <p>
573      * Gets whether or not character entity conversion goes in the opposite
574      * direction. If character entities are converted to characters then this
575      * method returns <code>true</code>, otherwise <code>false</code>
576      * </p>
577      *
578      * @return <code>true</code> if character entities are converted to
579      *     characters, otherwise <code>false</code>/
580      */
581     public final boolean isReverse() {
582         return reverse;
583     }
584     /***
585      * <p>
586      * Set whether or not character entity conversion goes in the opposite
587      * direction.
588      * </p>
589      *
590      * @param newReverse set to <code>true</code> if character entities should
591      *      be converted to characters, otherwise <code>false</code>.
592      */
593     public final void setReverse(final boolean newReverse) {
594         reverse = newReverse;
595     }
596 }