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 @Override
163 public long skip( long n )
164 throws IOException, IllegalArgumentException
165 {
166 if ( n < 0L )
167 {
168 throw new IllegalArgumentException( "skip value is negative" );
169 }
170
171 for ( long i = 0; i < n; i++ )
172 {
173 if ( read() == -1 )
174 {
175 return i;
176 }
177 }
178 return n;
179 }
180
181
182
183
184
185
186
187
188
189
190
191 @Override
192 public int read( char cbuf[], int off, int len )
193 throws IOException
194 {
195 for ( int i = 0; i < len; i++ )
196 {
197 int ch = read();
198 if ( ch == -1 )
199 {
200 if ( i == 0 )
201 {
202 return -1;
203 }
204 else
205 {
206 return i;
207 }
208 }
209 cbuf[off + i] = (char) ch;
210 }
211 return len;
212 }
213
214
215
216
217
218
219
220 @Override
221 public int read()
222 throws IOException
223 {
224 if ( replaceIndex > 0 )
225 {
226 return replaceData.charAt( replaceData.length() - ( replaceIndex-- ) );
227 }
228 if ( eof )
229 {
230 return -1;
231 }
232
233 BoundedReader in = new BoundedReader( this.in, markLength );
234
235 int ch = in.read();
236 if ( ch == -1 || ( ch == '\n' && !supportMultiLineFiltering ) )
237 {
238 return ch;
239 }
240
241 boolean inEscape = useEscape && ch == getEscapeString().charAt( 0 );
242
243 StringBuilder key = new StringBuilder();
244
245
246 if ( inEscape )
247 {
248 for ( int i = 0; i < getEscapeString().length(); i++ )
249 {
250 key.append( (char) ch );
251
252 if ( ch != getEscapeString().charAt( i ) || ch == -1 || ( ch == '\n' && !supportMultiLineFiltering ) )
253 {
254
255 in.reset();
256 inEscape = false;
257 key.setLength( 0 );
258 break;
259 }
260
261 ch = in.read();
262
263 }
264
265 }
266
267
268 int max = 0;
269 for ( DelimiterSpecification spec : delimiters )
270 {
271 String begin = spec.getBegin();
272
273
274 if ( begin.length() < max )
275 {
276 continue;
277 }
278
279 for ( int i = 0; i < begin.length(); i++ )
280 {
281 if ( ch != begin.charAt( i ) || ch == -1 || ( ch == '\n' && !supportMultiLineFiltering ) )
282 {
283
284 break;
285 }
286
287 if ( i == begin.length() - 1 )
288 {
289
290 beginToken = spec.getBegin();
291 endToken = spec.getEnd();
292
293 }
294
295 ch = in.read();
296
297 }
298
299 in.reset();
300 in.skip( key.length() );
301 ch = in.read();
302
303 }
304
305
306 if ( inEscape )
307 {
308
309 if ( beginToken != null )
310 {
311 if ( !isPreserveEscapeString() )
312 {
313 key.setLength( 0 );
314 }
315 }
316
317 beginToken = null;
318 endToken = null;
319
320 key.append( (char) ch );
321
322 replaceData = key.toString();
323 replaceIndex = key.length();
324
325 return read();
326
327 }
328
329
330 if ( beginToken == null || beginToken.length() == 0 || endToken == null || endToken.length() == 0 )
331 {
332
333 in.reset();
334 return in.read();
335
336 }
337
338
339
340 key.append( beginToken );
341 in.reset();
342 in.skip( beginToken.length() );
343 ch = in.read();
344
345 int endTokenSize = endToken.length();
346 int end = endTokenSize;
347 do
348 {
349 if ( ch == -1 )
350 {
351 break;
352 }
353 else if ( ch == '\n' && !supportMultiLineFiltering )
354 {
355
356 key.append( (char) ch );
357 break;
358 }
359
360 key.append( (char) ch );
361
362 if ( ch == this.endToken.charAt( endTokenSize - end ) )
363 {
364 end--;
365 if ( end == 0 )
366 {
367 break;
368 }
369 }
370 else
371 {
372 end = endTokenSize;
373 }
374
375 ch = in.read();
376 }
377 while ( true );
378
379
380 beginToken = null;
381 endToken = null;
382
383
384 String value = null;
385 if ( end == 0 )
386 {
387 try
388 {
389 if ( interpolateWithPrefixPattern )
390 {
391 value = interpolator.interpolate( key.toString(), "", recursionInterceptor );
392 }
393 else
394 {
395 value = interpolator.interpolate( key.toString(), recursionInterceptor );
396 }
397 }
398 catch ( InterpolationException e )
399 {
400 IllegalArgumentException error = new IllegalArgumentException( e.getMessage() );
401 error.initCause( e );
402
403 throw error;
404 }
405 }
406 else
407 {
408
409 in.reset();
410 return in.read();
411 }
412
413
414 if ( value != null )
415 {
416 replaceData = value;
417 replaceIndex = value.length();
418 }
419 else
420 {
421 replaceData = key.toString();
422 replaceIndex = key.length();
423 }
424
425 if ( ch == -1 )
426 {
427 eof = true;
428 }
429 return read();
430
431 }
432
433
434
435
436 public boolean isInterpolateWithPrefixPattern()
437 {
438 return interpolateWithPrefixPattern;
439 }
440
441
442
443
444 public void setInterpolateWithPrefixPattern( boolean interpolateWithPrefixPattern )
445 {
446 this.interpolateWithPrefixPattern = interpolateWithPrefixPattern;
447 }
448
449
450
451
452 public RecursionInterceptor getRecursionInterceptor()
453 {
454 return recursionInterceptor;
455 }
456
457
458
459
460
461
462 public AbstractFilterReaderLineEnding setRecursionInterceptor( RecursionInterceptor givenRecursionInterceptor )
463
464 {
465 this.recursionInterceptor = givenRecursionInterceptor;
466 return this;
467 }
468
469 }