/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 com.xpn.xwiki.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.Vector;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.oro.text.PatternCache;
import org.apache.oro.text.PatternCacheLRU;
import org.apache.oro.text.perl.Perl5Util;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternMatcherInput;
import org.apache.oro.text.regex.Perl5Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xwiki.container.Container;
import org.xwiki.xml.XMLUtils;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.monitor.api.MonitorPlugin;
import com.xpn.xwiki.render.WikiSubstitution;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiRequest;
public class Util
{
/**
* Encoding used for URL encoding/decoding. UTF-8 is the default encoding in RFC 3986, and is recommended by the W3
* consortium.
*/
private static final String URL_ENCODING = "UTF-8";
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
private static PatternCache patterns = new PatternCacheLRU(200);
private Perl5Matcher matcher = new Perl5Matcher();
private Perl5Util p5util = new Perl5Util(getPatterns());
public String substitute(String pattern, String text)
{
return getP5util().substitute(pattern, text);
}
public boolean match(String pattern, String text)
{
return getP5util().match(pattern, text);
}
public boolean matched()
{
return (getP5util().getMatch() != null);
}
public String substitute(String pattern, String substitution, String text)
{
WikiSubstitution subst = new WikiSubstitution(this, pattern);
subst.setSubstitution(substitution);
return subst.substitute(text);
}
public Perl5Matcher getMatcher()
{
return this.matcher;
}
public Perl5Util getP5util()
{
return this.p5util;
}
public List<String> getAllMatches(String content, String spattern, int group) throws MalformedPatternException
{
List<String> list = new ArrayList<String>();
PatternMatcherInput input = new PatternMatcherInput(content);
Pattern pattern = patterns.addPattern(spattern);
while (this.matcher.contains(input, pattern)) {
MatchResult result = this.matcher.getMatch();
String smatch = result.group(group);
list.add(smatch);
}
return list;
}
public List<String> getUniqueMatches(String content, String spattern, int group) throws MalformedPatternException
{
// Remove duplicate entries
Set<String> uniqueMatches = new HashSet<String>();
uniqueMatches.addAll(getAllMatches(content, spattern, group));
List<String> matches = new ArrayList<String>();
matches.addAll(uniqueMatches);
return matches;
}
public static String cleanValue(String value)
{
value = StringUtils.replace(value, "\r\r\n", "%_N_%");
value = StringUtils.replace(value, "\r\n", "%_N_%");
value = StringUtils.replace(value, "\n\r", "%_N_%");
value = StringUtils.replace(value, "\r", "\n");
value = StringUtils.replace(value, "\n", "%_N_%");
value = StringUtils.replace(value, "\"", "%_Q_%");
return value;
}
public static String restoreValue(String value)
{
value = StringUtils.replace(value, "%_N_%", "\n");
value = StringUtils.replace(value, "%_Q_%", "\"");
return value;
}
/**
* Create a Map from a string holding a space separated list of key=value pairs. If keys or values must contain
* spaces, they can be placed inside quotes, like <code>"this key"="a larger value"</code>. To use a quote as part
* of a key/value, use <code>%_Q_%</code>.
*
* @param mapString The string that must be parsed.
* @return A Map containing the keys and values. If a key is defined more than once, the last value is used.
*/
public static Hashtable<String, String> keyValueToHashtable(String mapString) throws IOException
{
Hashtable<String, String> result = new Hashtable<String, String>();
StreamTokenizer st = new StreamTokenizer(new BufferedReader(new StringReader(mapString)));
st.resetSyntax();
st.quoteChar('"');
st.wordChars('a', 'z');
st.wordChars('A', 'Z');
st.whitespaceChars(' ', ' ');
st.whitespaceChars('=', '=');
while (st.nextToken() != StreamTokenizer.TT_EOF) {
String key = st.sval;
st.nextToken();
String value = (st.sval != null) ? st.sval : "";
result.put(key, restoreValue(value));
}
return result;
}
public static PatternCache getPatterns()
{
return patterns;
}
public static Map<String, String[]> getObject(XWikiRequest request, String prefix)
{
@SuppressWarnings("unchecked")
Map<String, String[]> parameters = request.getParameterMap();
return getSubMap(parameters, prefix);
}
public static <T> Map<String, T> getSubMap(Map<String, T> map, String prefix)
{
Map<String, T> result = new HashMap<String, T>();
for (String name : map.keySet()) {
if (name.startsWith(prefix + "_")) {
String newname = name.substring(prefix.length() + 1);
result.put(newname, map.get(name));
} else if (name.equals(prefix)) {
result.put("", map.get(name));
}
}
return result;
}
public static String getWeb(String fullname)
{
int i = fullname.lastIndexOf(".");
return fullname.substring(0, i);
}
public Vector<String> split(String pattern, String text)
{
Vector<String> results = new Vector<String>();
getP5util().split(results, pattern, text);
return results;
}
public static boolean contains(String name, String list, String sep)
{
String[] sarray = StringUtils.split(list, sep);
return ArrayUtils.contains(sarray, name);
}
public static String noaccents(String text)
{
String temp = text;
temp = temp.replaceAll("\u00c0", "A");
temp = temp.replaceAll("\u00c1", "A");
temp = temp.replaceAll("\u00c2", "A");
temp = temp.replaceAll("\u00c3", "A");
temp = temp.replaceAll("\u00c4", "A");
temp = temp.replaceAll("\u00c5", "A");
temp = temp.replaceAll("\u0100", "A");
temp = temp.replaceAll("\u0102", "A");
temp = temp.replaceAll("\u0104", "A");
temp = temp.replaceAll("\u01cd", "A");
temp = temp.replaceAll("\u01de", "A");
temp = temp.replaceAll("\u01e0", "A");
temp = temp.replaceAll("\u01fa", "A");
temp = temp.replaceAll("\u0200", "A");
temp = temp.replaceAll("\u0202", "A");
temp = temp.replaceAll("\u0226", "A");
temp = temp.replaceAll("\u00e0", "a");
temp = temp.replaceAll("\u00e1", "a");
temp = temp.replaceAll("\u00e2", "a");
temp = temp.replaceAll("\u00e3", "a");
temp = temp.replaceAll("\u00e4", "a");
temp = temp.replaceAll("\u00e5", "a");
temp = temp.replaceAll("\u0101", "a");
temp = temp.replaceAll("\u0103", "a");
temp = temp.replaceAll("\u0105", "a");
temp = temp.replaceAll("\u01ce", "a");
temp = temp.replaceAll("\u01df", "a");
temp = temp.replaceAll("\u01e1", "a");
temp = temp.replaceAll("\u01fb", "a");
temp = temp.replaceAll("\u0201", "a");
temp = temp.replaceAll("\u0203", "a");
temp = temp.replaceAll("\u0227", "a");
temp = temp.replaceAll("\u00c6", "AE");
temp = temp.replaceAll("\u01e2", "AE");
temp = temp.replaceAll("\u01fc", "AE");
temp = temp.replaceAll("\u00e6", "ae");
temp = temp.replaceAll("\u01e3", "ae");
temp = temp.replaceAll("\u01fd", "ae");
temp = temp.replaceAll("\u008c", "OE");
temp = temp.replaceAll("\u0152", "OE");
temp = temp.replaceAll("\u009c", "oe");
temp = temp.replaceAll("\u0153", "oe");
temp = temp.replaceAll("\u00c7", "C");
temp = temp.replaceAll("\u0106", "C");
temp = temp.replaceAll("\u0108", "C");
temp = temp.replaceAll("\u010a", "C");
temp = temp.replaceAll("\u010c", "C");
temp = temp.replaceAll("\u00e7", "c");
temp = temp.replaceAll("\u0107", "c");
temp = temp.replaceAll("\u0109", "c");
temp = temp.replaceAll("\u010b", "c");
temp = temp.replaceAll("\u010d", "c");
temp = temp.replaceAll("\u00d0", "D");
temp = temp.replaceAll("\u010e", "D");
temp = temp.replaceAll("\u0110", "D");
temp = temp.replaceAll("\u00f0", "d");
temp = temp.replaceAll("\u010f", "d");
temp = temp.replaceAll("\u0111", "d");
temp = temp.replaceAll("\u00c8", "E");
temp = temp.replaceAll("\u00c9", "E");
temp = temp.replaceAll("\u00ca", "E");
temp = temp.replaceAll("\u00cb", "E");
temp = temp.replaceAll("\u0112", "E");
temp = temp.replaceAll("\u0114", "E");
temp = temp.replaceAll("\u0116", "E");
temp = temp.replaceAll("\u0118", "E");
temp = temp.replaceAll("\u011a", "E");
temp = temp.replaceAll("\u0204", "E");
temp = temp.replaceAll("\u0206", "E");
temp = temp.replaceAll("\u0228", "E");
temp = temp.replaceAll("\u00e8", "e");
temp = temp.replaceAll("\u00e9", "e");
temp = temp.replaceAll("\u00ea", "e");
temp = temp.replaceAll("\u00eb", "e");
temp = temp.replaceAll("\u0113", "e");
temp = temp.replaceAll("\u0115", "e");
temp = temp.replaceAll("\u0117", "e");
temp = temp.replaceAll("\u0119", "e");
temp = temp.replaceAll("\u011b", "e");
temp = temp.replaceAll("\u01dd", "e");
temp = temp.replaceAll("\u0205", "e");
temp = temp.replaceAll("\u0207", "e");
temp = temp.replaceAll("\u0229", "e");
temp = temp.replaceAll("\u011c", "G");
temp = temp.replaceAll("\u011e", "G");
temp = temp.replaceAll("\u0120", "G");
temp = temp.replaceAll("\u0122", "G");
temp = temp.replaceAll("\u01e4", "G");
temp = temp.replaceAll("\u01e6", "G");
temp = temp.replaceAll("\u01f4", "G");
temp = temp.replaceAll("\u011d", "g");
temp = temp.replaceAll("\u011f", "g");
temp = temp.replaceAll("\u0121", "g");
temp = temp.replaceAll("\u0123", "g");
temp = temp.replaceAll("\u01e5", "g");
temp = temp.replaceAll("\u01e7", "g");
temp = temp.replaceAll("\u01f5", "g");
temp = temp.replaceAll("\u0124", "H");
temp = temp.replaceAll("\u0126", "H");
temp = temp.replaceAll("\u021e", "H");
temp = temp.replaceAll("\u0125", "h");
temp = temp.replaceAll("\u0127", "h");
temp = temp.replaceAll("\u021f", "h");
temp = temp.replaceAll("\u00cc", "I");
temp = temp.replaceAll("\u00cd", "I");
temp = temp.replaceAll("\u00ce", "I");
temp = temp.replaceAll("\u00cf", "I");
temp = temp.replaceAll("\u0128", "I");
temp = temp.replaceAll("\u012a", "I");
temp = temp.replaceAll("\u012c", "I");
temp = temp.replaceAll("\u012e", "I");
temp = temp.replaceAll("\u0130", "I");
temp = temp.replaceAll("\u01cf", "I");
temp = temp.replaceAll("\u0208", "I");
temp = temp.replaceAll("\u020a", "I");
temp = temp.replaceAll("\u00ec", "i");
temp = temp.replaceAll("\u00ed", "i");
temp = temp.replaceAll("\u00ee", "i");
temp = temp.replaceAll("\u00ef", "i");
temp = temp.replaceAll("\u0129", "i");
temp = temp.replaceAll("\u012b", "i");
temp = temp.replaceAll("\u012d", "i");
temp = temp.replaceAll("\u012f", "i");
temp = temp.replaceAll("\u0131", "i");
temp = temp.replaceAll("\u01d0", "i");
temp = temp.replaceAll("\u0209", "i");
temp = temp.replaceAll("\u020b", "i");
temp = temp.replaceAll("\u0132", "IJ");
temp = temp.replaceAll("\u0133", "ij");
temp = temp.replaceAll("\u0134", "J");
temp = temp.replaceAll("\u0135", "j");
temp = temp.replaceAll("\u0136", "K");
temp = temp.replaceAll("\u01e8", "K");
temp = temp.replaceAll("\u0137", "k");
temp = temp.replaceAll("\u0138", "k");
temp = temp.replaceAll("\u01e9", "k");
temp = temp.replaceAll("\u0139", "L");
temp = temp.replaceAll("\u013b", "L");
temp = temp.replaceAll("\u013d", "L");
temp = temp.replaceAll("\u013f", "L");
temp = temp.replaceAll("\u0141", "L");
temp = temp.replaceAll("\u013a", "l");
temp = temp.replaceAll("\u013c", "l");
temp = temp.replaceAll("\u013e", "l");
temp = temp.replaceAll("\u0140", "l");
temp = temp.replaceAll("\u0142", "l");
temp = temp.replaceAll("\u0234", "l");
temp = temp.replaceAll("\u00d1", "N");
temp = temp.replaceAll("\u0143", "N");
temp = temp.replaceAll("\u0145", "N");
temp = temp.replaceAll("\u0147", "N");
temp = temp.replaceAll("\u014a", "N");
temp = temp.replaceAll("\u01f8", "N");
temp = temp.replaceAll("\u00f1", "n");
temp = temp.replaceAll("\u0144", "n");
temp = temp.replaceAll("\u0146", "n");
temp = temp.replaceAll("\u0148", "n");
temp = temp.replaceAll("\u0149", "n");
temp = temp.replaceAll("\u014b", "n");
temp = temp.replaceAll("\u01f9", "n");
temp = temp.replaceAll("\u0235", "n");
temp = temp.replaceAll("\u00d2", "O");
temp = temp.replaceAll("\u00d3", "O");
temp = temp.replaceAll("\u00d4", "O");
temp = temp.replaceAll("\u00d5", "O");
temp = temp.replaceAll("\u00d6", "O");
temp = temp.replaceAll("\u00d8", "O");
temp = temp.replaceAll("\u014c", "O");
temp = temp.replaceAll("\u014e", "O");
temp = temp.replaceAll("\u0150", "O");
temp = temp.replaceAll("\u01d1", "O");
temp = temp.replaceAll("\u01ea", "O");
temp = temp.replaceAll("\u01ec", "O");
temp = temp.replaceAll("\u01fe", "O");
temp = temp.replaceAll("\u020c", "O");
temp = temp.replaceAll("\u020e", "O");
temp = temp.replaceAll("\u022a", "O");
temp = temp.replaceAll("\u022c", "O");
temp = temp.replaceAll("\u022e", "O");
temp = temp.replaceAll("\u0230", "O");
temp = temp.replaceAll("\u00f2", "o");
temp = temp.replaceAll("\u00f3", "o");
temp = temp.replaceAll("\u00f4", "o");
temp = temp.replaceAll("\u00f5", "o");
temp = temp.replaceAll("\u00f6", "o");
temp = temp.replaceAll("\u00f8", "o");
temp = temp.replaceAll("\u014d", "o");
temp = temp.replaceAll("\u014f", "o");
temp = temp.replaceAll("\u0151", "o");
temp = temp.replaceAll("\u01d2", "o");
temp = temp.replaceAll("\u01eb", "o");
temp = temp.replaceAll("\u01ed", "o");
temp = temp.replaceAll("\u01ff", "o");
temp = temp.replaceAll("\u020d", "o");
temp = temp.replaceAll("\u020f", "o");
temp = temp.replaceAll("\u022b", "o");
temp = temp.replaceAll("\u022d", "o");
temp = temp.replaceAll("\u022f", "o");
temp = temp.replaceAll("\u0231", "o");
temp = temp.replaceAll("\u0156", "R");
temp = temp.replaceAll("\u0158", "R");
temp = temp.replaceAll("\u0210", "R");
temp = temp.replaceAll("\u0212", "R");
temp = temp.replaceAll("\u0157", "r");
temp = temp.replaceAll("\u0159", "r");
temp = temp.replaceAll("\u0211", "r");
temp = temp.replaceAll("\u0213", "r");
temp = temp.replaceAll("\u015a", "S");
temp = temp.replaceAll("\u015c", "S");
temp = temp.replaceAll("\u015e", "S");
temp = temp.replaceAll("\u0160", "S");
temp = temp.replaceAll("\u0218", "S");
temp = temp.replaceAll("\u015b", "s");
temp = temp.replaceAll("\u015d", "s");
temp = temp.replaceAll("\u015f", "s");
temp = temp.replaceAll("\u0161", "s");
temp = temp.replaceAll("\u0219", "s");
temp = temp.replaceAll("\u00de", "T");
temp = temp.replaceAll("\u0162", "T");
temp = temp.replaceAll("\u0164", "T");
temp = temp.replaceAll("\u0166", "T");
temp = temp.replaceAll("\u021a", "T");
temp = temp.replaceAll("\u00fe", "t");
temp = temp.replaceAll("\u0163", "t");
temp = temp.replaceAll("\u0165", "t");
temp = temp.replaceAll("\u0167", "t");
temp = temp.replaceAll("\u021b", "t");
temp = temp.replaceAll("\u0236", "t");
temp = temp.replaceAll("\u00d9", "U");
temp = temp.replaceAll("\u00da", "U");
temp = temp.replaceAll("\u00db", "U");
temp = temp.replaceAll("\u00dc", "U");
temp = temp.replaceAll("\u0168", "U");
temp = temp.replaceAll("\u016a", "U");
temp = temp.replaceAll("\u016c", "U");
temp = temp.replaceAll("\u016e", "U");
temp = temp.replaceAll("\u0170", "U");
temp = temp.replaceAll("\u0172", "U");
temp = temp.replaceAll("\u01d3", "U");
temp = temp.replaceAll("\u01d5", "U");
temp = temp.replaceAll("\u01d7", "U");
temp = temp.replaceAll("\u01d9", "U");
temp = temp.replaceAll("\u01db", "U");
temp = temp.replaceAll("\u0214", "U");
temp = temp.replaceAll("\u0216", "U");
temp = temp.replaceAll("\u00f9", "u");
temp = temp.replaceAll("\u00fa", "u");
temp = temp.replaceAll("\u00fb", "u");
temp = temp.replaceAll("\u00fc", "u");
temp = temp.replaceAll("\u0169", "u");
temp = temp.replaceAll("\u016b", "u");
temp = temp.replaceAll("\u016d", "u");
temp = temp.replaceAll("\u016f", "u");
temp = temp.replaceAll("\u0171", "u");
temp = temp.replaceAll("\u0173", "u");
temp = temp.replaceAll("\u01d4", "u");
temp = temp.replaceAll("\u01d6", "u");
temp = temp.replaceAll("\u01d8", "u");
temp = temp.replaceAll("\u01da", "u");
temp = temp.replaceAll("\u01dc", "u");
temp = temp.replaceAll("\u0215", "u");
temp = temp.replaceAll("\u0217", "u");
temp = temp.replaceAll("\u0174", "W");
temp = temp.replaceAll("\u0175", "w");
temp = temp.replaceAll("\u00dd", "Y");
temp = temp.replaceAll("\u0176", "Y");
temp = temp.replaceAll("\u0178", "Y");
temp = temp.replaceAll("\u0232", "Y");
temp = temp.replaceAll("\u00fd", "y");
temp = temp.replaceAll("\u00ff", "y");
temp = temp.replaceAll("\u0177", "y");
temp = temp.replaceAll("\u0233", "y");
temp = temp.replaceAll("\u0179", "Z");
temp = temp.replaceAll("\u017b", "Z");
temp = temp.replaceAll("\u017d", "Z");
temp = temp.replaceAll("\u017a", "z");
temp = temp.replaceAll("\u017c", "z");
temp = temp.replaceAll("\u017e", "z");
temp = temp.replaceAll("\u00df", "ss");
return temp;
}
public static boolean isAlphaNumeric(String text)
{
return StringUtils.isAlphanumeric(text.replace('-', 'a').replace('.', 'a'));
}
public static String getName(String name)
{
int i0 = name.indexOf(":");
if (i0 != -1) {
name = name.substring(i0 + 1);
return name;
}
if (name.indexOf(".") != -1) {
return name;
} else {
return "XWiki." + name;
}
}
public static String getName(String name, XWikiContext context)
{
String database = null;
int i0 = name.indexOf(":");
if (i0 != -1) {
database = name.substring(0, i0);
name = name.substring(i0 + 1);
context.setWikiId(database);
return name;
}
// This does not make sense
// context.setWikiId(context.getWiki().getDatabase());
if (name.indexOf(".") != -1) {
return name;
} else {
return "XWiki." + name;
}
}
public static Cookie getCookie(String cookieName, XWikiContext context)
{
return getCookie(cookieName, context.getRequest());
}
public static Cookie getCookie(String cookieName, HttpServletRequest request)
{
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookieName.equals(cookie.getName())) {
return (cookie);
}
}
}
return null;
}
public static String getHTMLExceptionMessage(XWikiException xe, XWikiContext context)
{
String title = XMLUtils.escape(xe.getMessage());
String text = XMLUtils.escape(xe.getFullMessage());
return "<div class=\"xwikirenderingerror\" title=\"Read technical information related to this error\" "
+ "style=\"cursor: pointer;\">" + title + "</div>"
+ "<div class=\"xwikirenderingerrordescription hidden\"><pre>" + text + "</pre></div>";
}
public static MonitorPlugin getMonitorPlugin(XWikiContext context)
{
try {
if ((context == null) || (context.getWiki() == null)) {
return null;
}
return (MonitorPlugin) context.getWiki().getPlugin("monitor", context);
} catch (Exception e) {
return null;
}
}
/**
* API to obtain a DOM document for the specified string
*
* @param str The parsed text
* @return A DOM document element corresponding to the string, or null on error
*/
public org.w3c.dom.Document getDOMForString(String str)
{
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new InputSource(new StringReader(str)));
} catch (SAXException ex) {
LOGGER.warn("Cannot parse string:" + str, ex);
} catch (IOException ex) {
LOGGER.warn("Cannot parse string:" + str, ex);
} catch (ParserConfigurationException ex) {
LOGGER.warn("Cannot parse string:" + str, ex);
}
return null;
}
/**
* API to get a new DOM document
*
* @return a new DOM document element, or null on error
*/
public org.w3c.dom.Document getDOMDocument()
{
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
} catch (ParserConfigurationException ex) {
LOGGER.warn("Cannot create DOM tree", ex);
}
return null;
}
/**
* API to protect Text from Radeox transformation
*
* @param text
* @return escaped text
* @deprecated dedicated to Radeox which is deprecated since a long time
*/
@Deprecated
public static String escapeText(String text)
{
text = text.replaceAll("http://", "http://");
text = text.replaceAll("ftp://", "ftp://");
text = text.replaceAll("\\-", "-");
text = text.replaceAll("\\*", "*");
text = text.replaceAll("\\~", "~");
text = text.replaceAll("\\[", "[");
text = text.replaceAll("\\]", "]");
text = text.replaceAll("\\{", "{");
text = text.replaceAll("\\}", "}");
text = text.replaceAll("\\1", "1");
return text;
}
/**
* API to protect URLs from Radeox transformation
*
* @param url
* @return encoded URL
* @deprecated dedicated to Radeox which is deprecated since a long time
*/
@Deprecated
public static String escapeURL(String url)
{
url = url.replaceAll("\\~", "%7E");
url = url.replaceAll("\\[", "%5B");
url = url.replaceAll("\\]", "%5D");
url = url.replaceAll("\\{", "%7B");
url = url.replaceAll("\\}", "%7D");
// We should not encode the following char for non local urls
// since this might not be handle correctly by FF
if (url.indexOf("//") == -1) {
url = url.replaceAll("-", "%2D");
url = url.replaceAll("\\*", "%2A");
}
return url;
}
/**
* Translates a string into <code>application/x-www-form-urlencoded</code> format, so that it can be safely used in
* URIs, as a parameter value in a query string or as a segment in the URI path. This uses the UTF-8 encoding, the
* default encoding for URIs, as stated in <a href="http://tools.ietf.org/html/rfc3986#section-2.5">RFC 3986</a>.
*
* @param text the non encoded text
* @param context the current context
* @return encoded text
* @see #decodeURI(String, XWikiContext)
*/
public static String encodeURI(String text, XWikiContext context)
{
try {
return URLEncoder.encode(text, URL_ENCODING);
} catch (Exception e) {
// Should not happen (UTF-8 is always available), but if so, fail securely
return null;
}
}
/**
* Decodes a <code>application/x-www-form-urlencoded</code> string, the reverse of
* {@link #encodeURI(String, XWikiContext)}. This uses the UTF-8 encoding, the default encoding for URIs, as stated
* in <a href="http://tools.ietf.org/html/rfc3986#section-2.5">RFC 3986</a>.
*
* @param text the encoded text
* @param context the current context
* @return decoded text
* @see #encodeURI(String, XWikiContext)
*/
public static String decodeURI(String text, XWikiContext context)
{
try {
return URLDecoder.decode(text, URL_ENCODING);
} catch (Exception e) {
// Should not happen (UTF-8 is always available)
return text;
}
}
/**
* Removes all non alpha numerical characters from the passed text. First tries to convert accented chars to their
* alpha numeric representation.
*
* @param text the text to convert
* @return the alpha numeric equivalent
*/
public static String convertToAlphaNumeric(String text)
{
// Start by removing accents
String textNoAccents = Util.noaccents(text);
// Now remove all non alphanumeric chars
StringBuffer result = new StringBuffer(textNoAccents.length());
char[] testChars = textNoAccents.toCharArray();
for (char testChar : testChars) {
if (Character.isLetterOrDigit(testChar) && testChar < 128) {
result.append(testChar);
}
}
return result.toString();
}
public static Date getFileLastModificationDate(String path)
{
try {
File f = new File(path);
return (new Date(f.lastModified()));
} catch (Exception ex) {
return new Date();
}
}
/**
* Validate a XML element name. XML elements must follow these naming rules :
* <ul>
* <li>Names can contain letters, numbers, and the following characters [., -, _].</li>
* <li>Names must not start with a number or punctuation character.</li>
* <li>Names must not start (case-insensitive) with the letters xml.</li>
* <li>Names cannot contain spaces.</li>
* </ul>
*
* @param elementName the XML element name to validate
* @return true if the element name is valid, false if it is not
*/
public static boolean isValidXMLElementName(String elementName)
{
if (elementName == null || elementName.equals("") || elementName.matches("(?i)^(xml).*")
|| !elementName.matches("(^[a-zA-Z\\_]+[\\w\\.\\-]*$)")) {
return false;
}
return true;
}
/**
* Load resources from: 1. FileSystem 2. ServletContext 3. ClassPath in this order.
*
* @param resource resource path to load
* @return InputStream of resource or null if not found
*/
public static InputStream getResourceAsStream(String resource)
{
File file = new File(resource);
try {
if (file.exists()) {
return new FileInputStream(file);
}
} catch (Exception e) {
// Probably running under -security, which prevents calling File.exists()
LOGGER.debug("Failed load resource [" + resource + "] using a file path");
}
try {
Container container = Utils.getComponent(Container.class);
InputStream res = container.getApplicationContext().getResourceAsStream(resource);
if (res != null) {
return res;
}
} catch (Exception e) {
LOGGER.debug("Failed to load resource [" + resource + "] using the application context");
}
return Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
}
/**
* Normalize the given language code. Converts the given language code to lower case and checks its validity (i.e.
* whether it is an ISO 639 language code or the string "default").
*
* <pre>
* Util.normalizeLanguage(null) = null
* Util.normalizeLanguage("") = ""
* Util.normalizeLanguage(" ") = ""
* Util.normalizeLanguage("default") = "default"
* Util.normalizeLanguage("DeFault") = "default"
* Util.normalizeLanguage("invalid") = "default"
* Util.normalizeLanguage("en") = "en"
* Util.normalizeLanguage("DE_at") = "de_AT"
* </pre>
*
* @param languageCode the language code to normalize
* @return normalized language code or the string "default" if the code is invalid
*/
public static String normalizeLanguage(String languageCode)
{
if (languageCode == null) {
return null;
}
if (StringUtils.isBlank(languageCode)) {
return "";
}
// handle language_COUNTRY case
final String separator = "_";
String[] parts = StringUtils.split(languageCode.toLowerCase(), "_-.");
String result = parts[0];
if (parts.length > 1) {
parts[1] = parts[1].toUpperCase();
// NOTE cannot use Locale#toString(), because it would change some language codes
result = parts[0] + separator + parts[1];
}
// handle the "default" case
final String defaultLanguage = "default";
if (defaultLanguage.equals(result)) {
return defaultLanguage;
}
try {
Locale l = new Locale(parts[0], parts.length > 1 ? parts[1] : "");
// Will throw an exception if the language code is not valid
l.getISO3Language();
return result;
} catch (MissingResourceException ex) {
LOGGER.warn("Invalid language: " + languageCode);
}
return defaultLanguage;
}
/**
* Get a likely unique 64bit hash representing the provided uid string. Use the MD5 hashing algorithm.
*
* @param uid an uid string usually provided by
* {@link org.xwiki.model.internal.reference.LocalUidStringEntityReferenceSerializer} or
* {@link org.xwiki.model.internal.reference.UidStringEntityReferenceSerializer}
* @return 64bit hash
* @since 4.0M1
*/
public static long getHash(String uid)
{
MessageDigest md5 = null;
long hash = 0;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(uid.getBytes("UTF-8"));
for (int l = digest.length, i = Math.max(0, digest.length - 9); i < l; i++) {
hash = hash << 8 | ((long) digest[i] & 0xFF);
}
} catch (NoSuchAlgorithmException ex) {
LOGGER.error("Cannot retrieve MD5 provider for hashing", ex);
throw new RuntimeException("MD5 hash is required for id hash");
} catch (Exception ex) {
LOGGER.error("Id computation failed during MD5 processing", ex);
throw new RuntimeException("MD5 hash is required for id hash");
}
return hash;
}
}