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