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