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