1 | /*
|
---|
2 | * Copyright 2001-2004 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 | package org.apache.tools.ant.taskdefs.optional.i18n;
|
---|
18 |
|
---|
19 | import java.io.BufferedReader;
|
---|
20 | import java.io.BufferedWriter;
|
---|
21 | import java.io.File;
|
---|
22 | import java.io.FileInputStream;
|
---|
23 | import java.io.FileOutputStream;
|
---|
24 | import java.io.IOException;
|
---|
25 | import java.io.InputStreamReader;
|
---|
26 | import java.io.OutputStreamWriter;
|
---|
27 | import java.util.Hashtable;
|
---|
28 | import java.util.Locale;
|
---|
29 | import java.util.Vector;
|
---|
30 | import org.apache.tools.ant.BuildException;
|
---|
31 | import org.apache.tools.ant.DirectoryScanner;
|
---|
32 | import org.apache.tools.ant.Project;
|
---|
33 | import org.apache.tools.ant.taskdefs.MatchingTask;
|
---|
34 | import org.apache.tools.ant.types.FileSet;
|
---|
35 | import org.apache.tools.ant.util.FileUtils;
|
---|
36 | import org.apache.tools.ant.util.LineTokenizer;
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * Translates text embedded in files using Resource Bundle files.
|
---|
40 | * Since ant 1.6 preserves line endings
|
---|
41 | *
|
---|
42 | */
|
---|
43 | public class Translate extends MatchingTask {
|
---|
44 | /**
|
---|
45 | * search a bundle matching the specified language, the country and the variant
|
---|
46 | */
|
---|
47 | private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT = 0;
|
---|
48 | /**
|
---|
49 | * search a bundle matching the specified language, and the country
|
---|
50 | */
|
---|
51 | private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY = 1;
|
---|
52 | /**
|
---|
53 | * search a bundle matching the specified language only
|
---|
54 | */
|
---|
55 | private static final int BUNDLE_SPECIFIED_LANGUAGE = 2;
|
---|
56 | /**
|
---|
57 | * search a bundle matching nothing special
|
---|
58 | */
|
---|
59 | private static final int BUNDLE_NOMATCH = 3;
|
---|
60 | /**
|
---|
61 | * search a bundle matching the language, the country and the variant
|
---|
62 | * of the current locale of the computer
|
---|
63 | */
|
---|
64 | private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT = 4;
|
---|
65 | /**
|
---|
66 | * search a bundle matching the language, and the country
|
---|
67 | * of the current locale of the computer
|
---|
68 | */
|
---|
69 | private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY = 5;
|
---|
70 | /**
|
---|
71 | * search a bundle matching the language only
|
---|
72 | * of the current locale of the computer
|
---|
73 | */
|
---|
74 | private static final int BUNDLE_DEFAULT_LANGUAGE = 6;
|
---|
75 | /**
|
---|
76 | * number of possibilities for the search
|
---|
77 | */
|
---|
78 | private static final int BUNDLE_MAX_ALTERNATIVES = BUNDLE_DEFAULT_LANGUAGE + 1;
|
---|
79 | /**
|
---|
80 | * Family name of resource bundle
|
---|
81 | */
|
---|
82 | private String bundle;
|
---|
83 |
|
---|
84 | /**
|
---|
85 | * Locale specific language of the resource bundle
|
---|
86 | */
|
---|
87 | private String bundleLanguage;
|
---|
88 |
|
---|
89 | /**
|
---|
90 | * Locale specific country of the resource bundle
|
---|
91 | */
|
---|
92 | private String bundleCountry;
|
---|
93 |
|
---|
94 | /**
|
---|
95 | * Locale specific variant of the resource bundle
|
---|
96 | */
|
---|
97 | private String bundleVariant;
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * Destination directory
|
---|
101 | */
|
---|
102 | private File toDir;
|
---|
103 |
|
---|
104 | /**
|
---|
105 | * Source file encoding scheme
|
---|
106 | */
|
---|
107 | private String srcEncoding;
|
---|
108 |
|
---|
109 | /**
|
---|
110 | * Destination file encoding scheme
|
---|
111 | */
|
---|
112 | private String destEncoding;
|
---|
113 |
|
---|
114 | /**
|
---|
115 | * Resource Bundle file encoding scheme, defaults to srcEncoding
|
---|
116 | */
|
---|
117 | private String bundleEncoding;
|
---|
118 |
|
---|
119 | /**
|
---|
120 | * Starting token to identify keys
|
---|
121 | */
|
---|
122 | private String startToken;
|
---|
123 |
|
---|
124 | /**
|
---|
125 | * Ending token to identify keys
|
---|
126 | */
|
---|
127 | private String endToken;
|
---|
128 |
|
---|
129 | /**
|
---|
130 | * Whether or not to create a new destination file.
|
---|
131 | * Defaults to <code>false</code>.
|
---|
132 | */
|
---|
133 | private boolean forceOverwrite;
|
---|
134 |
|
---|
135 | /**
|
---|
136 | * Vector to hold source file sets.
|
---|
137 | */
|
---|
138 | private Vector filesets = new Vector();
|
---|
139 |
|
---|
140 | /**
|
---|
141 | * Holds key value pairs loaded from resource bundle file
|
---|
142 | */
|
---|
143 | private Hashtable resourceMap = new Hashtable();
|
---|
144 | /**
|
---|
145 |
|
---|
146 | * Used to resolve file names.
|
---|
147 | */
|
---|
148 | private FileUtils fileUtils = FileUtils.newFileUtils();
|
---|
149 |
|
---|
150 | /**
|
---|
151 | * Last Modified Timestamp of resource bundle file being used.
|
---|
152 | */
|
---|
153 | private long[] bundleLastModified = new long[BUNDLE_MAX_ALTERNATIVES];
|
---|
154 |
|
---|
155 | /**
|
---|
156 | * Last Modified Timestamp of source file being used.
|
---|
157 | */
|
---|
158 | private long srcLastModified;
|
---|
159 |
|
---|
160 | /**
|
---|
161 | * Last Modified Timestamp of destination file being used.
|
---|
162 | */
|
---|
163 | private long destLastModified;
|
---|
164 |
|
---|
165 | /**
|
---|
166 | * Has at least one file from the bundle been loaded?
|
---|
167 | */
|
---|
168 | private boolean loaded = false;
|
---|
169 |
|
---|
170 | /**
|
---|
171 | * Sets Family name of resource bundle; required.
|
---|
172 | * @param bundle family name of resource bundle
|
---|
173 | */
|
---|
174 | public void setBundle(String bundle) {
|
---|
175 | this.bundle = bundle;
|
---|
176 | }
|
---|
177 |
|
---|
178 | /**
|
---|
179 | * Sets locale specific language of resource bundle; optional.
|
---|
180 | * @param bundleLanguage langage of the bundle
|
---|
181 | */
|
---|
182 | public void setBundleLanguage(String bundleLanguage) {
|
---|
183 | this.bundleLanguage = bundleLanguage;
|
---|
184 | }
|
---|
185 |
|
---|
186 | /**
|
---|
187 | * Sets locale specific country of resource bundle; optional.
|
---|
188 | * @param bundleCountry country of the bundle
|
---|
189 | */
|
---|
190 | public void setBundleCountry(String bundleCountry) {
|
---|
191 | this.bundleCountry = bundleCountry;
|
---|
192 | }
|
---|
193 |
|
---|
194 | /**
|
---|
195 | * Sets locale specific variant of resource bundle; optional.
|
---|
196 | * @param bundleVariant locale variant of resource bundle
|
---|
197 | */
|
---|
198 | public void setBundleVariant(String bundleVariant) {
|
---|
199 | this.bundleVariant = bundleVariant;
|
---|
200 | }
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * Sets Destination directory; required.
|
---|
204 | * @param toDir destination directory
|
---|
205 | */
|
---|
206 | public void setToDir(File toDir) {
|
---|
207 | this.toDir = toDir;
|
---|
208 | }
|
---|
209 |
|
---|
210 | /**
|
---|
211 | * Sets starting token to identify keys; required.
|
---|
212 | * @param startToken starting token to identify keys
|
---|
213 | */
|
---|
214 | public void setStartToken(String startToken) {
|
---|
215 | this.startToken = startToken;
|
---|
216 | }
|
---|
217 |
|
---|
218 | /**
|
---|
219 | * Sets ending token to identify keys; required.
|
---|
220 | * @param endToken ending token to identify keys
|
---|
221 | */
|
---|
222 | public void setEndToken(String endToken) {
|
---|
223 | this.endToken = endToken;
|
---|
224 | }
|
---|
225 |
|
---|
226 | /**
|
---|
227 | * Sets source file encoding scheme; optional,
|
---|
228 | * defaults to encoding of local system.
|
---|
229 | * @param srcEncoding source file encoding
|
---|
230 | */
|
---|
231 | public void setSrcEncoding(String srcEncoding) {
|
---|
232 | this.srcEncoding = srcEncoding;
|
---|
233 | }
|
---|
234 |
|
---|
235 | /**
|
---|
236 | * Sets destination file encoding scheme; optional. Defaults to source file
|
---|
237 | * encoding
|
---|
238 | * @param destEncoding destination file encoding scheme
|
---|
239 | */
|
---|
240 | public void setDestEncoding(String destEncoding) {
|
---|
241 | this.destEncoding = destEncoding;
|
---|
242 | }
|
---|
243 |
|
---|
244 | /**
|
---|
245 | * Sets Resource Bundle file encoding scheme; optional. Defaults to source file
|
---|
246 | * encoding
|
---|
247 | * @param bundleEncoding bundle file encoding scheme
|
---|
248 | */
|
---|
249 | public void setBundleEncoding(String bundleEncoding) {
|
---|
250 | this.bundleEncoding = bundleEncoding;
|
---|
251 | }
|
---|
252 |
|
---|
253 | /**
|
---|
254 | * Whether or not to overwrite existing file irrespective of
|
---|
255 | * whether it is newer than the source file as well as the
|
---|
256 | * resource bundle file.
|
---|
257 | * Defaults to false.
|
---|
258 | * @param forceOverwrite whether or not to overwrite existing files
|
---|
259 | */
|
---|
260 | public void setForceOverwrite(boolean forceOverwrite) {
|
---|
261 | this.forceOverwrite = forceOverwrite;
|
---|
262 | }
|
---|
263 |
|
---|
264 | /**
|
---|
265 | * Adds a set of files to translate as a nested fileset element.
|
---|
266 | * @param set the fileset to be added
|
---|
267 | */
|
---|
268 | public void addFileset(FileSet set) {
|
---|
269 | filesets.addElement(set);
|
---|
270 | }
|
---|
271 |
|
---|
272 | /**
|
---|
273 | * Check attributes values, load resource map and translate
|
---|
274 | * @throws BuildException if the required attributes are not set
|
---|
275 | * Required : <ul>
|
---|
276 | * <li>bundle</li>
|
---|
277 | * <li>starttoken</li>
|
---|
278 | * <li>endtoken</li>
|
---|
279 | * </ul>
|
---|
280 | */
|
---|
281 | public void execute() throws BuildException {
|
---|
282 | if (bundle == null) {
|
---|
283 | throw new BuildException("The bundle attribute must be set.",
|
---|
284 | getLocation());
|
---|
285 | }
|
---|
286 |
|
---|
287 | if (startToken == null) {
|
---|
288 | throw new BuildException("The starttoken attribute must be set.",
|
---|
289 | getLocation());
|
---|
290 | }
|
---|
291 |
|
---|
292 | if (endToken == null) {
|
---|
293 | throw new BuildException("The endtoken attribute must be set.",
|
---|
294 | getLocation());
|
---|
295 | }
|
---|
296 |
|
---|
297 | if (bundleLanguage == null) {
|
---|
298 | Locale l = Locale.getDefault();
|
---|
299 | bundleLanguage = l.getLanguage();
|
---|
300 | }
|
---|
301 |
|
---|
302 | if (bundleCountry == null) {
|
---|
303 | bundleCountry = Locale.getDefault().getCountry();
|
---|
304 | }
|
---|
305 |
|
---|
306 | if (bundleVariant == null) {
|
---|
307 | Locale l = new Locale(bundleLanguage, bundleCountry);
|
---|
308 | bundleVariant = l.getVariant();
|
---|
309 | }
|
---|
310 |
|
---|
311 | if (toDir == null) {
|
---|
312 | throw new BuildException("The todir attribute must be set.",
|
---|
313 | getLocation());
|
---|
314 | }
|
---|
315 |
|
---|
316 | if (!toDir.exists()) {
|
---|
317 | toDir.mkdirs();
|
---|
318 | } else if (toDir.isFile()) {
|
---|
319 | throw new BuildException(toDir + " is not a directory");
|
---|
320 | }
|
---|
321 |
|
---|
322 | if (srcEncoding == null) {
|
---|
323 | srcEncoding = System.getProperty("file.encoding");
|
---|
324 | }
|
---|
325 |
|
---|
326 | if (destEncoding == null) {
|
---|
327 | destEncoding = srcEncoding;
|
---|
328 | }
|
---|
329 |
|
---|
330 | if (bundleEncoding == null) {
|
---|
331 | bundleEncoding = srcEncoding;
|
---|
332 | }
|
---|
333 |
|
---|
334 | loadResourceMaps();
|
---|
335 |
|
---|
336 | translate();
|
---|
337 | }
|
---|
338 |
|
---|
339 | /**
|
---|
340 | * Load resource maps based on resource bundle encoding scheme.
|
---|
341 | * The resource bundle lookup searches for resource files with various
|
---|
342 | * suffixes on the basis of (1) the desired locale and (2) the default
|
---|
343 | * locale (basebundlename), in the following order from lower-level
|
---|
344 | * (more specific) to parent-level (less specific):
|
---|
345 | *
|
---|
346 | * basebundlename + "_" + language1 + "_" + country1 + "_" + variant1
|
---|
347 | * basebundlename + "_" + language1 + "_" + country1
|
---|
348 | * basebundlename + "_" + language1
|
---|
349 | * basebundlename
|
---|
350 | * basebundlename + "_" + language2 + "_" + country2 + "_" + variant2
|
---|
351 | * basebundlename + "_" + language2 + "_" + country2
|
---|
352 | * basebundlename + "_" + language2
|
---|
353 | *
|
---|
354 | * To the generated name, a ".properties" string is appeneded and
|
---|
355 | * once this file is located, it is treated just like a properties file
|
---|
356 | * but with bundle encoding also considered while loading.
|
---|
357 | */
|
---|
358 | private void loadResourceMaps() throws BuildException {
|
---|
359 | Locale locale = new Locale(bundleLanguage,
|
---|
360 | bundleCountry,
|
---|
361 | bundleVariant);
|
---|
362 | String language = locale.getLanguage().length() > 0
|
---|
363 | ? "_" + locale.getLanguage() : "";
|
---|
364 | String country = locale.getCountry().length() > 0
|
---|
365 | ? "_" + locale.getCountry() : "";
|
---|
366 | String variant = locale.getVariant().length() > 0
|
---|
367 | ? "_" + locale.getVariant() : "";
|
---|
368 | String bundleFile = bundle + language + country + variant;
|
---|
369 | processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT, false);
|
---|
370 |
|
---|
371 | bundleFile = bundle + language + country;
|
---|
372 | processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY, false);
|
---|
373 |
|
---|
374 | bundleFile = bundle + language;
|
---|
375 | processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE, false);
|
---|
376 |
|
---|
377 | bundleFile = bundle;
|
---|
378 | processBundle(bundleFile, BUNDLE_NOMATCH, false);
|
---|
379 |
|
---|
380 | //Load default locale bundle files
|
---|
381 | //using default file encoding scheme.
|
---|
382 | locale = Locale.getDefault();
|
---|
383 |
|
---|
384 | language = locale.getLanguage().length() > 0
|
---|
385 | ? "_" + locale.getLanguage() : "";
|
---|
386 | country = locale.getCountry().length() > 0
|
---|
387 | ? "_" + locale.getCountry() : "";
|
---|
388 | variant = locale.getVariant().length() > 0
|
---|
389 | ? "_" + locale.getVariant() : "";
|
---|
390 | bundleEncoding = System.getProperty("file.encoding");
|
---|
391 |
|
---|
392 | bundleFile = bundle + language + country + variant;
|
---|
393 | processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT, false);
|
---|
394 |
|
---|
395 | bundleFile = bundle + language + country;
|
---|
396 | processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY, false);
|
---|
397 |
|
---|
398 | bundleFile = bundle + language;
|
---|
399 | processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE, true);
|
---|
400 | }
|
---|
401 |
|
---|
402 | /**
|
---|
403 | * Process each file that makes up this bundle.
|
---|
404 | */
|
---|
405 | private void processBundle(final String bundleFile, final int i,
|
---|
406 | final boolean checkLoaded) throws BuildException {
|
---|
407 | final File propsFile = getProject().resolveFile(bundleFile + ".properties");
|
---|
408 | FileInputStream ins = null;
|
---|
409 | try {
|
---|
410 | ins = new FileInputStream(propsFile);
|
---|
411 | loaded = true;
|
---|
412 | bundleLastModified[i] = propsFile.lastModified();
|
---|
413 | log("Using " + propsFile, Project.MSG_DEBUG);
|
---|
414 | loadResourceMap(ins);
|
---|
415 | } catch (IOException ioe) {
|
---|
416 | log(propsFile + " not found.", Project.MSG_DEBUG);
|
---|
417 | //if all resource files associated with this bundle
|
---|
418 | //have been scanned for and still not able to
|
---|
419 | //find a single resrouce file, throw exception
|
---|
420 | if (!loaded && checkLoaded) {
|
---|
421 | throw new BuildException(ioe.getMessage(), getLocation());
|
---|
422 | }
|
---|
423 | }
|
---|
424 | }
|
---|
425 |
|
---|
426 | /**
|
---|
427 | * Load resourceMap with key value pairs. Values of existing keys
|
---|
428 | * are not overwritten. Bundle's encoding scheme is used.
|
---|
429 | */
|
---|
430 | private void loadResourceMap(FileInputStream ins) throws BuildException {
|
---|
431 | try {
|
---|
432 | BufferedReader in = null;
|
---|
433 | InputStreamReader isr = new InputStreamReader(ins, bundleEncoding);
|
---|
434 | in = new BufferedReader(isr);
|
---|
435 | String line = null;
|
---|
436 | while ((line = in.readLine()) != null) {
|
---|
437 | //So long as the line isn't empty and isn't a comment...
|
---|
438 | if (line.trim().length() > 1 && '#' != line.charAt(0) && '!' != line.charAt(0)) {
|
---|
439 | //Legal Key-Value separators are :, = and white space.
|
---|
440 | int sepIndex = line.indexOf('=');
|
---|
441 | if (-1 == sepIndex) {
|
---|
442 | sepIndex = line.indexOf(':');
|
---|
443 | }
|
---|
444 | if (-1 == sepIndex) {
|
---|
445 | for (int k = 0; k < line.length(); k++) {
|
---|
446 | if (Character.isSpaceChar(line.charAt(k))) {
|
---|
447 | sepIndex = k;
|
---|
448 | break;
|
---|
449 | }
|
---|
450 | }
|
---|
451 | }
|
---|
452 | //Only if we do have a key is there going to be a value
|
---|
453 | if (-1 != sepIndex) {
|
---|
454 | String key = line.substring(0, sepIndex).trim();
|
---|
455 | String value = line.substring(sepIndex + 1).trim();
|
---|
456 | //Handle line continuations, if any
|
---|
457 | while (value.endsWith("\\")) {
|
---|
458 | value = value.substring(0, value.length() - 1);
|
---|
459 | if ((line = in.readLine()) != null) {
|
---|
460 | value = value + line.trim();
|
---|
461 | } else {
|
---|
462 | break;
|
---|
463 | }
|
---|
464 | }
|
---|
465 | if (key.length() > 0) {
|
---|
466 | //Has key already been loaded into resourceMap?
|
---|
467 | if (resourceMap.get(key) == null) {
|
---|
468 | resourceMap.put(key, value);
|
---|
469 | }
|
---|
470 | }
|
---|
471 | }
|
---|
472 | }
|
---|
473 | }
|
---|
474 | if (in != null) {
|
---|
475 | in.close();
|
---|
476 | }
|
---|
477 | } catch (IOException ioe) {
|
---|
478 | throw new BuildException(ioe.getMessage(), getLocation());
|
---|
479 | }
|
---|
480 | }
|
---|
481 |
|
---|
482 | /**
|
---|
483 | * Reads source file line by line using the source encoding and
|
---|
484 | * searches for keys that are sandwiched between the startToken
|
---|
485 | * and endToken. The values for these keys are looked up from
|
---|
486 | * the hashtable and substituted. If the hashtable doesn't
|
---|
487 | * contain the key, they key itself is used as the value.
|
---|
488 | * Detination files and directories are created as needed.
|
---|
489 | * The destination file is overwritten only if
|
---|
490 | * the forceoverwritten attribute is set to true if
|
---|
491 | * the source file or any associated bundle resource file is
|
---|
492 | * newer than the destination file.
|
---|
493 | */
|
---|
494 | private void translate() throws BuildException {
|
---|
495 | for (int i = 0; i < filesets.size(); i++) {
|
---|
496 | FileSet fs = (FileSet) filesets.elementAt(i);
|
---|
497 | DirectoryScanner ds = fs.getDirectoryScanner(getProject());
|
---|
498 | String[] srcFiles = ds.getIncludedFiles();
|
---|
499 | for (int j = 0; j < srcFiles.length; j++) {
|
---|
500 | try {
|
---|
501 | File dest = fileUtils.resolveFile(toDir, srcFiles[j]);
|
---|
502 | //Make sure parent dirs exist, else, create them.
|
---|
503 | try {
|
---|
504 | File destDir = new File(dest.getParent());
|
---|
505 | if (!destDir.exists()) {
|
---|
506 | destDir.mkdirs();
|
---|
507 | }
|
---|
508 | } catch (Exception e) {
|
---|
509 | log("Exception occurred while trying to check/create "
|
---|
510 | + " parent directory. " + e.getMessage(),
|
---|
511 | Project.MSG_DEBUG);
|
---|
512 | }
|
---|
513 | destLastModified = dest.lastModified();
|
---|
514 | File src = fileUtils.resolveFile(ds.getBasedir(), srcFiles[j]);
|
---|
515 | srcLastModified = src.lastModified();
|
---|
516 | //Check to see if dest file has to be recreated
|
---|
517 | boolean needsWork = forceOverwrite
|
---|
518 | || destLastModified < srcLastModified;
|
---|
519 | if (!needsWork) {
|
---|
520 | for (int icounter = 0; icounter < BUNDLE_MAX_ALTERNATIVES; icounter++) {
|
---|
521 | needsWork = (destLastModified < bundleLastModified[icounter]);
|
---|
522 | if (needsWork) {
|
---|
523 | break;
|
---|
524 | }
|
---|
525 | }
|
---|
526 | }
|
---|
527 | if (needsWork) {
|
---|
528 | log("Processing " + srcFiles[j],
|
---|
529 | Project.MSG_DEBUG);
|
---|
530 | FileOutputStream fos = new FileOutputStream(dest);
|
---|
531 | BufferedWriter out
|
---|
532 | = new BufferedWriter(new OutputStreamWriter(fos, destEncoding));
|
---|
533 | FileInputStream fis = new FileInputStream(src);
|
---|
534 | BufferedReader in
|
---|
535 | = new BufferedReader(new InputStreamReader(fis, srcEncoding));
|
---|
536 | String line;
|
---|
537 | LineTokenizer lineTokenizer = new LineTokenizer();
|
---|
538 | lineTokenizer.setIncludeDelims(true);
|
---|
539 | line = lineTokenizer.getToken(in);
|
---|
540 | while ((line) != null) {
|
---|
541 | // 2003-02-21 new replace algorithm by tbee ([email protected])
|
---|
542 | // because it wasn't able to replace something like "@aaa;@bbb;"
|
---|
543 |
|
---|
544 | // is there a startToken
|
---|
545 | // and there is still stuff following the startToken
|
---|
546 | int startIndex = line.indexOf(startToken);
|
---|
547 | while (startIndex >= 0
|
---|
548 | && (startIndex + startToken.length()) <= line.length()) {
|
---|
549 | // the new value, this needs to be here
|
---|
550 | // because it is required to calculate the next position to search from
|
---|
551 | // at the end of the loop
|
---|
552 | String replace = null;
|
---|
553 |
|
---|
554 | // we found a starttoken, is there an endtoken following?
|
---|
555 | // start at token+tokenlength because start and end
|
---|
556 | // token may be indentical
|
---|
557 | int endIndex = line.indexOf(endToken, startIndex + startToken.length());
|
---|
558 | if (endIndex < 0) {
|
---|
559 | startIndex += 1;
|
---|
560 | } else {
|
---|
561 | // grab the token
|
---|
562 | String token
|
---|
563 | = line.substring(startIndex + startToken.length(), endIndex);
|
---|
564 |
|
---|
565 | // If there is a white space or = or :, then
|
---|
566 | // it isn't to be treated as a valid key.
|
---|
567 | boolean validToken = true;
|
---|
568 | for (int k = 0; k < token.length() && validToken; k++) {
|
---|
569 | char c = token.charAt(k);
|
---|
570 | if (c == ':' || c == '='
|
---|
571 | || Character.isSpaceChar(c)) {
|
---|
572 | validToken = false;
|
---|
573 | }
|
---|
574 | }
|
---|
575 | if (!validToken) {
|
---|
576 | startIndex += 1;
|
---|
577 | } else {
|
---|
578 | // find the replace string
|
---|
579 | if (resourceMap.containsKey(token)) {
|
---|
580 | replace = (String) resourceMap.get(token);
|
---|
581 | } else {
|
---|
582 | replace = token;
|
---|
583 | }
|
---|
584 |
|
---|
585 |
|
---|
586 | // generate the new line
|
---|
587 | line = line.substring(0, startIndex)
|
---|
588 | + replace
|
---|
589 | + line.substring(endIndex + endToken.length());
|
---|
590 |
|
---|
591 | // set start position for next search
|
---|
592 | startIndex += replace.length();
|
---|
593 | }
|
---|
594 | }
|
---|
595 |
|
---|
596 | // find next starttoken
|
---|
597 | startIndex = line.indexOf(startToken, startIndex);
|
---|
598 | }
|
---|
599 |
|
---|
600 |
|
---|
601 | out.write(line);
|
---|
602 | line = lineTokenizer.getToken(in);
|
---|
603 | }
|
---|
604 | if (in != null) {
|
---|
605 | in.close();
|
---|
606 | }
|
---|
607 | if (out != null) {
|
---|
608 | out.close();
|
---|
609 | }
|
---|
610 | } else {
|
---|
611 | log("Skipping " + srcFiles[j]
|
---|
612 | + " as destination file is up to date",
|
---|
613 | Project.MSG_VERBOSE);
|
---|
614 | }
|
---|
615 | } catch (IOException ioe) {
|
---|
616 | throw new BuildException(ioe.getMessage(), getLocation());
|
---|
617 | }
|
---|
618 | }
|
---|
619 | }
|
---|
620 | }
|
---|
621 | }
|
---|