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
64
65 public class PathMatcher extends AbstractMatcher {
66
67 private static final WildMatcher WILD = WildMatcher.INSTANCE;
68
69 private final List<IMatcher> matchers;
70
71 private final char slash;
72
73 private boolean beginning;
74
75 PathMatcher(String pattern, Character pathSeparator, boolean dirOnly)
76 throws InvalidPatternException {
77 super(pattern, dirOnly);
78 slash = getPathSeparator(pathSeparator);
79 beginning = pattern.indexOf(slash) == 0;
80 if (isSimplePathWithSegments(pattern))
81 matchers = null;
82 else
83 matchers = createMatchers(split(pattern, slash), pathSeparator,
84 dirOnly);
85 }
86
87 private boolean isSimplePathWithSegments(String path) {
88 return !isWildCard(path) && path.indexOf('\\') < 0
89 && count(path, slash, true) > 0;
90 }
91
92 static private List<IMatcher> createMatchers(List<String> segments,
93 Character pathSeparator, boolean dirOnly)
94 throws InvalidPatternException {
95 List<IMatcher> matchers = new ArrayList<IMatcher>(segments.size());
96 for (int i = 0; i < segments.size(); i++) {
97 String segment = segments.get(i);
98 IMatcher matcher = createNameMatcher0(segment, pathSeparator,
99 dirOnly);
100 if (matcher == WILD && i > 0
101 && matchers.get(matchers.size() - 1) == WILD)
102
103 continue;
104 matchers.add(matcher);
105 }
106 return matchers;
107 }
108
109
110
111
112
113
114
115
116
117
118
119 public static IMatcher createPathMatcher(String pattern,
120 Character pathSeparator, boolean dirOnly)
121 throws InvalidPatternException {
122 pattern = trim(pattern);
123 char slash = Strings.getPathSeparator(pathSeparator);
124
125 int slashIdx = pattern.indexOf(slash, 1);
126 if (slashIdx > 0 && slashIdx < pattern.length() - 1)
127 return new PathMatcher(pattern, pathSeparator, dirOnly);
128 return createNameMatcher0(pattern, pathSeparator, dirOnly);
129 }
130
131
132
133
134
135
136
137
138
139 private static String trim(String pattern) {
140 while (pattern.length() > 0
141 && pattern.charAt(pattern.length() - 1) == ' ') {
142 if (pattern.length() > 1
143 && pattern.charAt(pattern.length() - 2) == '\\') {
144
145
146 pattern = pattern.substring(0, pattern.length() - 2) + " ";
147 return pattern;
148 }
149 pattern = pattern.substring(0, pattern.length() - 1);
150 }
151 return pattern;
152 }
153
154 private static IMatcher createNameMatcher0(String segment,
155 Character pathSeparator, boolean dirOnly)
156 throws InvalidPatternException {
157
158 if (WildMatcher.WILDMATCH.equals(segment)
159 || WildMatcher.WILDMATCH2.equals(segment))
160 return WILD;
161
162 PatternState state = checkWildCards(segment);
163 switch (state) {
164 case LEADING_ASTERISK_ONLY:
165 return new LeadingAsteriskMatcher(segment, pathSeparator, dirOnly);
166 case TRAILING_ASTERISK_ONLY:
167 return new TrailingAsteriskMatcher(segment, pathSeparator, dirOnly);
168 case COMPLEX:
169 return new WildCardMatcher(segment, pathSeparator, dirOnly);
170 default:
171 return new NameMatcher(segment, pathSeparator, dirOnly, true);
172 }
173 }
174
175 public boolean matches(String path, boolean assumeDirectory) {
176 if (matchers == null)
177 return simpleMatch(path, assumeDirectory);
178 return iterate(path, 0, path.length(), assumeDirectory);
179 }
180
181
182
183
184
185
186 private boolean simpleMatch(String path, boolean assumeDirectory) {
187 boolean hasSlash = path.indexOf(slash) == 0;
188 if (beginning && !hasSlash)
189 path = slash + path;
190
191 if (!beginning && hasSlash)
192 path = path.substring(1);
193
194 if (path.equals(pattern))
195
196 if (dirOnly && !assumeDirectory)
197
198 return false;
199 else
200
201 return true;
202
203
204
205
206
207
208 if (path.startsWith(pattern + FastIgnoreRule.PATH_SEPARATOR))
209 return true;
210
211 return false;
212 }
213
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 }