com.ckfinder.connector.utils.FileUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.ckfinder.connector.utils.FileUtils.java

Source

/*
 * CKFinder
 * ========
 * http://ckfinder.com
 * Copyright (C) 2007-2013, CKSource - Frederico Knabben. All rights reserved.
 *
 * The software, this file and its contents are subject to the CKFinder
 * License. Please read the license.txt file before using, installing, copying,
 * modifying or distribute this file or part of its contents. The contents of
 * this file is part of the Source Code of CKFinder.
 */

package com.ckfinder.connector.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.fileupload.FileItem;

import com.ckfinder.connector.ServletContextFactory;
import com.ckfinder.connector.configuration.Constants;
import com.ckfinder.connector.configuration.IConfiguration;
import com.ckfinder.connector.data.ResourceType;
import java.io.FileFilter;
import java.net.URLEncoder;
import java.util.Collections;

/**
 * Utils for files.
 *
 */
public class FileUtils {

    /**
     * max read file buffer size.
     */
    private static final int MAX_BUFFER_SIZE = 1024;

    private static final Map<String, String> UTF8_LOWER_ACCENTS = new HashMap<String, String>();
    private static final Map<String, String> UTF8_UPPER_ACCENTS = new HashMap<String, String>();

    private static final Map<String, String> encodingMap;
    static {
        Map<String, String> mapHelper = new HashMap<String, String>();
        mapHelper.put("%21", "!");
        mapHelper.put("%27", "'");
        mapHelper.put("%28", "(");
        mapHelper.put("%29", ")");
        mapHelper.put("%7E", "~");
        mapHelper.put("[+]", "%20");
        encodingMap = Collections.unmodifiableMap(mapHelper);
    }

    /**
     * Gets list of childeren folder or files for dir, according to searchDirs param.
     * @param dir folder to search.
     * @param searchDirs if true method return list of folders, otherwise list of files.
     * @return list of files or subdirectores in selected directory
     */
    public static List<String> findChildrensList(final File dir, final boolean searchDirs) {
        List<String> files = new ArrayList<String>();
        for (String subFiles : dir.list()) {
            File file = new File(dir + "/" + subFiles);
            if ((searchDirs && file.isDirectory()) || (!searchDirs && !file.isDirectory())) {
                files.add(file.getName());
            }
        }
        return files;
    }

    /**
     * Gets file extension.
     * @param fileName name of file.
     * @return file extension
     */
    public static String getFileExtension(final String fileName, final boolean shortExtensionMode) {
        if (shortExtensionMode)
            return FileUtils.getFileExtension(fileName);
        if (fileName == null || fileName.indexOf(".") == -1 || fileName.indexOf(".") == fileName.length() - 1) {
            return null;
        }
        return fileName.substring(fileName.indexOf(".") + 1);
    }

