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) && count(path, slash, true) > 0;
89 }
90
91 static private List<IMatcher> createMatchers(List<String> segments,
92 Character pathSeparator, boolean dirOnly)
93 throws InvalidPatternException {
94 List<IMatcher> matchers = new ArrayList<IMatcher>(segments.size());
95 for (int i = 0; i < segments.size(); i++) {
96 String segment = segments.get(i);
97 IMatcher matcher = createNameMatcher0(segment, pathSeparator,
98 dirOnly);
99 if (matcher == WILD && i > 0
100 && matchers.get(matchers.size() - 1) == WILD)
101
102 continue;
103 matchers.add(matcher);
104 }
105 return matchers;
106 }
107
108
109
110
111
112
113
114
115
116
117
118 public static IMatcher createPathMatcher(String pattern,
119 Character pathSeparator, boolean dirOnly)
120 throws InvalidPatternException {
121 pattern = pattern.trim();
122 char slash = Strings.getPathSeparator(pathSeparator);
123
124 int slashIdx = pattern.indexOf(slash, 1);
125 if (slashIdx > 0 && slashIdx < pattern.length() - 1)
126 return new PathMatcher(pattern, pathSeparator, dirOnly);
127 return createNameMatcher0(pattern, pathSeparator, dirOnly);
128 }
129
130 private static IMatcher createNameMatcher0(String segment,
131 Character pathSeparator, boolean dirOnly)
132 throws InvalidPatternException {
133
134 if (WildMatcher.WILDMATCH.equals(segment)
135 || WildMatcher.WILDMATCH2.equals(segment))
136 return WILD;
137
138 PatternState state = checkWildCards(segment);
139 switch (state) {
140 case LEADING_ASTERISK_ONLY:
141 return new LeadingAsteriskMatcher(segment, pathSeparator, dirOnly);
142 case TRAILING_ASTERISK_ONLY:
143 return new TrailingAsteriskMatcher(segment, pathSeparator, dirOnly);
144 case COMPLEX:
145 return new WildCardMatcher(segment, pathSeparator, dirOnly);
146 default:
147 return new NameMatcher(segment, pathSeparator, dirOnly);
148 }
149 }
150
151 public boolean matches(String path, boolean assumeDirectory) {
152 if (matchers == null)
153 return simpleMatch(path, assumeDirectory);
154 return iterate(path, 0, path.length(), assumeDirectory);
155 }
156
157
158
159
160
161
162 private boolean simpleMatch(String path, boolean assumeDirectory) {
163 boolean hasSlash = path.indexOf(slash) == 0;
164 if (beginning && !hasSlash)
165 path = slash + path;
166
167 if (!beginning && hasSlash)
168 path = path.substring(1);
169
170 if (path.equals(pattern))
171
172 if (dirOnly && !assumeDirectory)
173
174 return false;
175 else
176
177 return true;
178
179
180
181
182
183
184 if (path.startsWith(pattern + FastIgnoreRule.PATH_SEPARATOR))
185 return true;
186
187 return false;
188 }
189
190 public boolean matches(String segment, int startIncl, int endExcl,
191 boolean assumeDirectory) {
192 throw new UnsupportedOperationException(
193 "Path matcher works only on entire paths");
194 }
195
196 boolean iterate(final String path, final int startIncl, final int endExcl,
197 boolean assumeDirectory) {
198 int matcher = 0;
199 int right = startIncl;
200 boolean match = false;
201 int lastWildmatch = -1;
202 while (true) {
203 int left = right;
204 right = path.indexOf(slash, right);
205 if (right == -1) {
206 if (left < endExcl)
207 match = matches(matcher, path, left, endExcl,
208 assumeDirectory);
209 if (match) {
210 if (matcher == matchers.size() - 2
211 && matchers.get(matcher + 1) == WILD)
212
213 return true;
214 if (matcher < matchers.size() - 1
215 && matchers.get(matcher) == WILD) {
216
217 matcher++;
218 match = matches(matcher, path, left, endExcl,
219 assumeDirectory);
220 } else if (dirOnly && !assumeDirectory)
221
222 return false;
223 }
224 return match && matcher + 1 == matchers.size();
225 }
226 if (right - left > 0)
227 match = matches(matcher, path, left, right, assumeDirectory);
228 else {
229
230 right++;
231 continue;
232 }
233 if (match) {
234 if (matchers.get(matcher) == WILD) {
235 lastWildmatch = matcher;
236
237 right = left - 1;
238 }
239 matcher++;
240 if (matcher == matchers.size())
241 return true;
242 } else if (lastWildmatch != -1)
243 matcher = lastWildmatch + 1;
244 else
245 return false;
246 right++;
247 }
248 }
249
250 boolean matches(int matcherIdx, String path, int startIncl, int endExcl,
251 boolean assumeDirectory) {
252 IMatcher matcher = matchers.get(matcherIdx);
253 return matcher.matches(path, startIncl, endExcl, assumeDirectory);
254 }
255 }