1 /* 2 * Copyright (c) 2008, 2009, 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 sun.nio.fs; 27 28 import java.util.regex.PatternSyntaxException; 29 30 public class Globs { Globs()31 private Globs() { } 32 33 private static final String regexMetaChars = ".^$+{[]|()"; 34 private static final String globMetaChars = "\\*?[{"; 35 isRegexMeta(char c)36 private static boolean isRegexMeta(char c) { 37 return regexMetaChars.indexOf(c) != -1; 38 } 39 isGlobMeta(char c)40 private static boolean isGlobMeta(char c) { 41 return globMetaChars.indexOf(c) != -1; 42 } 43 private static char EOL = 0; //TBD 44 next(String glob, int i)45 private static char next(String glob, int i) { 46 if (i < glob.length()) { 47 return glob.charAt(i); 48 } 49 return EOL; 50 } 51 52 /** 53 * Creates a regex pattern from the given glob expression. 54 * 55 * @throws PatternSyntaxException 56 */ toRegexPattern(String globPattern, boolean isDos)57 private static String toRegexPattern(String globPattern, boolean isDos) { 58 boolean inGroup = false; 59 StringBuilder regex = new StringBuilder("^"); 60 61 int i = 0; 62 while (i < globPattern.length()) { 63 char c = globPattern.charAt(i++); 64 switch (c) { 65 case '\\': 66 // escape special characters 67 if (i == globPattern.length()) { 68 throw new PatternSyntaxException("No character to escape", 69 globPattern, i - 1); 70 } 71 char next = globPattern.charAt(i++); 72 if (isGlobMeta(next) || isRegexMeta(next)) { 73 regex.append('\\'); 74 } 75 regex.append(next); 76 break; 77 case '/': 78 if (isDos) { 79 regex.append("\\\\"); 80 } else { 81 regex.append(c); 82 } 83 break; 84 case '[': 85 // don't match name separator in class 86 if (isDos) { 87 regex.append("[[^\\\\]&&["); 88 } else { 89 regex.append("[[^/]&&["); 90 } 91 if (next(globPattern, i) == '^') { 92 // escape the regex negation char if it appears 93 regex.append("\\^"); 94 i++; 95 } else { 96 // negation 97 if (next(globPattern, i) == '!') { 98 regex.append('^'); 99 i++; 100 } 101 // hyphen allowed at start 102 if (next(globPattern, i) == '-') { 103 regex.append('-'); 104 i++; 105 } 106 } 107 boolean hasRangeStart = false; 108 char last = 0; 109 while (i < globPattern.length()) { 110 c = globPattern.charAt(i++); 111 if (c == ']') { 112 break; 113 } 114 if (c == '/' || (isDos && c == '\\')) { 115 throw new PatternSyntaxException("Explicit 'name separator' in class", 116 globPattern, i - 1); 117 } 118 // TBD: how to specify ']' in a class? 119 if (c == '\\' || c == '[' || 120 c == '&' && next(globPattern, i) == '&') { 121 // escape '\', '[' or "&&" for regex class 122 regex.append('\\'); 123 } 124 regex.append(c); 125 126 if (c == '-') { 127 if (!hasRangeStart) { 128 throw new PatternSyntaxException("Invalid range", 129 globPattern, i - 1); 130 } 131 if ((c = next(globPattern, i++)) == EOL || c == ']') { 132 break; 133 } 134 if (c < last) { 135 throw new PatternSyntaxException("Invalid range", 136 globPattern, i - 3); 137 } 138 regex.append(c); 139 hasRangeStart = false; 140 } else { 141 hasRangeStart = true; 142 last = c; 143 } 144 } 145 if (c != ']') { 146 throw new PatternSyntaxException("Missing ']", globPattern, i - 1); 147 } 148 regex.append("]]"); 149 break; 150 case '{': 151 if (inGroup) { 152 throw new PatternSyntaxException("Cannot nest groups", 153 globPattern, i - 1); 154 } 155 regex.append("(?:(?:"); 156 inGroup = true; 157 break; 158 case '}': 159 if (inGroup) { 160 regex.append("))"); 161 inGroup = false; 162 } else { 163 regex.append('}'); 164 } 165 break; 166 case ',': 167 if (inGroup) { 168 regex.append(")|(?:"); 169 } else { 170 regex.append(','); 171 } 172 break; 173 case '*': 174 if (next(globPattern, i) == '*') { 175 // crosses directory boundaries 176 regex.append(".*"); 177 i++; 178 } else { 179 // within directory boundary 180 if (isDos) { 181 regex.append("[^\\\\]*"); 182 } else { 183 regex.append("[^/]*"); 184 } 185 } 186 break; 187 case '?': 188 if (isDos) { 189 regex.append("[^\\\\]"); 190 } else { 191 regex.append("[^/]"); 192 } 193 break; 194 195 default: 196 if (isRegexMeta(c)) { 197 regex.append('\\'); 198 } 199 regex.append(c); 200 } 201 } 202 203 if (inGroup) { 204 throw new PatternSyntaxException("Missing '}", globPattern, i - 1); 205 } 206 207 return regex.append('$').toString(); 208 } 209 toUnixRegexPattern(String globPattern)210 static String toUnixRegexPattern(String globPattern) { 211 return toRegexPattern(globPattern, false); 212 } 213 toWindowsRegexPattern(String globPattern)214 static String toWindowsRegexPattern(String globPattern) { 215 return toRegexPattern(globPattern, true); 216 } 217 } 218