1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jexl3.internal.introspection;
19
20 import java.util.LinkedHashSet;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class PermissionsParser {
55
56 private String src;
57
58 private int size;
59
60 private Map<String, Permissions.NoJexlPackage> packages;
61
62 private Set<String> wildcards;
63
64
65
66
67 public PermissionsParser() {
68 }
69
70
71
72
73 private void clear() {
74 src = null; size = 0; packages = null; wildcards = null;
75 }
76
77
78
79
80
81
82 public Permissions parse(final String... srcs) {
83 return parse(new LinkedHashSet<>(), new ConcurrentHashMap<>(), srcs);
84 }
85
86
87
88
89
90
91
92
93 synchronized Permissions parse(Set<String> wildcards, Map<String, Permissions.NoJexlPackage> packages, final String... srcs) {
94 try {
95 if (srcs == null || srcs.length == 0) {
96 return Permissions.UNRESTRICTED;
97 }
98 this.packages = packages;
99 this.wildcards = wildcards;
100 for (final String src : srcs) {
101 this.src = src;
102 this.size = src.length();
103 readPackages();
104 }
105 final Permissions permissions = new Permissions(wildcards, packages);
106 return permissions;
107 } finally {
108 clear();
109 }
110 }
111
112
113
114
115
116
117
118 private String unexpected(final char c, final int i) {
119 return "unexpected '" + c + "'" + "@" + i;
120 }
121
122
123
124
125
126
127 private int readEol(final int offset) {
128 int i = offset;
129 while (i < size) {
130 final char c = src.charAt(i);
131 if (c == '\n') {
132 break;
133 }
134 i += 1;
135 }
136 return i;
137 }
138
139
140
141
142
143
144 private int readSpaces(final int offset) {
145 int i = offset;
146 while (i < size) {
147 final char c = src.charAt(i);
148 if (!Character.isWhitespace(c)) {
149 break;
150 }
151 i += 1;
152 }
153 return offset;
154 }
155
156
157
158
159
160
161
162 private int readIdentifier(final StringBuilder id, final int offset) {
163 return readIdentifier(id, offset, false, false);
164 }
165
166
167
168
169
170
171
172
173
174 private int readIdentifier(final StringBuilder id, final int offset, final boolean dot, final boolean star) {
175 int begin = -1;
176 boolean starf = star;
177 int i = offset;
178 char c = 0;
179 while (i < size) {
180 c = src.charAt(i);
181
182 if (Character.isJavaIdentifierStart(c) && begin < 0) {
183 begin = i;
184 id.append(c);
185 } else if (Character.isJavaIdentifierPart(c) && begin >= 0) {
186 id.append(c);
187 } else if (dot && c == '.') {
188 if (src.charAt(i - 1) == '.') {
189 throw new IllegalStateException(unexpected(c, i));
190 }
191 id.append('.');
192 begin = -1;
193 } else if (starf && c == '*') {
194 id.append('*');
195 starf = false;
196 } else {
197 break;
198 }
199 i += 1;
200 }
201
202 if (dot && c == '.') {
203 throw new IllegalStateException(unexpected(c, i));
204 }
205 return i;
206 }
207
208
209
210
211 private void readPackages() {
212 final StringBuilder temp = new StringBuilder();
213 Permissions.NoJexlPackage njpackage = null;
214 int i = 0;
215 int j = -1;
216 String pname = null;
217 while (i < size) {
218 final char c = src.charAt(i);
219
220 if (j >= i) {
221 throw new IllegalStateException(unexpected(c, i));
222 }
223 j = i;
224
225 if (Character.isWhitespace(c)) {
226 i = readSpaces(i + 1);
227 continue;
228 }
229
230 if (c == '#') {
231 i = readEol(i + 1);
232 continue;
233 }
234
235 if (pname == null) {
236 final int next = readIdentifier(temp, i, true, true);
237 if (i != next) {
238 pname = temp.toString();
239 temp.setLength(0);
240 i = next;
241
242 if (pname.endsWith(".*")) {
243 wildcards.add(pname);
244 pname = null;
245 }
246 continue;
247 }
248 }
249
250 if (njpackage == null) {
251 if (c == '{') {
252 njpackage = new Permissions.NoJexlPackage();
253 packages.put(pname, njpackage);
254 i += 1;
255 }
256 } else if (c == '}') {
257
258 if (njpackage.isEmpty()) {
259 packages.put(pname, Permissions.NOJEXL_PACKAGE);
260 }
261 njpackage = null;
262 pname = null;
263 i += 1;
264 } else {
265 i = readClass(njpackage, null, null, i);
266 }
267 }
268 }
269
270
271
272
273
274
275
276
277
278 private int readClass(final Permissions.NoJexlPackage njpackage, final String outer, final String inner, final int offset) {
279 final StringBuilder temp = new StringBuilder();
280 Permissions.NoJexlClass njclass = null;
281 String njname = null;
282 String identifier = inner;
283 int i = offset;
284 int j = -1;
285 boolean isMethod = false;
286 while(i < size) {
287 final char c = src.charAt(i);
288
289 if (j >= i) {
290 throw new IllegalStateException(unexpected(c, i));
291 }
292 j = i;
293
294 if (Character.isWhitespace(c)) {
295 i = readSpaces(i + 1);
296 continue;
297 }
298
299 if (c == '#') {
300 i = readEol(i + 1);
301 continue;
302 }
303
304 if (njclass != null && c == '}') {
305
306 if (njclass.isEmpty()) {
307 njpackage.addNoJexl(njname, Permissions.NOJEXL_CLASS);
308 }
309 i += 1;
310 break;
311 }
312
313 if (identifier == null) {
314 final int next = readIdentifier(temp, i);
315 if (i != next) {
316 identifier = temp.toString();
317 temp.setLength(0);
318 i = next;
319 continue;
320 }
321 }
322
323 if (njclass == null) {
324
325 if ((identifier == null) || (c != '{')) {
326 throw new IllegalStateException(unexpected(c, i));
327 }
328
329 njclass = new Permissions.NoJexlClass();
330 njname = outer != null ? outer + "$" + identifier : identifier;
331 njpackage.addNoJexl(njname, njclass);
332 identifier = null;
333 } else if (identifier != null) {
334
335 if (c == '{') {
336
337 i = readClass(njpackage, njname, identifier, i - 1);
338 identifier = null;
339 continue;
340 }
341 if (c == ';') {
342
343 if (isMethod) {
344 njclass.methodNames.add(identifier);
345 isMethod = false;
346 } else {
347 njclass.fieldNames.add(identifier);
348 }
349 identifier = null;
350 } else if (c == '(' && !isMethod) {
351
352 isMethod = true;
353 } else if (c != ')' || src.charAt(i - 1) != '(') {
354
355 throw new IllegalStateException(unexpected(c, i));
356 }
357 }
358 i += 1;
359 }
360 return i;
361 }
362 }