    /**
     * Gets file last extension.
     * @param fileName name of file.
     * @return file extension
     */
    public static String getFileExtension(final String fileName) {
        if (fileName == null || fileName.lastIndexOf(".") == -1
                || fileName.lastIndexOf(".") == fileName.length() - 1) {
            return null;
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * Gets file name without it's extension.
     * @param fileName name of file
     * @return file extension
     */
    public static String getFileNameWithoutExtension(final String fileName, final boolean shortExtensionMode) {
        if (shortExtensionMode)
            return FileUtils.getFileNameWithoutExtension(fileName);

        if (fileName == null || fileName.indexOf(".") == -1) {
            return null;
        }
        return fileName.substring(0, fileName.indexOf("."));
    }

    /**
     * Gets file name without it's last extension.
     * @param fileName name of file
     * @return file extension
     */
    public static String getFileNameWithoutExtension(final String fileName) {
        if (fileName == null || fileName.lastIndexOf(".") == -1) {
            return null;
        }
        return fileName.substring(0, fileName.lastIndexOf("."));
    }

    /**
     * Print file content to outputstream.
     * @param file file to be printed.
     * @param out outputstream.
     * @throws IOException when io error occurs.
     */
    public static void printFileContentToResponse(final File file, final OutputStream out) throws IOException {
        FileInputStream in = null;
        if (file.length() == 0) {
            return;
        }
        try {
            in = new FileInputStream(file);
            byte[] buf = null;
            if (file.length() < MAX_BUFFER_SIZE) {
                buf = new byte[(int) file.length()];
            } else {
                buf = new byte[MAX_BUFFER_SIZE];
            }

            int numRead = 0;
            while ((numRead = in.read(buf)) != -1) {
                out.write(buf, 0, numRead);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                throw e;
            }
        }
    }

    /**
     *
     * @param sourceFile source file
     * @param destFile destenation file
     * @param move if source file should be deleted.
     * @param conf connector configuration
     * @return true if file moved/copied correctly
     * @throws IOException when IOerror occurs
     */
    public static boolean copyFromSourceToDestFile(final File sourceFile, final File destFile, final boolean move,
            final IConfiguration conf) throws IOException {
        createPath(destFile, conf, true);
        InputStream in = new FileInputStream(sourceFile);
        OutputStream out = new FileOutputStream(destFile);
        byte[] buf = new byte[MAX_BUFFER_SIZE];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
        if (move) {
            sourceFile.delete();
        }
        return true;

    }

    /**
     * gets full path of file.
     * @param file path to a file in ckfinder
     * @return full path
     * @throws Exception when servlet context is null
     */
    public static String getFullPath(final String file) throws Exception {
        if (checkFileParentExists(PathUtils.escape(file))) {
            return file;
        } else {
            return ServletContextFactory.getServletContext().getRealPath(file);
        }
    }

    /**
     * check if parent of file in param exists and is directory.
     * @param file file to check
     * @return true if is directory and exists.
     */
    private static boolean checkFileParentExists(final String file) {
        String fileName = PathUtils.removeSlashFromEnd(file);
        File dir = new File(fileName.substring(0, fileName.lastIndexOf("/")));
        return dir.exists() && dir.isDirectory();
    }

    /**
     * Parse date with pattern yyyyMMddHHmm. Pattern is used in get file command
     * response XML.
     * @param file input file.
     * @return parsed file modification date.
     */
    public static String parseLastModifDate(final File file) {
        Date date = new Date(file.lastModified());
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm");
        return dateFormat.format(date);
    }

    /**
     * check if dirname matches configuration hidden folder regex.
     * @param dirName dir name
     * @param conf connector configuration
     * @return true if matches.
     */
    public static boolean checkIfDirIsHidden(final String dirName, final IConfiguration conf) {
        if (dirName == null || dirName.equals("")) {
            return false;
        }
        String dir = PathUtils.removeSlashFromEnd(PathUtils.escape(dirName));
        Scanner sc = new Scanner(dir).useDelimiter("/");
        while (sc.hasNext()) {
            boolean check = Pattern.compile(getHiddenFileOrFolderRegex(conf.getHiddenFolders())).matcher(sc.next())
                    .matches();
            if (check) {
                return true;
            }
        }
        return false;
    }

    /**
     * check if filename matches configuration hidden file regex.
     * @param fileName file name
     * @param conf connector configuration
     * @return true if matches.
     */
    public static boolean checkIfFileIsHidden(final String fileName, final IConfiguration conf) {
        return Pattern.compile(getHiddenFileOrFolderRegex(conf.getHiddenFiles())).matcher(fileName).matches();
    }

    /**
     * get hidden folder regex pattern.
     * @param hiddenList list of hidden file or files patterns.
     * @return full folder regerx pattern
     */
    private static String getHiddenFileOrFolderRegex(final List<String> hiddenList) {
        StringBuilder sb = new StringBuilder("(");
        for (String item : hiddenList) {
            if (sb.length() > 3) {
                sb.append("|");
            }

            item = item.replaceAll("\\.", "\\\\.");
            item = item.replaceAll("\\*", ".+");
            item = item.replaceAll("\\?", ".");

            sb.append("(");
            sb.append(item);
            sb.append(")");

        }
        sb.append(")+");
        return sb.toString();
    }

    /**
     * deletes file or folder with all subfolders and subfiles.
     * @param file file or directory to delete.
     * @return true if all files are deleted.
     */
    public static boolean delete(final File file) {

        if (file.isDirectory()) {
            for (String item : file.list()) {
                File subFile = new File(file.getAbsolutePath() + File.separator + item);
                if (!delete(subFile)) {
                    return false;
                }
            }
        }
        return file.delete();
    }

    /**
     * check if file or folder name doesn't match invalid name.
     * @param fileName file name
     * @return true if file name is correct
     */
    public static boolean checkFileName(final String fileName) {
        return !(fileName == null || fileName.equals("") || fileName.charAt(fileName.length() - 1) == '.'
                || fileName.contains("..") || checkFolderNamePattern(fileName));
    }

    /**
     * check if new folder name contains disallowed chars.
     * @param fileName file name
     * @return true if it does contain disallowed characters.
     */
    private static boolean checkFolderNamePattern(final String fileName) {
        Pattern pattern = Pattern.compile(Constants.INVALID_FILE_NAME_REGEX);
        Matcher matcher = pattern.matcher(fileName);
        return matcher.find();
    }

    /**
     * checks if file extension is on denied list or isn't on allowed list.
     * @param fileName filename
     * @param type resource type
     * @return 0 if ok, 1 if not ok, 2 if rename required
     */
    public static int checkFileExtension(final String fileName, final ResourceType type) {
        if (type == null || fileName == null) {
            return 1;
        }

        if (fileName.indexOf('.') == -1) {
            return 0;
        }

        return checkSingleExtension(getFileExtension(fileName), type) ? 0 : 1;
    }

    /**
     * checks is file extension is on denied list or isn't on allowed list.
     * @param fileExt file extension
     * @param type file resource type
     * @return 0 if isn't on denied and is on allowed, otherwise 1
     */
    private static boolean checkSingleExtension(final String fileExt, final ResourceType type) {
        Scanner scanner = new Scanner(type.getDeniedExtensions()).useDelimiter(",");
        while (scanner.hasNext()) {
            if (scanner.next().equalsIgnoreCase(fileExt)) {
                return false;
            }
        }
        Scanner scanner1 = new Scanner(type.getAllowedExtensions()).useDelimiter(",");
        while (scanner1.hasNext()) {
            if (scanner1.next().equalsIgnoreCase(fileExt)) {
                return true;
            }
        }
        return false;
    }

    /**
     * converts filename to connector encoding.
     * @param fileName file name
     * @param configuration connector configuration
     * @return encoded file name
     */
    public static String convertFromUriEncoding(final String fileName, final IConfiguration configuration) {
        try {
            return new String(fileName.getBytes(configuration.getUriEncoding()), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return fileName;
        }
    }

    /**
     * converts filename to ASCII.
     * @param fileName file name
     * @return encoded file name
     */
    public static String convertToASCII(final String fileName) {
        String newFileName = fileName;
        fillLowerAccents();
        fillUpperAccents();
        for (String s : UTF8_LOWER_ACCENTS.keySet()) {
            newFileName = newFileName.replace(s, UTF8_LOWER_ACCENTS.get(s));
        }

        for (String s : UTF8_UPPER_ACCENTS.keySet()) {
            newFileName = newFileName.replace(s, UTF8_UPPER_ACCENTS.get(s));
        }
        return newFileName;
    }

    /**
     * creates file and all above folders that doesn"t exists.
     * @param file file to create.
     * @param conf connector configuration
     * @param isFile if it is path to folder.
     * @throws IOException when io error occurs.
     */
    public static void createPath(final File file, final IConfiguration conf, final boolean isFile)
            throws IOException {
        String path = file.getAbsolutePath();
        // on Linux first path char - "/" is removed by StringTokenizer
        StringTokenizer st = new StringTokenizer(path, File.separator);

        // if path include "/" as a first char of path we have to add it manually
        String checkPath = (path.indexOf(File.separator) == 0) ? File.separator : "";
        checkPath += (String) st.nextElement();
        while (st.hasMoreElements()) {
            String string = (String) st.nextElement();
            checkPath = checkPath.concat(File.separator + string);
            if (!(string.equals(file.getName()) && isFile)) {
                File dir = new File(checkPath);
                if (!dir.exists()) {
                    mkdir(dir, conf);
                }
            } else {
                file.createNewFile();
            }
        }
    }

    /**
     * Creates dir.
     * @param dir dir to create.
     * @param configuration connector configuration
     * @return create dir result.
     */
    public static boolean mkdir(final File dir, final IConfiguration configuration) {
        return dir.mkdir();
    }

    /**
     * check if file size isn't bigger then max size for type.
     * @param type resource type
     * @param fileSize file size
     * @return true if file size isn't bigger then max size for type.
     */
    public static boolean checkFileSize(final ResourceType type, final long fileSize) {
        return (type.getMaxSize() == null || type.getMaxSize() > fileSize);
    }

    /**
     * check if file has html file extension.
     * @param file file name
     * @param configuration connector configuration
     * @return true if has
     */
    public static boolean checkIfFileIsHtmlFile(final String file, final IConfiguration configuration) {

        return configuration.getHTMLExtensions().contains(getFileExtension(file).toLowerCase());

    }

    /**
     * Detect HTML in the first KB to prevent against potential security issue with
     * IE/Safari/Opera file type auto detection bug.
     * Returns true if file contain insecure HTML code at the beginning.
     * @param item file upload item
     * @return true if dedected.
     * @throws IOException when io error occurs.
     */
    public static boolean detectHtml(final FileItem item) throws IOException {
        byte[] buff = new byte[MAX_BUFFER_SIZE];
        InputStream is = null;
        try {
            is = item.getInputStream();
            is.read(buff, 0, MAX_BUFFER_SIZE);
            String content = new String(buff);
            content = content.toLowerCase().trim();

            if (Pattern
                    .compile("<!DOCTYPE\\W+X?HTML.+", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE)
                    .matcher(content).matches()) {
                return true;
            }

            String[] tags = { "<body", "<head", "<html", "<img", "<pre", "<script", "<table", "<title" };

            for (String tag : tags) {
                if (content.indexOf(tag) != -1) {
                    return true;
                }
            }

            if (Pattern
                    .compile("type\\s*=\\s*[\'\"]?\\s*(?:\\w*/)?(?:ecma|java)",
                            Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE)
                    .matcher(content).find()) {
                return true;
            }

            if (Pattern
                    .compile("(?:href|src|data)\\s*=\\s*[\'\"]?\\s*(?:ecma|java)script:",
                            Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE)
                    .matcher(content).find()) {
                return true;
            }

            if (Pattern
                    .compile("url\\s*\\(\\s*[\'\"]?\\s*(?:ecma|java)script:",
                            Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE)
                    .matcher(content).find()) {
                return true;
            }
        } catch (IOException e) {
            throw e;
        } finally {
            if (is != null) {
                is.close();
            }
        }
        return false;
    }

    /**
    * Checks if folder has any subfolders but respects ACL and hideFolders
    * setting from configuration.
    * @param dirPath path to current folder.
     * @param dir current folder being checked. Represented by File object.
     * @param configuration configuration object.
     * @param resourceType name of resource type, folder is assignd to.
     * @param currentUserRole user role.
    * @return true if there are any allowed and non-hidden subfolders.
    */
    public static Boolean hasChildren(String dirPath, File dir, IConfiguration configuration, String resourceType,
            String currentUserRole) {
        FileFilter fileFilter = new FileFilter() {
            public boolean accept(File file) {
                return file.isDirectory();
            }
        };
        File[] subDirsList = dir.listFiles(fileFilter);

        if (subDirsList != null) {
            for (int i = 0; i < subDirsList.length; i++) {
                String subDirName = subDirsList[i].getName();

                if (!FileUtils.checkIfDirIsHidden(subDirName, configuration) && AccessControlUtil
                        .getInstance(configuration).checkFolderACL(resourceType, dirPath + subDirName,
                                currentUserRole, AccessControlUtil.CKFINDER_CONNECTOR_ACL_FOLDER_VIEW))
                    return true;
            }
        }
        return false;
    }

    /**
     * rename file with double extension.
     * @param fileName file name
     * @return new file name with . replaced with _ (but not last)
     */
    public static String renameFileWithBadExt(final ResourceType type, final String fileName) {
        if (type == null || fileName == null) {
            return null;
        }

        if (fileName.indexOf('.') == -1) {
            return fileName;
        }

        StringTokenizer tokens = new StringTokenizer(fileName, ".");
        String cfileName = tokens.nextToken();
        String currToken = "";
        while (tokens.hasMoreTokens()) {
            currToken = tokens.nextToken();
            if (tokens.hasMoreElements()) {
                cfileName = cfileName.concat(checkSingleExtension(currToken, type) ? "." : "_");
                cfileName = cfileName.concat(currToken);
            } else {
                cfileName = cfileName.concat(".".concat(currToken));
            }
        }
        return cfileName;
    }

    public static String encodeURIComponent(final String fileName) throws UnsupportedEncodingException {
        String fileNameHelper = URLEncoder.encode(fileName, "utf-8");
        for (Map.Entry<String, String> entry : encodingMap.entrySet()) {
            fileNameHelper = fileNameHelper.replaceAll(entry.getKey(), entry.getValue());
        }
        return fileNameHelper;
    }

    public static boolean checkFolderName(final String folderName, final IConfiguration configuration) {
        if ((configuration.isDisallowUnsafeCharacters() && (folderName.contains(".") || folderName.contains(";")))
                || FileUtils.checkFolderNamePattern(folderName)) {
            return false;
        }
        return true;
    }

    public static boolean checkFileName(final String fileName, final IConfiguration configuration) {
        if ((configuration.isDisallowUnsafeCharacters() && fileName.contains(";"))
                || !FileUtils.checkFileName(fileName))
            return false;
        return true;
    }

    public static String backupWithBackSlash(final String fileName, final String toReplace) {
        return fileName.replaceAll(toReplace, "\\\\" + toReplace);
    }

    /**
     * fills data for upper accesnts map.
     */
    private static void fillUpperAccents() {
        if (UTF8_UPPER_ACCENTS.size() == 0) {
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "D");
            UTF8_UPPER_ACCENTS.put("", "F");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "R");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("", "N");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "K");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "Y");
            UTF8_UPPER_ACCENTS.put("", "N");
            UTF8_UPPER_ACCENTS.put("", "L");
            UTF8_UPPER_ACCENTS.put("", "H");
            UTF8_UPPER_ACCENTS.put("", "P");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "C");
            UTF8_UPPER_ACCENTS.put("", "W");
            UTF8_UPPER_ACCENTS.put("", "C");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "G");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "C");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "I");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "C");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "W");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "C");
            UTF8_UPPER_ACCENTS.put("", "Oe");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "Y");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("?", "L");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "S");
            UTF8_UPPER_ACCENTS.put("", "G");
            UTF8_UPPER_ACCENTS.put("", "L");
            UTF8_UPPER_ACCENTS.put("", "F");
            UTF8_UPPER_ACCENTS.put("", "Z");
            UTF8_UPPER_ACCENTS.put("", "W");
            UTF8_UPPER_ACCENTS.put("", "B");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "I");
            UTF8_UPPER_ACCENTS.put("?", "I");
            UTF8_UPPER_ACCENTS.put("", "D");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("", "R");
            UTF8_UPPER_ACCENTS.put("", "Ae");
            UTF8_UPPER_ACCENTS.put("?", "I");
            UTF8_UPPER_ACCENTS.put("", "R");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "Ue");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "E");
            UTF8_UPPER_ACCENTS.put("", "N");
            UTF8_UPPER_ACCENTS.put("", "N");
            UTF8_UPPER_ACCENTS.put("", "H");
            UTF8_UPPER_ACCENTS.put("", "G");
            UTF8_UPPER_ACCENTS.put("?", "D");
            UTF8_UPPER_ACCENTS.put("", "J");
            UTF8_UPPER_ACCENTS.put("", "Y");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("?", "Y");
            UTF8_UPPER_ACCENTS.put("?", "O");
            UTF8_UPPER_ACCENTS.put("", "Y");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "T");
            UTF8_UPPER_ACCENTS.put("?", "Y");
            UTF8_UPPER_ACCENTS.put("?", "O");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "L");
            UTF8_UPPER_ACCENTS.put("", "W");
            UTF8_UPPER_ACCENTS.put("", "Z");
            UTF8_UPPER_ACCENTS.put("", "I");
            UTF8_UPPER_ACCENTS.put("", "A");
            UTF8_UPPER_ACCENTS.put("", "G");
            UTF8_UPPER_ACCENTS.put("", "M");
            UTF8_UPPER_ACCENTS.put("", "O");
            UTF8_UPPER_ACCENTS.put("", "I");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "I");
            UTF8_UPPER_ACCENTS.put("", "Z");
            UTF8_UPPER_ACCENTS.put("?", "A");
            UTF8_UPPER_ACCENTS.put("", "U");
            UTF8_UPPER_ACCENTS.put("", "Th");
            UTF8_UPPER_ACCENTS.put("?", "Dh");
            UTF8_UPPER_ACCENTS.put("", "Ae");
            UTF8_UPPER_ACCENTS.put("", "E");
        }
    }

    /**
     * fills data for lower accesnts map.
     */
    private static void fillLowerAccents() {
        if (UTF8_LOWER_ACCENTS.size() == 0) {
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("?", "d");
            UTF8_LOWER_ACCENTS.put("", "f");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "s");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "ss");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "r");
            UTF8_LOWER_ACCENTS.put("", "t");
            UTF8_LOWER_ACCENTS.put("", "n");
            UTF8_LOWER_ACCENTS.put("?", "a");
            UTF8_LOWER_ACCENTS.put("", "k");
            UTF8_LOWER_ACCENTS.put("?", "s");
            UTF8_LOWER_ACCENTS.put("", "y");
            UTF8_LOWER_ACCENTS.put("", "n");
            UTF8_LOWER_ACCENTS.put("", "l");
            UTF8_LOWER_ACCENTS.put("", "h");
            UTF8_LOWER_ACCENTS.put("", "p");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "c");
            UTF8_LOWER_ACCENTS.put("?", "w");
            UTF8_LOWER_ACCENTS.put("", "c");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "s");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "g");
            UTF8_LOWER_ACCENTS.put("", "t");
            UTF8_LOWER_ACCENTS.put("", "s");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "c");
            UTF8_LOWER_ACCENTS.put("", "s");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "c");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "w");
            UTF8_LOWER_ACCENTS.put("", "t");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("?", "c");
            UTF8_LOWER_ACCENTS.put("", "oe");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "y");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "l");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "s");
            UTF8_LOWER_ACCENTS.put("", "g");
            UTF8_LOWER_ACCENTS.put("", "l");
            UTF8_LOWER_ACCENTS.put("", "f");
            UTF8_LOWER_ACCENTS.put("", "z");
            UTF8_LOWER_ACCENTS.put("", "w");
            UTF8_LOWER_ACCENTS.put("", "b");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "d");
            UTF8_LOWER_ACCENTS.put("", "t");
            UTF8_LOWER_ACCENTS.put("", "r");
            UTF8_LOWER_ACCENTS.put("", "ae");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "r");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "ue");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "e");
            UTF8_LOWER_ACCENTS.put("", "n");
            UTF8_LOWER_ACCENTS.put("", "n");
            UTF8_LOWER_ACCENTS.put("", "h");
            UTF8_LOWER_ACCENTS.put("?", "g");
            UTF8_LOWER_ACCENTS.put("", "d");
            UTF8_LOWER_ACCENTS.put("", "j");
            UTF8_LOWER_ACCENTS.put("", "y");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "t");
            UTF8_LOWER_ACCENTS.put("", "y");
            UTF8_LOWER_ACCENTS.put("", "o");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "l");
            UTF8_LOWER_ACCENTS.put("", "w");
            UTF8_LOWER_ACCENTS.put("", "z");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "g");
            UTF8_LOWER_ACCENTS.put("?", "m");
            UTF8_LOWER_ACCENTS.put("?", "o");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "i");
            UTF8_LOWER_ACCENTS.put("", "z");
            UTF8_LOWER_ACCENTS.put("", "a");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "th");
            UTF8_LOWER_ACCENTS.put("", "dh");
            UTF8_LOWER_ACCENTS.put("", "ae");
            UTF8_LOWER_ACCENTS.put("", "u");
            UTF8_LOWER_ACCENTS.put("", "e");

        }
    }
}