1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.filtering;
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.util.Set;
25
26 import org.codehaus.plexus.interpolation.InterpolationException;
27 import org.codehaus.plexus.interpolation.Interpolator;
28 import org.codehaus.plexus.interpolation.RecursionInterceptor;
29 import org.codehaus.plexus.interpolation.SimpleRecursionInterceptor;
30 import org.codehaus.plexus.interpolation.multi.DelimiterSpecification;
31
32
33
34
35
36
37
38
39
40 public class MultiDelimiterInterpolatorFilterReaderLineEnding extends AbstractFilterReaderLineEnding {
41
42
43
44
45 private Interpolator interpolator;
46
47 private RecursionInterceptor recursionInterceptor;
48
49
50
51
52 private String replaceData = null;
53
54
55
56
57 private int replaceIndex = 0;
58
59
60
61
62 public static final String DEFAULT_BEGIN_TOKEN = "${";
63
64
65
66
67 public static final String DEFAULT_END_TOKEN = "}";
68
69
70
71
72 private boolean interpolateWithPrefixPattern = true;
73
74 private String beginToken;
75
76 private String endToken;
77
78 private boolean supportMultiLineFiltering;
79
80 private static final int MAXIMUM_BUFFER_SIZE = 8192;
81
82 private boolean eof = false;
83
84
85
86
87
88
89
90
91 public MultiDelimiterInterpolatorFilterReaderLineEnding(
92 Reader in, Interpolator interpolator, boolean supportMultiLineFiltering) {
93 this(in, interpolator, new SimpleRecursionInterceptor(), supportMultiLineFiltering);
94 }
95
96
97
98
99
100
101
102 public MultiDelimiterInterpolatorFilterReaderLineEnding(
103 Reader in, Interpolator interpolator, RecursionInterceptor ri, boolean supportMultiLineFiltering) {
104
105 super(new BufferedReader(in, MAXIMUM_BUFFER_SIZE));
106
107 this.interpolator = interpolator;
108
109
110 this.interpolator.setCacheAnswers(true);
111
112 recursionInterceptor = ri;
113
114 delimiters.add(DelimiterSpecification.DEFAULT_SPEC);
115
116 this.supportMultiLineFiltering = supportMultiLineFiltering;
117
118 calculateMarkLength();
119 }
120
121
122
123
124
125 public boolean removeDelimiterSpec(String delimiterSpec) {
126 return delimiters.remove(DelimiterSpecification.parse(delimiterSpec));
127 }
128
129
130
131
132
133 public AbstractFilterReaderLineEnding setDelimiterSpecs(Set<String> specs) {
134 delimiters.clear();
135 for (String spec : specs) {
136 delimiters.add(DelimiterSpecification.parse(spec));
137 markLength += spec.length() * 2;
138 }
139
140 return this;
141 }
142
143
144
145
146
147
148
149
150
151
152 @Override
153 public long skip(long n) throws IOException, IllegalArgumentException {
154 if (n < 0L) {
155 throw new IllegalArgumentException("skip value is negative");
156 }
157
158 for (long i = 0; i < n; i++) {
159 if (read() == -1) {
160 return i;
161 }
162 }
163 return n;
164 }
165
166
167
168
169
170
171
172
173
174
175
176 @Override
177 public int read(char[] cbuf, int off, int len) throws IOException {
178 for (int i = 0; i < len; i++) {
179 int ch = read();
180 if (ch == -1) {
181 if (i == 0) {
182 return -1;
183 } else {
184 return i;
185 }
186 }
187 cbuf[off + i] = (char) ch;
188 }
189 return len;
190 }
191
192
193
194
195
196
197
198 @Override
199 public int read() throws IOException {
200 if (replaceIndex > 0) {
201 return replaceData.charAt(replaceData.length() - (replaceIndex--));
202 }
203 if (eof) {
204 return -1;
205 }
206
207 BoundedReader in = new BoundedReader(this.in, markLength);
208
209 int ch = in.read();
210 if (ch == -1 || (ch == '\n' && !supportMultiLineFiltering)) {
211 return ch;
212 }
213
214 boolean inEscape = useEscape && ch == getEscapeString().charAt(0);
215
216 StringBuilder key = new StringBuilder();
217
218
219 if (inEscape) {
220 for (int i = 0; i < getEscapeString().length(); i++) {
221 key.append((char) ch);
222
223 if (ch != getEscapeString().charAt(i) || ch == '\n' && !supportMultiLineFiltering) {
224
225 in.reset();
226 inEscape = false;
227 key.setLength(0);
228 break;
229 }
230
231 ch = in.read();
232 }
233 }
234
235
236 int max = 0;
237 for (DelimiterSpecification spec : delimiters) {
238 String begin = spec.getBegin();
239
240
241 if (begin.length() < max) {
242 continue;
243 }
244
245 for (int i = 0; i < begin.length(); i++) {
246 if (ch != begin.charAt(i) || ch == '\n' && !supportMultiLineFiltering) {
247
248 break;
249 }
250
251 if (i == begin.length() - 1) {
252
253 beginToken = spec.getBegin();
254 endToken = spec.getEnd();
255 }
256
257 ch = in.read();
258 }
259
260 in.reset();
261 in.skip(key.length());
262 ch = in.read();
263 }
264
265
266 if (inEscape) {
267
268 if (beginToken != null) {
269 if (!isPreserveEscapeString()) {
270 key.setLength(0);
271 }
272 }
273
274 beginToken = null;
275 endToken = null;
276
277 key.append((char) ch);
278
279 replaceData = key.toString();
280 replaceIndex = key.length();
281
282 return read();
283 }
284
285
286 if (beginToken == null || beginToken.length() == 0 || endToken == null || endToken.length() == 0) {
287
288 in.reset();
289 return in.read();
290 }
291
292
293
294 key.append(beginToken);
295 in.reset();
296 in.skip(beginToken.length());
297 ch = in.read();
298
299 int endTokenSize = endToken.length();
300 int end = endTokenSize;
301 do {
302 if (ch == -1) {
303 break;
304 } else if (ch == '\n' && !supportMultiLineFiltering) {
305
306 key.append((char) ch);
307 break;
308 }
309
310 key.append((char) ch);
311
312 if (ch == this.endToken.charAt(endTokenSize - end)) {
313 end--;
314 if (end == 0) {
315 break;
316 }
317 } else {
318 end = endTokenSize;
319 }
320
321 ch = in.read();
322 } while (true);
323
324
325 beginToken = null;
326 endToken = null;
327
328
329 String value;
330 if (end == 0) {
331 try {
332 if (interpolateWithPrefixPattern) {
333 value = interpolator.interpolate(key.toString(), "", recursionInterceptor);
334 } else {
335 value = interpolator.interpolate(key.toString(), recursionInterceptor);
336 }
337 } catch (InterpolationException e) {
338 throw new IllegalArgumentException(e);
339 }
340 } else {
341
342 in.reset();
343 return in.read();
344 }
345
346
347 if (value != null) {
348 replaceData = value;
349 replaceIndex = value.length();
350 } else {
351 replaceData = key.toString();
352 replaceIndex = key.length();
353 }
354
355 if (ch == -1) {
356 eof = true;
357 }
358 return read();
359 }
360
361
362
363
364 public boolean isInterpolateWithPrefixPattern() {
365 return interpolateWithPrefixPattern;
366 }
367
368
369
370
371 public void setInterpolateWithPrefixPattern(boolean interpolateWithPrefixPattern) {
372 this.interpolateWithPrefixPattern = interpolateWithPrefixPattern;
373 }
374
375
376
377
378 public RecursionInterceptor getRecursionInterceptor() {
379 return recursionInterceptor;
380 }
381
382
383
384
385
386
387 public AbstractFilterReaderLineEnding setRecursionInterceptor(RecursionInterceptor givenRecursionInterceptor)
388
389 {
390 this.recursionInterceptor = givenRecursionInterceptor;
391 return this;
392 }
393 }