/* * Copyright 2008-2014 by Emeric Vernat * * This file is part of Java Melody. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.bull.javamelody.swing.print; import java.util.Arrays; /** * Encodage de chaines au format HTML. * * @author Emeric Vernat */ final class MHtmlEncoder { /** * Liste des caracteres speciaux HTML triée. Remplie dans le init static */ private static final char[] TO_REPLACE; /** * Liste des chaines remplacantes triée dans le même ordre que to_replace. Remplie dans le init static */ private static final char[][] REPLACE_BY; /** * Initialisation de la classe. 1) tri de la liste de caracteres speciaux 2) generation des tables de remplacement * * @formatter:off */ static { // Mapping des caractères spéciaux vers leur code HTML // Respecter l'espace entre le caractere et son code. final String[] htmlCharacters = { "€ €", "Œ Œ", "œ œ", // latin-15 // pas de nbsp (insécable à l'impression) "  ", "\n <br/>", "\r ", "\t     ", "< <", "& &", "Æ Æ", "À À", "Ä Ä", "É É", "Ë Ë", "Ì Ì", "Ó Ó", "Ø Ø", "Þ Þ", "Ù Ù", "á á", "à à", "ä ä", "ê ê", "ë ë", "ì ì", "ó ó", "ø ø", "ß ß", "û û", "ý ý", "¤ ¤", "§ §", "ª ª", "­ ­", "° °", "³ ³", "¶ ¶", "¹ ¹", "¼ ¼", "¿ ¿", "× ×", "÷ ÷", "¢ ¢", "> >", "\" "", "' '", "` '", "Á Á", "Å Å", "Ç Ç", "Ê Ê", "Í Í", "Ï Ï", "Ô Ô", "Õ Õ", "Ú Ú", "Ü Ü", "â â", "å å", "ç ç", "è è", "í í", "ï ï", "ô ô", "õ õ", "þ þ", "ù ù", "ÿ ÿ", "¡ ¡", "¥ ¥", "¨ ¨", "« «", "® ®", "± ±", "´ ´", "· ·", "º º", "½ ½", " Â", "à Ã", "Ð Ð", "È È", "Î Î", "Ñ Ñ", "Ò Ò", "Ö Ö", "Û Û", "Ý Ý", "æ æ", "ã ã", "é é", "ð ð", "î î", "ñ ñ", "ò ò", "ö ö", "ú ú", "ü ü", "£ £", "¦ ¦", "© ©", "¬ ¬", "¯ ¯", "² ²", "µ µ", "¸ ¸", "» »", "¾ ¾", "‘ ‘", "’ ’", "‚ ‚", "“ “", "” ”", "„ „", "† †", "‡ ‡", "‰ ‰", "‹ ‹", "› ›", "™ ™", "– –", "— —", }; // tri de la table des caracteres HTML Arrays.sort(htmlCharacters); final int length = htmlCharacters.length; TO_REPLACE = new char[length]; REPLACE_BY = new char[length][]; for (int i = 0; i < length; i++) { // premier caractere dans la table des carateres a remplacer TO_REPLACE[i] = htmlCharacters[i].charAt(0); // à partir du troisième caractere : // dans la table des codes remplacants REPLACE_BY[i] = htmlCharacters[i].substring(2).toCharArray(); } } /** * Constructeur. */ private MHtmlEncoder() { super(); } /** * Retourne une chaine encodée. * * @return String Chaine encodée * @param s * String Chaine à encoder */ public static String encodeString(final String s) { if (s != null) { final StringBuilder sb = new StringBuilder(s.length() + s.length() / 4); encodeString(sb, s); return sb.toString(); } return ""; } /** * Append une chaine à un StringBuilder apres l'avoir encodée. Plus la chaine à encoder est longue, plus les gains de perfs sont sensibles. * * @param sb * String StringBuilder à appender. * @param s * String Chaine à encoder et à ajouter à <CODE>sb</CODE> */ public static void encodeString(final StringBuilder sb, final String s) { if (s == null) { return; } final int len = s.length(); // réserve un peu plus de place dans le StringBuilder sb.ensureCapacity(sb.length() + len + len / 4); int i; int index; char c; for (i = 0; i < len; i++) { c = s.charAt(i); // petite optimisation (qui represente 90% des cas...) if (isSimpleLetterOrDigit(c)) { sb.append(c); } else { // cherche dans le tableau des caractères index = Arrays.binarySearch(TO_REPLACE, c); if (index >= 0) { // si trouvé, append la chaîne remplaçante sb.append(REPLACE_BY[index]); } else if (c < '\u0020' || c > '\u007e') { // si c'est un caractère bizarre non reconnu, on code son numéro décimal (en charset iso-8859-1) sb.append("&#").append(Integer.toString(c)).append(';'); } else { // sinon append le caractère sans le modifier sb.append(c); // nécessite un charset système genre windows-1252 } } } } private static boolean isSimpleLetterOrDigit(char c) { return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'; } }