/** * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.html.refs; import java.util.Comparator; import org.exoplatform.services.chars.CharsUtil; /** * Author : Nhu Dinh Thuan nhudinhthuan@yahoo.com May 8, 2006 */ public class RefsDecoder { private static final CharRefs charRefs = new CharRefs(); static Comparator<CharRef> comparator = new Comparator<CharRef>() { public int compare(CharRef o1, CharRef o2) { return o1.getName().compareTo(o2.getName()); } }; public String decode(String text) { return new String(decodeChars(text.toCharArray())); } public char[] decode(char[] chars) { return decodeChars(chars); } private char[] decodeChars(char[] chars) { if (!charRefs.isSorted()) charRefs.sort(comparator); int index = CharsUtil.indexOf(chars, '&', 0); if (index < 0 || CharsUtil.indexOf(chars, ';', index) < 0) return chars; CharsSequence decode = new CharsSequence(chars.length); int temp = 0; int end = 0; boolean ref = true; char[] ckey = null; while (index < chars.length) { if (temp < index) copy(chars, decode, temp, index); end = CharsUtil.indexOf(chars, ';', index); if (end < 0) break; if (chars[index + 1] == '#') { ckey = new char[end - index - 2]; System.arraycopy(chars, index + 2, ckey, 0, ckey.length); ref = false; } else { ckey = new char[end - index - 1]; System.arraycopy(chars, index + 1, ckey, 0, ckey.length); ref = true; } if (!ref) { ref = decode(ckey, decode); } else { if (Character.isLetter(ckey[0])) { CharRef item = charRefs.searchByName(new String(ckey), comparator); if (item != null) { decode.append((char) item.getValue()); } else { copy(chars, decode, index, end + 1); } } else { copy(chars, decode, index, end); } } temp = end + 1; index = CharsUtil.indexOf(chars, '&', temp); if (index < 0) break; } copy(chars, decode, temp, chars.length); return decode.getValues(); } private void copy(char[] chars, CharsSequence decode, int start, int end) { while (start < chars.length) { if (start == end) break; decode.append(chars[start]); start++; } } private boolean decode(char[] values, CharsSequence decode) { char character; int number = 0; int radix = 0; boolean done = false; int i = 0; while (i < values.length && !done) { character = values[i]; if (Character.isDigit(character)) { if (radix == 0) radix = 10; number = number * radix + (character - '0'); } else { switch (character) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': if (radix == 16) number = number * radix + (character - 'A' + 10); else done = true; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (radix == 16) number = number * radix + (character - 'a' + 10); else done = true; break; case 'x': case 'X': if (radix == 0) radix = 16; else done = true; break; case ';': done = true; i++; break; default: done = true; break; } } if (!done) i++; } if (number == 0) return true; decode.append((char) number); return false; } }