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