1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.ignore.internal;
44
45 import static org.eclipse.jgit.ignore.internal.Strings.checkWildCards;
46 import static org.eclipse.jgit.ignore.internal.Strings.count;
47 import static org.eclipse.jgit.ignore.internal.Strings.getPathSeparator;
48 import static org.eclipse.jgit.ignore.internal.Strings.isWildCard;
49 import static org.eclipse.jgit.ignore.internal.Strings.split;
50
51 import java.util.ArrayList;
52 import java.util.List;
53
54 import org.eclipse.jgit.errors.InvalidPatternException;
55 import org.eclipse.jgit.ignore.FastIgnoreRule;
56 import org.eclipse.jgit.ignore.internal.Strings.PatternState;
57
58
59
60
61
62
63 public class PathMatcher extends AbstractMatcher {
64
65 private static final WildMatcher WILD = WildMatcher.INSTANCE;
66
67 private final List<IMatcher> matchers;
68
69 private final char slash;
70
71 private boolean beginning;
72
73 PathMatcher(String pattern, Character pathSeparator, boolean dirOnly)
74 throws InvalidPatternException {
75 super(pattern, dirOnly);
76 slash = getPathSeparator(pathSeparator);
77 beginning = pattern.indexOf(slash) == 0;
78 if (isSimplePathWithSegments(pattern))
79 matchers = null;
80 else
81 matchers = createMatchers(split(pattern, slash), pathSeparator,
82 dirOnly);
83 }
84
85 private boolean isSimplePathWithSegments(String path) {
86 return !isWildCard(path) && path.indexOf('\\') < 0
87 && count(path, slash, true) > 0;
88 }
89
90 static private List<IMatcher> createMatchers(List<String> segments,
91 Character pathSeparator, boolean dirOnly)
92 throws InvalidPatternException {
93 List<IMatcher> matchers = new ArrayList<>(segments.size());
94 for (int i = 0; i < segments.size(); i++) {
95 String segment = segments.get(i);
96 IMatcher matcher = createNameMatcher0(segment, pathSeparator,
97 dirOnly);
98 if (matcher == WILD && i > 0
99 && matchers.get(matchers.size() - 1) == WILD)
100
101 continue;
102 matchers.add(matcher);
103 }
104 return matchers;
105 }
106
107
108
109
110
111
112
113
114
115
116
117 public static IMatcher createPathMatcher(String pattern,
118 Character pathSeparator, boolean dirOnly)
119 throws InvalidPatternException {
120 pattern = trim(pattern);
121 char slash = Strings.getPathSeparator(pathSeparator);
122
123 int slashIdx = pattern.indexOf(slash, 1);
124 if (slashIdx > 0 && slashIdx < pattern.length() - 1)
125 return new PathMatcher(pattern, pathSeparator, dirOnly);
126 return createNameMatcher0(pattern, pathSeparator, dirOnly);
127 }
128
129
130
131
132
133
134
135
136
137 private static String trim(String pattern) {
138 while (pattern.length() > 0
139 && pattern.charAt(pattern.length() - 1) == ' ') {
140 if (pattern.length() > 1
141 && pattern.charAt(pattern.length() - 2) == '\\') {
142
143
144 pattern = pattern.substring(0, pattern.length() - 2) + " ";
145 return pattern;
146 }
147 pattern = pattern.substring(0, pattern.length() - 1);
148 }
149 return pattern;
150 }
151
152 private static IMatcher createNameMatcher0(String segment,
153 Character pathSeparator, boolean dirOnly)
154 throws InvalidPatternException {
155
156 if (WildMatcher.WILDMATCH.equals(segment)
157 || WildMatcher.WILDMATCH2.equals(segment))
158 return WILD;
159
160 PatternState state = checkWildCards(segment);
161 switch (state) {
162 case LEADING_ASTERISK_ONLY:
163 return new LeadingAsteriskMatcher(segment, pathSeparator, dirOnly);
164 case TRAILING_ASTERISK_ONLY:
165 return new TrailingAsteriskMatcher(segment, pathSeparator, dirOnly);
166 case COMPLEX:
167 return new WildCardMatcher(segment, pathSeparator, dirOnly);
168 default:
169 return new NameMatcher(segment, pathSeparator, dirOnly, true);
170 }
171 }
172
173 @Override
174 public boolean matches(String path, boolean assumeDirectory) {
175 if (matchers == null)
176 return simpleMatch(path, assumeDirectory);
177 return iterate(path, 0, path.length(), assumeDirectory);
178 }
179
180
181
182
183
184
185 private boolean simpleMatch(String path, boolean assumeDirectory) {
186 boolean hasSlash = path.indexOf(slash) == 0;
187 if (beginning && !hasSlash)
188 path = slash + path;
189
190 if (!beginning && hasSlash)
191 path = path.substring(1);
192
193 if (path.equals(pattern))
194
195 if (dirOnly && !assumeDirectory)
196
197 return false;
198 else
199
200 return true;
201
202
203
204
205
206
207 if (path.startsWith(pattern + FastIgnoreRule.PATH_SEPARATOR))
208 return true;
209
210 return false;
211 }
212
213 @Override
214 public boolean matches(String segment, int startIncl, int endExcl,
215 boolean assumeDirectory) {
216 throw new UnsupportedOperationException(
217 "Path matcher works only on entire paths");
218 }
219
220 boolean iterate(final String path, final int startIncl, final int endExcl,
221 boolean assumeDirectory) {
222 int matcher = 0;
223 int right = startIncl;
224 boolean match = false;
225 int lastWildmatch = -1;
226 while (true) {
227 int left = right;
228 right = path.indexOf(slash, right);
229 if (right == -1) {
230 if (left < endExcl)
231 match = matches(matcher, path, left, endExcl,
232 assumeDirectory);
233 if (match) {
234 if (matcher == matchers.size() - 2
235 && matchers.get(matcher + 1) == WILD)
236
237 return true;
238 if (matcher < matchers.size() - 1
239 && matchers.get(matcher) == WILD) {
240
241 matcher++;
242 match = matches(matcher, path, left, endExcl,
243 assumeDirectory);
244 } else if (dirOnly && !assumeDirectory)
245
246 return false;
247 }
248 return match && matcher + 1 == matchers.size();
249 }
250 if (right - left > 0)
251 match = matches(matcher, path, left, right, assumeDirectory);
252 else {
253
254 right++;
255 continue;
256 }
257 if (match) {
258 if (matchers.get(matcher) == WILD) {
259 lastWildmatch = matcher;
260
261 right = left - 1;
262 }
263 matcher++;
264 if (matcher == matchers.size())
265 return true;
266 } else if (lastWildmatch != -1)
267 matcher = lastWildmatch + 1;
268 else
269 return false;
270 right++;
271 }
272 }
273
274 boolean matches(int matcherIdx, String path, int startIncl, int endExcl,
275 boolean assumeDirectory) {
276 IMatcher matcher = matchers.get(matcherIdx);
277 return matcher.matches(path, startIncl, endExcl, assumeDirectory);
278 }
279 }