001/*
002 * Copyright (C) 2014 XStream Committers.
003 * All rights reserved.
004 *
005 * Created on 09. January 2014 by Joerg Schaible
006 */
007package com.thoughtworks.xstream.security;
008
009/**
010 * Permission for any type with a name matching one of the provided wildcard expressions.
011 * 
012 * <p>
013 * Supported are patterns with path expressions using dot as separator:
014 * </p>
015 * <ul>
016 * <li>?: one non-control character except separator, e.g. for 'java.net.Inet?Address'</li>
017 * <li>*: arbitrary number of non-control characters except separator, e.g. for types in a package like 'java.lang.*'</li>
018 * <li>**: arbitrary number of non-control characters including separator, e.g. for types in a package and subpackages like 'java.lang.**'</li>
019 * </ul>
020 * <p>
021 * The complete range of UTF-8 characters is supported except control characters.
022 * </p>
023 * 
024 * @author J&ouml;rg Schaible
025 * @since 1.4.7
026 */
027public class WildcardTypePermission extends RegExpTypePermission {
028
029    /**
030     * @since 1.4.7
031     */
032    public WildcardTypePermission(final String[] patterns) {
033        super(getRegExpPatterns(patterns));
034    }
035
036    private static String[] getRegExpPatterns(final String[] wildcards) {
037        if (wildcards == null)
038            return null;
039        final String[] regexps = new String[wildcards.length];
040        for (int i = 0; i < wildcards.length; ++i) {
041            final String wildcardExpression = wildcards[i];
042            final StringBuffer result = new StringBuffer(wildcardExpression.length() * 2);
043            result.append("(?u)");
044            final int length = wildcardExpression.length();
045            for (int j = 0; j < length; j++) {
046                final char ch = wildcardExpression.charAt(j);
047                switch (ch) {
048                case '\\':
049                case '.':
050                case '+':
051                case '|':
052                case '[':
053                case ']':
054                case '(':
055                case ')':
056                case '^':
057                case '$':
058                    result.append('\\').append(ch);
059                    break;
060
061                case '?':
062                    result.append('.');
063                    break;
064
065                case '*':
066                    // see "General Category Property" in http://www.unicode.org/reports/tr18/
067                    if (j + 1 < length && wildcardExpression.charAt(j + 1) == '*') {
068                        result.append("[\\P{C}]*");
069                        j++;
070                    } else {
071                        result.append("[\\P{C}&&[^").append('.').append("]]*");
072                    }
073                    break;
074
075                default:
076                    result.append(ch);
077                    break;
078                }
079            }
080            regexps[i] = result.toString();
081        }
082        return regexps;
083    }
084}