1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.jrtfs; 27 28 import java.util.regex.PatternSyntaxException; 29 30 final class JrtUtils { 31 private JrtUtils() {} 32 33 private static final String regexMetaChars = ".^$+{[]|()"; 34 private static final String globMetaChars = "\\*?[{"; 35 private static boolean isRegexMeta(char c) { 36 return regexMetaChars.indexOf(c) != -1; 37 } 38 private static boolean isGlobMeta(char c) { 39 return globMetaChars.indexOf(c) != -1; 40 } 41 private static final char EOL = 0; //TBD 42 private static char next(String glob, int i) { 43 if (i < glob.length()) { 44 return glob.charAt(i); 45 } 46 return EOL; 47 } 48 49 /* 50 * Creates a regex pattern from the given glob expression. 51 * 52 * @throws PatternSyntaxException 53 */ 54 public static String toRegexPattern(String globPattern) { 55 boolean inGroup = false; 56 StringBuilder regex = new StringBuilder("^"); 57 58 int i = 0; 59 while (i < globPattern.length()) { 60 char c = globPattern.charAt(i++); 61 switch (c) { 62 case '\\': 63 // escape special characters 64 if (i == globPattern.length()) { 65 throw new PatternSyntaxException("No character to escape", 66 globPattern, i - 1); 67 } 68 char next = globPattern.charAt(i++); 69 if (isGlobMeta(next) || isRegexMeta(next)) { 70 regex.append('\\'); 71 } 72 regex.append(next); 73 break; 74 case '/': 75 regex.append(c); 76 break; 77 case '[': 78 // don't match name separator in class 79 regex.append("[[^/]&&["); 80 if (next(globPattern, i) == '^') { 81 // escape the regex negation char if it appears 82 regex.append("\\^"); 83 i++; 84 } else { 85 // negation 86 if (next(globPattern, i) == '!') { 87 regex.append('^'); 88 i++; 89 } 90 // hyphen allowed at start 91 if (next(globPattern, i) == '-') { 92 regex.append('-'); 93 i++; 94 } 95 } 96 boolean hasRangeStart = false; 97 char last = 0; 98 while (i < globPattern.length()) { 99 c = globPattern.charAt(i++); 100 if (c == ']') { 101 break; 102 } 103 if (c == '/') { 104 throw new PatternSyntaxException("Explicit 'name separator' in class", 105 globPattern, i - 1); 106 } 107 // TBD: how to specify ']' in a class? 108 if (c == '\\' || c == '[' || 109 c == '&' && next(globPattern, i) == '&') { 110 // escape '\', '[' or "&&" for regex class 111 regex.append('\\'); 112 } 113 regex.append(c); 114 115 if (c == '-') { 116 if (!hasRangeStart) { 117 throw new PatternSyntaxException("Invalid range", 118 globPattern, i - 1); 119 } 120 if ((c = next(globPattern, i++)) == EOL || c == ']') { 121 break; 122 } 123 if (c < last) { 124 throw new PatternSyntaxException("Invalid range", 125 globPattern, i - 3); 126 } 127 regex.append(c); 128 hasRangeStart = false; 129 } else { 130 hasRangeStart = true; 131 last = c; 132 } 133 } 134 if (c != ']') { 135 throw new PatternSyntaxException("Missing ']", globPattern, i - 1); 136 } 137 regex.append("]]"); 138 break; 139 case '{': 140 if (inGroup) { 141 throw new PatternSyntaxException("Cannot nest groups", 142 globPattern, i - 1); 143 } 144 regex.append("(?:(?:"); 145 inGroup = true; 146 break; 147 case '}': 148 if (inGroup) { 149 regex.append("))"); 150 inGroup = false; 151 } else { 152 regex.append('}'); 153 } 154 break; 155 case ',': 156 if (inGroup) { 157 regex.append(")|(?:"); 158 } else { 159 regex.append(','); 160 } 161 break; 162 case '*': 163 if (next(globPattern, i) == '*') { 164 // crosses directory boundaries 165 regex.append(".*"); 166 i++; 167 } else { 168 // within directory boundary 169 regex.append("[^/]*"); 170 } 171 break; 172 case '?': 173 regex.append("[^/]"); 174 break; 175 default: 176 if (isRegexMeta(c)) { 177 regex.append('\\'); 178 } 179 regex.append(c); 180 } 181 } 182 if (inGroup) { 183 throw new PatternSyntaxException("Missing '}", globPattern, i - 1); 184 } 185 return regex.append('$').toString(); 186 } 187 }