diff --git a/src/main/org/apache/tools/ant/listener/MailLogger.java b/src/main/org/apache/tools/ant/listener/MailLogger.java index de9cda0c6c..d771641150 100644 --- a/src/main/org/apache/tools/ant/listener/MailLogger.java +++ b/src/main/org/apache/tools/ant/listener/MailLogger.java @@ -36,6 +36,7 @@ import org.apache.tools.ant.taskdefs.email.EmailAddress; import org.apache.tools.ant.taskdefs.email.Mailer; import org.apache.tools.ant.taskdefs.email.Message; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.util.ClasspathUtils; import org.apache.tools.ant.util.DateUtils; import org.apache.tools.ant.util.FileUtils; @@ -96,6 +97,7 @@ */ public class MailLogger extends DefaultLogger { private static final String DEFAULT_MIME_TYPE = "text/plain"; + private static final String DEFAULT_CHARSET_NAME = "default"; /** Buffer in which the message is constructed prior to sending */ private StringBuffer buffer = new StringBuffer(); @@ -159,7 +161,7 @@ public void buildFinished(BuildEvent event) { .toCcList(getValue(properties, prefix + ".cc", "")) .toBccList(getValue(properties, prefix + ".bcc", "")) .mimeType(getValue(properties, "mimeType", DEFAULT_MIME_TYPE)) - .charset(getValue(properties, "charset", "")) + .charSet(new CharSet(getValue(properties, "charset", DEFAULT_CHARSET_NAME))) .body(getValue(properties, prefix + ".body", "")) .subject(getValue( properties, prefix + ".subject", @@ -267,12 +269,19 @@ public Values subject(String subject) { this.subject = subject; return this; } - private String charset; + private CharSet charSet; public String charset() { - return charset; + return charSet.getValue(); + } + public CharSet charSet() { + return charSet; } public Values charset(String charset) { - this.charset = charset; + this.charSet = new CharSet(charset); + return this; + } + public Values charSet(CharSet charSet) { + this.charSet = charSet; return this; } private String mimeType; @@ -365,7 +374,7 @@ private void sendMail(Values values, String message) throws IOException { mailMessage.setSubject(values.subject()); - if (values.charset().isEmpty()) { + if (DEFAULT_CHARSET_NAME.equals(values.charset())) { mailMessage.setHeader("Content-Type", values.mimeType()); } else { mailMessage.setHeader("Content-Type", values.mimeType() @@ -406,8 +415,8 @@ private void sendMimeMail(Project project, Values values, String message) { new Message(!values.body().isEmpty() ? values.body() : message); mymessage.setProject(project); mymessage.setMimeType(values.mimeType()); - if (!values.charset().isEmpty()) { - mymessage.setCharset(values.charset()); + if (!DEFAULT_CHARSET_NAME.equals(values.charset())) { + mymessage.setCharSet(values.charSet()); } mailer.setMessage(mymessage); mailer.setFrom(new EmailAddress(values.from())); diff --git a/src/main/org/apache/tools/ant/taskdefs/Concat.java b/src/main/org/apache/tools/ant/taskdefs/Concat.java index 333bad9058..7d51132f50 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Concat.java +++ b/src/main/org/apache/tools/ant/taskdefs/Concat.java @@ -19,7 +19,6 @@ import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -37,6 +36,7 @@ import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.util.ChainReaderHelper; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FilterChain; @@ -89,11 +89,11 @@ public class Concat extends Task implements ResourceCollection { * sub element points to a file or contains text */ public static class TextElement extends ProjectComponent { - private String value = ""; - private boolean trimLeading = false; - private boolean trim = false; - private boolean filtering = true; - private String encoding = null; + private String value = ""; + private boolean trimLeading = false; + private boolean trim = false; + private boolean filtering = true; + private CharSet charSet = CharSet.getDefault(); /** * whether to filter the text in this element @@ -117,7 +117,16 @@ private boolean getFiltering() { * @param encoding the name of the charset used to encode */ public void setEncoding(String encoding) { - this.encoding = encoding; + this.charSet = new CharSet(encoding); + } + + /** + * The CharSet of the text element + * + * @param charSet the name of the charset used to encode + */ + public void setEncoding(CharSet charSet) { + this.charSet = charSet; } /** @@ -132,20 +141,11 @@ public void setFile(File file) throws BuildException { throw new BuildException("File %s does not exist.", file); } - BufferedReader reader = null; - try { - if (this.encoding == null) { - reader = new BufferedReader(new FileReader(file)); - } else { - reader = new BufferedReader( - new InputStreamReader(Files.newInputStream(file.toPath()), - this.encoding)); - } + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + Files.newInputStream(file.toPath()), charSet.getCharset()))) { value = FileUtils.safeReadFully(reader); } catch (IOException ex) { throw new BuildException(ex); - } finally { - FileUtils.close(reader); } } @@ -418,8 +418,7 @@ public InputStream getInputStream() { rdr = new MultiReader<>(Arrays.asList(readers).iterator(), identityReaderFactory); } - return outputEncoding == null ? new ReaderInputStream(rdr) - : new ReaderInputStream(rdr, outputEncoding); + return new ReaderInputStream(rdr, outputCharSet.getCharset()); } @Override public String getName() { @@ -444,12 +443,18 @@ public String getName() { private boolean append; /** - * Stores the input file encoding. + * Stores the input file CharSet. */ - private String encoding; + private CharSet charSet = CharSet.getDefault(); + + /** Indicates if attribute is set explicitly */ + private boolean hasCharSet = false; + + /** Stores the output file CharSet. */ + private CharSet outputCharSet = CharSet.getDefault(); - /** Stores the output file encoding. */ - private String outputEncoding; + /** Indicates if attribute is set explicitly */ + private boolean hasOutputCharSet = false; /** Stores the binary attribute */ private boolean binary; @@ -489,15 +494,9 @@ public String getName() { /** exposed resource name */ private String resourceName; - private ReaderFactory resourceReaderFactory = new ReaderFactory() { - @Override - public Reader getReader(Resource o) throws IOException { - InputStream is = o.getInputStream(); - return new BufferedReader(encoding == null - ? new InputStreamReader(is) - : new InputStreamReader(is, encoding)); - } - }; + private ReaderFactory resourceReaderFactory = + o -> new BufferedReader(new InputStreamReader(o.getInputStream(), + charSet.getCharset())); private ReaderFactory identityReaderFactory = o -> o; @@ -515,8 +514,10 @@ public void reset() { append = false; forceOverwrite = true; dest = null; - encoding = null; - outputEncoding = null; + charSet = CharSet.getDefault(); + hasCharSet = false; + outputCharSet = CharSet.getDefault(); + hasOutputCharSet = false; fixLastLine = false; filterChains = null; footer = null; @@ -566,10 +567,7 @@ public void setAppend(boolean append) { * outputencoding is set, the outputstream. */ public void setEncoding(String encoding) { - this.encoding = encoding; - if (outputEncoding == null) { - outputEncoding = encoding; - } + setCharSet(new CharSet(encoding)); } /** @@ -578,7 +576,30 @@ public void setEncoding(String encoding) { * @since Ant 1.6 */ public void setOutputEncoding(String outputEncoding) { - this.outputEncoding = outputEncoding; + setOutputCharSet(new CharSet(outputEncoding)); + } + + + /** + * Sets the charset + * @param charSet the charset of the input stream and unless + * outputcharset is set, the outputstream. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; + hasCharSet = true; + if (!hasOutputCharSet) { + outputCharSet = charSet; + } + } + + /** + * Sets the charset for outputting + * @param outputCharSet the charset for the output file + */ + public void setOutputCharSet(CharSet outputCharSet) { + this.outputCharSet = outputCharSet; + hasOutputCharSet = true; } /** @@ -802,8 +823,8 @@ public void execute() { ResourceUtils.copyResource(new ConcatResource(c), dest == null ? new LogOutputResource(this, Project.MSG_WARN) : dest, - null, null, true, false, append, null, - null, getProject(), force); + null, null, true, false, append, CharSet.getDefault(), + CharSet.getDefault(), getProject(), force); } catch (IOException e) { throw new BuildException("error concatenating content to " + dest, e); } @@ -853,7 +874,7 @@ private void validate() { throw new BuildException( "Nested text is incompatible with binary concatenation"); } - if (encoding != null || outputEncoding != null) { + if (hasCharSet || hasOutputCharSet) { throw new BuildException( "Setting input or output encoding is incompatible with binary concatenation"); } diff --git a/src/main/org/apache/tools/ant/taskdefs/Copy.java b/src/main/org/apache/tools/ant/taskdefs/Copy.java index 013f459860..1a30d9ffec 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Copy.java +++ b/src/main/org/apache/tools/ant/taskdefs/Copy.java @@ -34,6 +34,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.FilterSet; @@ -100,8 +101,9 @@ public class Copy extends Task { //CheckStyle:VisibilityModifier ON private final Vector filterChains = new Vector<>(); private final Vector filterSets = new Vector<>(); - private String inputEncoding = null; - private String outputEncoding = null; + private CharSet inputCharSet = CharSet.getDefault(); + private CharSet outputCharSet = CharSet.getDefault(); + private boolean hasOutputCharSet = false; private long granularity = 0; private boolean force = false; private boolean quiet = false; @@ -380,20 +382,36 @@ public void add(final FileNameMapper fileNameMapper) { * @since 1.32, Ant 1.5 */ public void setEncoding(final String encoding) { - this.inputEncoding = encoding; - if (outputEncoding == null) { - outputEncoding = encoding; - } + setCharSet(new CharSet(encoding)); } /** * Get the character encoding to be used. - * @return the character encoding, null if not set. + * @return the character encoding. * * @since 1.32, Ant 1.5 */ public String getEncoding() { - return inputEncoding; + return inputCharSet.getValue(); + } + + /** + * Set the charset. + * @param charSet the charset. + */ + public void setCharSet(final CharSet charSet) { + this.inputCharSet = charSet; + if (!hasOutputCharSet) { + outputCharSet = charSet; + } + } + + /** + * Get the charset to be used. + * @return the charset. + */ + public CharSet getCharSet() { + return inputCharSet; } /** @@ -402,18 +420,33 @@ public String getEncoding() { * @since Ant 1.6 */ public void setOutputEncoding(final String encoding) { - this.outputEncoding = encoding; + setOutputCharSet(new CharSet(encoding)); } /** * Get the character encoding for output files. - * @return the character encoding for output files, - * null if not set. - * + * @return the character encoding for output files * @since Ant 1.6 */ public String getOutputEncoding() { - return outputEncoding; + return outputCharSet.getValue(); + } + + /** + * Set the charset for output files. + * @param charSet the output CharSet. + */ + public void setOutputCharSet(final CharSet charSet) { + this.outputCharSet = charSet; + hasOutputCharSet = true; + } + + /** + * Get the charset for output files. + * @return the charset for output files, + */ + public CharSet getOutputCharSet() { + return outputCharSet; } /** @@ -883,8 +916,8 @@ protected void doFileOperations() { executionFilters, filterChains, forceOverwrite, preserveLastModified, - /* append: */ false, inputEncoding, - outputEncoding, getProject(), + /* append: */ false, inputCharSet, + outputCharSet, getProject(), getForce()); } catch (final IOException ioe) { String msg = "Failed to copy " + fromFile + " to " + toFile @@ -965,8 +998,8 @@ protected void doResourceOperations(final Map map) { forceOverwrite, preserveLastModified, /* append: */ false, - inputEncoding, - outputEncoding, + inputCharSet, + outputCharSet, getProject(), getForce()); } catch (final IOException ioe) { @@ -1085,7 +1118,7 @@ private String getDueTo(final Exception ex) { message.append(String.format( "%nThis is normally due to the input file containing invalid" + "%nbytes for the character encoding used : %s%n", - inputEncoding == null ? fileUtils.getDefaultEncoding() : inputEncoding)); + inputCharSet.getCharset())); } return message.toString(); } diff --git a/src/main/org/apache/tools/ant/taskdefs/CopyPath.java b/src/main/org/apache/tools/ant/taskdefs/CopyPath.java index 7ea9f1d7d2..837803a237 100644 --- a/src/main/org/apache/tools/ant/taskdefs/CopyPath.java +++ b/src/main/org/apache/tools/ant/taskdefs/CopyPath.java @@ -24,6 +24,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.FileNameMapper; @@ -201,7 +202,7 @@ public void execute() throws BuildException { log("Copying " + sourceFile + " to " + destFile, Project.MSG_VERBOSE); FILE_UTILS.copyFile(sourceFile, destFile, null, null, false, - preserveLastModified, null, null, getProject()); + preserveLastModified, CharSet.getDefault(), CharSet.getDefault(), getProject()); } catch (IOException ioe) { String msg = "Failed to copy " + sourceFile + " to " + destFile + " due to " + ioe.getMessage(); diff --git a/src/main/org/apache/tools/ant/taskdefs/Echo.java b/src/main/org/apache/tools/ant/taskdefs/Echo.java index de659946a9..f58c5c76ca 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Echo.java +++ b/src/main/org/apache/tools/ant/taskdefs/Echo.java @@ -24,6 +24,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.LogLevel; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.resources.FileProvider; @@ -44,8 +45,8 @@ public class Echo extends Task { protected String message = ""; protected File file = null; protected boolean append = false; - /** encoding; set to null or empty means 'default' */ - private String encoding = ""; + /** encoding */ + private CharSet charSet = CharSet.getDefault(); private boolean force = false; // by default, messages are always displayed @@ -64,8 +65,8 @@ public void execute() throws BuildException { ResourceUtils.copyResource( new StringResource(message.isEmpty() ? System.lineSeparator() : message), output == null ? new LogOutputResource(this, logLevel) : output, - null, null, false, false, append, null, - encoding.isEmpty() ? null : encoding, getProject(), force); + null, null, false, false, append, + CharSet.getDefault(), charSet, getProject(), force); } catch (IOException ioe) { throw new BuildException(ioe, getLocation()); } @@ -139,12 +140,20 @@ public void setLevel(EchoLevel echoLevel) { /** * Declare the encoding to use when outputting to a file; - * Use "" for the platform's default encoding. + * Use "" for the platform encoding. * @param encoding the character encoding to use. * @since 1.7 */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Declare the charset to use when outputting to a file; + * @param charSet the charset to use. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/Expand.java b/src/main/org/apache/tools/ant/taskdefs/Expand.java index 19f27fb4b9..3b428fcae4 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Expand.java +++ b/src/main/org/apache/tools/ant/taskdefs/Expand.java @@ -34,6 +34,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.types.PatternSet; @@ -59,8 +60,6 @@ * name="unwar" */ public class Expand extends Task { - public static final String NATIVE_ENCODING = "native-encoding"; - /** Error message when more that one mapper is defined */ public static final String ERROR_MULTIPLE_MAPPERS = "Cannot define more than one mapper"; @@ -79,13 +78,12 @@ public class Expand extends Task { private boolean scanForUnicodeExtraFields = true; private Boolean allowFilesToEscapeDest = null; - private String encoding; + private CharSet charSet = CharSet.getUtf8(); /** * Creates an Expand instance and sets encoding to UTF-8. */ public Expand() { - this("UTF8"); } /** @@ -95,7 +93,16 @@ public Expand() { * @since Ant 1.9.5 */ protected Expand(String encoding) { - this.encoding = encoding; + this.charSet = new CharSet(encoding); + } + + /** + * Creates an Expand instance and sets the given charset. + * + * @param charSet CharSet + */ + protected Expand(CharSet charSet) { + this.charSet = charSet; } /** @@ -182,26 +189,20 @@ protected void expandFile(FileUtils fileUtils, File srcF, File dir) { log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO); FileNameMapper mapper = getMapper(); if (!srcF.exists()) { - throw new BuildException("Unable to expand " - + srcF + throw new BuildException("Unable to expand " + srcF + " as the file does not exist", getLocation()); } - try (ZipFile zf = new ZipFile(srcF, encoding, scanForUnicodeExtraFields)) { + try (ZipFile zf = new ZipFile(srcF, charSet.getCharset(), scanForUnicodeExtraFields)) { boolean empty = true; Enumeration entries = zf.getEntries(); while (entries.hasMoreElements()) { ZipEntry ze = entries.nextElement(); empty = false; - InputStream is = null; log("extracting " + ze.getName(), Project.MSG_DEBUG); - try { - extractFile(fileUtils, srcF, dir, - is = zf.getInputStream(ze), //NOSONAR - ze.getName(), new Date(ze.getTime()), - ze.isDirectory(), mapper); - } finally { - FileUtils.close(is); + try (InputStream is = zf.getInputStream(ze)) { + extractFile(fileUtils, srcF, dir, is, ze.getName(), new Date(ze.getTime()), + ze.isDirectory(), mapper); } } if (empty && getFailOnEmptyArchive()) { @@ -209,8 +210,7 @@ protected void expandFile(FileUtils fileUtils, File srcF, File dir) { } log("expand complete", Project.MSG_VERBOSE); } catch (IOException ioe) { - throw new BuildException( - "Error while expanding " + srcF.getPath() + throw new BuildException("Error while expanding " + srcF.getPath() + "\n" + ioe.toString(), ioe); } @@ -454,12 +454,11 @@ public void add(FileNameMapper fileNameMapper) { createMapper().add(fileNameMapper); } - /** * Sets the encoding to assume for file names and comments. * *

Set to native-encoding if you want your - * platform's native encoding, defaults to UTF8.

+ * platform encoding, defaults to UTF-8.

* @param encoding the name of the character encoding * @since Ant 1.6 */ @@ -467,6 +466,17 @@ public void setEncoding(String encoding) { internalSetEncoding(encoding); } + /** + * Sets the encoding to assume for file names and comments. + * + *

Set to native-encoding if you want your + * platform encoding, defaults to UTF-8.

+ * @param charSet the name of the charset + */ + public void setCharSet(CharSet charSet) { + internalSetCharSet(charSet); + } + /** * Supports grand-children that want to support the attribute * where the child-class doesn't (i.e. Unzip in the compress @@ -476,10 +486,18 @@ public void setEncoding(String encoding) { * @since Ant 1.8.0 */ protected void internalSetEncoding(String encoding) { - if (NATIVE_ENCODING.equals(encoding)) { - encoding = null; - } - this.encoding = encoding; + internalSetCharSet(new CharSet(encoding)); + } + + /** + * Supports grand-children that want to support the attribute + * where the child-class doesn't (i.e. Unzip in the compress + * Antlib). + * + * @param charSet CharSet + */ + protected void internalSetCharSet(CharSet charSet) { + this.charSet = charSet; } /** @@ -487,7 +505,14 @@ protected void internalSetEncoding(String encoding) { * @since Ant 1.8.0 */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * @return String + */ + public CharSet getCharSet() { + return charSet; } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java b/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java index 405234038f..d2b1a1d9d6 100644 --- a/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java +++ b/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java @@ -20,7 +20,6 @@ import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; @@ -34,6 +33,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.filters.ChainableReader; import org.apache.tools.ant.filters.FixCrLfFilter; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.util.FileUtils; @@ -101,13 +101,17 @@ public class FixCRLF extends MatchingTask implements ChainableReader { /** * Encoding to assume for the files */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * Encoding to use for output files */ - private String outputEncoding = null; + private CharSet outputCharSet = CharSet.getDefault(); + /** + * Is output encoding set explicitly? + */ + private boolean hasOutputCharSet = false; /** * Chain this task as a reader. @@ -246,11 +250,11 @@ public void setEof(AddAsisRemove attr) { /** * Specifies the encoding Ant expects the files to be - * in--defaults to the platforms default encoding. + * in--defaults to the platform encoding. * @param encoding String encoding name. */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** @@ -259,7 +263,29 @@ public void setEncoding(String encoding) { * @param outputEncoding String outputEncoding name. */ public void setOutputEncoding(String outputEncoding) { - this.outputEncoding = outputEncoding; + setOutputCharSet(new CharSet(outputEncoding)); + } + + /** + * Specifies the charset Ant expects the files to be + * in--defaults to the platform encoding. + * @param charSet CharSet charset. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; + if (!hasOutputCharSet) { + this.outputCharSet = charSet; + } + } + + /** + * Specifies the charset that the files are + * to be written in--same as input charset by default. + * @param outputCharSet CharSet output charset. + */ + public void setOutputCharSet(CharSet outputCharSet) { + this.outputCharSet = outputCharSet; + hasOutputCharSet = true; } /** @@ -290,15 +316,13 @@ public void execute() throws BuildException { validate(); // log options used - String enc = encoding == null ? "default" : encoding; log("options:" + " eol=" + filter.getEol().getValue() + " tab=" + filter.getTab().getValue() + " eof=" + filter.getEof().getValue() + " tablength=" + filter.getTablength() - + " encoding=" + enc - + " outputencoding=" - + (outputEncoding == null ? enc : outputEncoding), + + " encoding=" + charSet.getValue() + + " outputencoding=" + outputCharSet.getValue(), Project.MSG_VERBOSE); DirectoryScanner ds = super.getDirectoryScanner(srcDir); @@ -357,8 +381,7 @@ private void processFile(String file) throws BuildException { File tmpFile = FILE_UTILS.createTempFile("fixcrlf", "", null, true, true); try { FILE_UTILS.copyFile(srcFile, tmpFile, null, fcv, true, false, - encoding, outputEncoding == null ? encoding : outputEncoding, - getProject()); + charSet, outputCharSet, getProject()); File destFile = new File(destD, file); @@ -420,11 +443,8 @@ public OneLiner(File srcFile) throws BuildException { this.srcFile = srcFile; try { - reader = new BufferedReader( - ((encoding == null) ? new FileReader(srcFile) - : new InputStreamReader( - Files.newInputStream(srcFile.toPath()), encoding)), INBUFLEN); - + reader = new BufferedReader(new InputStreamReader(Files.newInputStream( + srcFile.toPath()), charSet.getCharset()), INBUFLEN); nextLine(); } catch (IOException e) { throw new BuildException(srcFile + ": " + e.getMessage(), diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java index 42f19fbeb7..d1c6f9fd69 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Jar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java @@ -28,7 +28,6 @@ import java.io.PrintWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; @@ -48,6 +47,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Manifest.Section; import org.apache.tools.ant.types.ArchiveFileSet; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; @@ -55,7 +55,6 @@ import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.ZipFileSet; import org.apache.tools.ant.types.spi.Service; -import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.StreamUtils; import org.apache.tools.zip.JarMarker; import org.apache.tools.zip.ZipExtraField; @@ -111,7 +110,7 @@ public class Jar extends Zip { private Manifest manifest; /** The encoding to use when reading in a manifest file */ - private String manifestEncoding; + private CharSet manifestCharSet = CharSet.getUtf8(); /** * The file found from the 'manifest' attribute. This can be @@ -184,7 +183,7 @@ public Jar() { super(); archiveType = "jar"; emptyBehavior = "create"; - setEncoding("UTF8"); + setCharSet(CharSet.getUtf8()); setZip64Mode(Zip64ModeAttribute.NEVER); rootEntries = new Vector<>(); } @@ -270,7 +269,16 @@ public void setIndexMetaInf(boolean flag) { * @param manifestEncoding the character encoding */ public void setManifestEncoding(String manifestEncoding) { - this.manifestEncoding = manifestEncoding; + setManifestCharSet(new CharSet(manifestEncoding)); + } + + /** + * The charset to use in the manifest file. + * + * @param manifestCharSet the charset + */ + public void setManifestCharSet(CharSet manifestCharSet) { + this.manifestCharSet = manifestCharSet; } /** @@ -308,7 +316,7 @@ public void setManifest(File manifestFile) { private Manifest getManifest(File manifestFile) { try (InputStreamReader isr = new InputStreamReader( - Files.newInputStream(manifestFile.toPath()), getManifestCharset())) { + Files.newInputStream(manifestFile.toPath()), manifestCharSet.getCharset())) { return getManifest(isr); } catch (IOException e) { throw new BuildException("Unable to read manifest file: " @@ -541,15 +549,9 @@ private void writeManifest(ZipOutputStream zOut, Manifest manifest) } writer.close(); - ByteArrayInputStream bais = - new ByteArrayInputStream(baos.toByteArray()); - try { - super.zipFile(bais, zOut, MANIFEST_NAME, - System.currentTimeMillis(), null, - ZipFileSet.DEFAULT_FILE_MODE); - } finally { - // not really required - FileUtils.close(bais); + try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) { + super.zipFile(bais, zOut, MANIFEST_NAME, System.currentTimeMillis(), null, + ZipFileSet.DEFAULT_FILE_MODE); } super.initZipOutputStream(zOut); } @@ -678,7 +680,7 @@ private void filesetManifest(File file, InputStream is) throws IOException { manifest = getManifest(file); } else { try (InputStreamReader isr = - new InputStreamReader(is, getManifestCharset())) { + new InputStreamReader(is, manifestCharSet.getCharset())) { manifest = getManifest(isr); } } @@ -694,7 +696,7 @@ private void filesetManifest(File file, InputStream is) throws IOException { newManifest = getManifest(file); } else { try (InputStreamReader isr = - new InputStreamReader(is, getManifestCharset())) { + new InputStreamReader(is, manifestCharSet.getCharset())) { newManifest = getManifest(isr); } } @@ -849,7 +851,7 @@ protected boolean createEmptyZip(File zipFile) throws BuildException { + getDestFile().getAbsolutePath()); try (ZipOutputStream zOut = new ZipOutputStream(getDestFile())) { - zOut.setEncoding(getEncoding()); + zOut.setCharSet(getCharSet()); zOut.setUseZip64(getZip64Mode().getMode()); if (isCompress()) { zOut.setMethod(ZipOutputStream.DEFLATED); @@ -1062,7 +1064,7 @@ protected static String findJarName(String fileName, protected static void grabFilesAndDirs(String file, List dirs, List files) throws IOException { - try (org.apache.tools.zip.ZipFile zf = new org.apache.tools.zip.ZipFile(file, "utf-8")) { + try (org.apache.tools.zip.ZipFile zf = new org.apache.tools.zip.ZipFile(file, Manifest.JAR_CHARSET)) { Set dirSet = new HashSet<>(); StreamUtils.enumerationAsStream(zf.getEntries()).forEach(ze -> { String name = ze.getName(); @@ -1118,20 +1120,6 @@ private Resource[][] grabManifests(ResourceCollection[] rcs) { return manifests; } - private Charset getManifestCharset() { - if (manifestEncoding == null) { - return Charset.defaultCharset(); - } - try { - return Charset.forName(manifestEncoding); - } catch (IllegalArgumentException e) { - throw new BuildException( - "Unsupported encoding while reading manifest: " - + e.getMessage(), - e); - } - } - /** The strict enumerated type. */ public static class StrictMode extends EnumeratedAttribute { /** Public no arg constructor. */ diff --git a/src/main/org/apache/tools/ant/taskdefs/Javac.java b/src/main/org/apache/tools/ant/taskdefs/Javac.java index ad4ce2a4cd..0510c0f3b0 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Javac.java +++ b/src/main/org/apache/tools/ant/taskdefs/Javac.java @@ -37,6 +37,7 @@ import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterExtension; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.FileUtils; @@ -115,7 +116,8 @@ public class Javac extends MatchingTask { private Path upgrademodulepath; private Path compileSourcepath; private Path moduleSourcepath; - private String encoding; + private CharSet charSet = CharSet.getDefault(); + private boolean hasCharSet = false; private boolean debug = false; private boolean optimize = false; private boolean deprecation = false; @@ -687,15 +689,32 @@ public String getMemoryMaximumSize() { * @param encoding the source file encoding */ public void setEncoding(final String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** - * Gets the java source file encoding name. + * Gets the Java source file encoding name. * @return the source file encoding name */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * Set the Java source file charset. + * @param encoding the source file charset + */ + public void setCharSet(final CharSet encoding) { + this.charSet = encoding; + hasCharSet = true; + } + + /** + * Gets the Java source file charset. + * @return the source file charset + */ + public CharSet getCharSet() { + return charSet; } /** @@ -1096,6 +1115,13 @@ public void setCreateMissingPackageInfoClass(final boolean b) { createMissingPackageInfoClass = b; } + /** + * @return boolean whether encoding attribute is set explicitly. + */ + public boolean hasCharSet() { + return hasCharSet; + } + /** * Executes the task. * @exception BuildException if an error occurs diff --git a/src/main/org/apache/tools/ant/taskdefs/Javadoc.java b/src/main/org/apache/tools/ant/taskdefs/Javadoc.java index bca0e0bdcb..bbaf88ea42 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Javadoc.java +++ b/src/main/org/apache/tools/ant/taskdefs/Javadoc.java @@ -49,6 +49,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.DirSet; import org.apache.tools.ant.types.EnumeratedAttribute; @@ -474,7 +475,7 @@ private void addArgIfNotEmpty(final String key, final String value) { private String executable = null; private boolean docFilesSubDirs = false; private String excludeDocFilesSubDir = null; - private String docEncoding = null; + private CharSet docCharSet = CharSet.getDefault(); private boolean postProcessGeneratedJavadocs = true; private final ResourceCollectionContainer nestedSourceFiles @@ -1282,9 +1283,18 @@ public void setHelpfile(final File f) { * @param enc name of the encoding to use. */ public void setDocencoding(final String enc) { + setDocCharSet(new CharSet(enc)); + } + + /** + * Output file charset. + * + * @param charSet charset to use. + */ + public void setDocCharSet(final CharSet charSet) { cmd.createArgument().setValue("-docencoding"); - cmd.createArgument().setValue(enc); - docEncoding = enc; + cmd.createArgument().setValue(charSet.getValue()); + docCharSet = charSet; } /** @@ -1647,7 +1657,15 @@ public String getPackages() { * @param src the name of the charset */ public void setCharset(final String src) { - this.addArgIfNotEmpty("-charset", src); + setCharSet(new CharSet(src)); + } + + /** + * Charset for cross-platform viewing of generated documentation. + * @param cs CharSet + */ + public void setCharSet(final CharSet cs) { + this.addArgIfNotEmpty("-charset", cs.getValue()); } /** @@ -2549,13 +2567,11 @@ private void postProcessGeneratedJavadocs() throws IOException { } private int postProcess(final File file, final String fixData) throws IOException { - final String enc = docEncoding != null ? docEncoding - : FILE_UTILS.getDefaultEncoding(); // we load the whole file as one String (toc/index files are // generally small, because they only contain frameset declaration): String fileContents; try (InputStreamReader reader = - new InputStreamReader(Files.newInputStream(file.toPath()), enc)) { + new InputStreamReader(Files.newInputStream(file.toPath()), docCharSet.getCharset())) { fileContents = fixLineFeeds(FileUtils.safeReadFully(reader)); } @@ -2566,7 +2582,7 @@ private int postProcess(final File file, final String fixData) throws IOExceptio final String patchedFileContents = patchContent(fileContents, fixData); if (!patchedFileContents.equals(fileContents)) { try (final OutputStreamWriter w = - new OutputStreamWriter(Files.newOutputStream(file.toPath()), enc)) { + new OutputStreamWriter(Files.newOutputStream(file.toPath()), docCharSet.getCharset())) { w.write(patchedFileContents); w.close(); return 1; diff --git a/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java b/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java index e46d34a65c..b88f82da97 100644 --- a/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java +++ b/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java @@ -22,7 +22,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Properties; @@ -33,6 +32,7 @@ import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.util.ChainReaderHelper; import org.apache.tools.ant.filters.util.ChainReaderHelper.ChainReader; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; @@ -60,9 +60,9 @@ public class LoadProperties extends Task { private final List filterChains = new Vector<>(); /** - * Encoding to use for input; defaults to the platform's default encoding. + * Encoding to use for input; defaults to the platform encoding. */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * Prefix for loaded properties. @@ -89,18 +89,33 @@ public void setResource(String resource) { } /** - * Encoding to use for input, defaults to the platform's default - * encoding.

+ * Encoding to use for input, defaults to the platform encoding. * + *

* For a list of possible values see * * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html * .

* - * @param encoding The new Encoding value + * @param encoding The new encoding value */ public final void setEncoding(final String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Charset to use for input, defaults to the platform encoding. + * + *

+ * For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html + * .

+ * + * @param charSet The new charset value + */ + public final void setCharSet(final CharSet charSet) { + this.charSet = charSet; } /** @@ -175,11 +190,9 @@ public final void execute() throws BuildException { throw new BuildException("Source resource does not exist: " + src); } - Charset charset = encoding == null ? Charset.defaultCharset() : Charset.forName(encoding); - try (ChainReader instream = new ChainReaderHelper(getProject(), - new InputStreamReader(new BufferedInputStream(src.getInputStream()), charset), filterChains) - .getAssembledReader()) { + new InputStreamReader(new BufferedInputStream(src.getInputStream()), + charSet.getCharset()), filterChains).getAssembledReader()) { String text = instream.readFully(); diff --git a/src/main/org/apache/tools/ant/taskdefs/LoadResource.java b/src/main/org/apache/tools/ant/taskdefs/LoadResource.java index a9e4c629b1..f5e862708f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/LoadResource.java +++ b/src/main/org/apache/tools/ant/taskdefs/LoadResource.java @@ -20,7 +20,6 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.nio.charset.Charset; import java.util.List; import java.util.Vector; import org.apache.tools.ant.BuildException; @@ -28,6 +27,7 @@ import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.util.ChainReaderHelper; import org.apache.tools.ant.filters.util.ChainReaderHelper.ChainReader; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; @@ -56,10 +56,9 @@ public class LoadResource extends Task { private boolean quiet = false; /** - * Encoding to use for filenames, defaults to the platform's default - * encoding. + * Charset to use for filenames, defaults to the platform charset. */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * name of property @@ -72,9 +71,9 @@ public class LoadResource extends Task { private final List filterChains = new Vector<>(); /** - * Encoding to use for input, defaults to the platform's default - * encoding.

+ * Encoding to use for input, defaults to the platform encoding. * + *

* For a list of possible values see * * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html @@ -84,10 +83,26 @@ public class LoadResource extends Task { */ public final void setEncoding(final String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } + /** + * Charset to use for input, defaults to the platform encoding. + * + *

+ * For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html + * .

+ * + * @param charSet The new charset value + */ + + public final void setCharSet(final CharSet charSet) { + this.charSet = charSet; + } + /** * Property name to save to. * @@ -148,8 +163,6 @@ public final void execute() log("loading " + src + " into property " + property, Project.MSG_VERBOSE); - Charset charset = encoding == null ? Charset.defaultCharset() - : Charset.forName(encoding); try { final long len = src.getSize(); log("resource size = " + (len != Resource.UNKNOWN_SIZE @@ -163,7 +176,7 @@ public final void execute() try (ChainReader chainReader = new ChainReaderHelper( getProject(), new InputStreamReader( - new BufferedInputStream(src.getInputStream()), charset), + new BufferedInputStream(src.getInputStream()), charSet.getCharset()), filterChains).with(crh -> { if (src.getSize() != Resource.UNKNOWN_SIZE) { crh.setBufferSize(size); diff --git a/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java b/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java index 2345b3137a..b623a6d4d4 100644 --- a/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java @@ -23,12 +23,12 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.nio.charset.Charset; import java.nio.file.Files; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.util.StreamUtils; @@ -68,7 +68,7 @@ public class ManifestTask extends Task { /** * The encoding of the manifest file */ - private String encoding; + private CharSet charSet = CharSet.getUtf8(); /** * whether to merge Class-Path attributes. @@ -179,7 +179,15 @@ public void setFile(File f) { * @param encoding the manifest file encoding. */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * The charset to use for reading in an existing manifest file + * @param charSet the manifest file charset. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** @@ -227,9 +235,8 @@ public void execute() throws BuildException { BuildException error = null; if (manifestFile.exists()) { - Charset charset = Charset.forName(encoding == null ? "UTF-8" : encoding); try (InputStreamReader isr = new InputStreamReader( - Files.newInputStream(manifestFile.toPath()), charset)) { + Files.newInputStream(manifestFile.toPath()), charSet.getCharset())) { current = new Manifest(isr); } catch (ManifestException m) { error = new BuildException("Existing manifest " + manifestFile diff --git a/src/main/org/apache/tools/ant/taskdefs/Move.java b/src/main/org/apache/tools/ant/taskdefs/Move.java index 7dadc1bbf8..19193316fe 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Move.java +++ b/src/main/org/apache/tools/ant/taskdefs/Move.java @@ -246,8 +246,8 @@ private void copyFile(File fromFile, File toFile, boolean filtering, boolean ove forceOverwrite, getPreserveLastModified(), /* append: */ false, - getEncoding(), - getOutputEncoding(), + getCharSet(), + getOutputCharSet(), getProject(), getForce()); } catch (IOException ioe) { throw new BuildException("Failed to copy " + fromFile + " to " diff --git a/src/main/org/apache/tools/ant/taskdefs/Redirector.java b/src/main/org/apache/tools/ant/taskdefs/Redirector.java index ee91adbd11..323f2e2bd3 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Redirector.java +++ b/src/main/org/apache/tools/ant/taskdefs/Redirector.java @@ -38,6 +38,7 @@ import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.util.ChainReaderHelper; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.util.ConcatFileInputStream; import org.apache.tools.ant.util.FileUtils; @@ -58,9 +59,6 @@ public class Redirector { private static final int STREAMPUMPER_WAIT_INTERVAL = 1000; - private static final String DEFAULT_ENCODING = System - .getProperty("file.encoding"); - private class PropertyOutputStream extends ByteArrayOutputStream { private final String property; @@ -167,14 +165,14 @@ public void close() throws IOException { /** The input filter chains */ private Vector inputFilterChains; - /** The output encoding */ - private String outputEncoding = DEFAULT_ENCODING; + /** The output charset */ + private CharSet outputCharSet = CharSet.getDefault(); - /** The error encoding */ - private String errorEncoding = DEFAULT_ENCODING; + /** The error charset */ + private CharSet errorCharSet = CharSet.getDefault(); - /** The input encoding */ - private String inputEncoding = DEFAULT_ENCODING; + /** The input charset */ + private CharSet inputCharSet = CharSet.getDefault(); /** Whether to complete properties settings **/ private boolean appendProperties = true; @@ -316,13 +314,7 @@ public void setOutput(final File[] out) { * String. */ public void setOutputEncoding(final String outputEncoding) { - if (outputEncoding == null) { - throw new IllegalArgumentException( - "outputEncoding must not be null"); - } - synchronized (outMutex) { - this.outputEncoding = outputEncoding; - } + setOutputCharSet(new CharSet(outputEncoding)); } /** @@ -332,12 +324,7 @@ public void setOutputEncoding(final String outputEncoding) { * String. */ public void setErrorEncoding(final String errorEncoding) { - if (errorEncoding == null) { - throw new IllegalArgumentException("errorEncoding must not be null"); - } - synchronized (errMutex) { - this.errorEncoding = errorEncoding; - } + setErrorCharSet(new CharSet(errorEncoding)); } /** @@ -347,11 +334,42 @@ public void setErrorEncoding(final String errorEncoding) { * String. */ public void setInputEncoding(final String inputEncoding) { - if (inputEncoding == null) { - throw new IllegalArgumentException("inputEncoding must not be null"); + setInputCharSet(new CharSet(inputEncoding)); + } + + /** + * Set the output charset. + * + * @param outputCharSet + * CharSet. + */ + public void setOutputCharSet(final CharSet outputCharSet) { + synchronized (outMutex) { + this.outputCharSet = outputCharSet; } + } + + /** + * Set the error charset. + * + * @param errorCharSet + * CharSet. + */ + public void setErrorCharSet(final CharSet errorCharSet) { + synchronized (errMutex) { + this.errorCharSet = errorCharSet; + } + } + + /** + * Set the input charset. + * + * @param inputCharSet + * CharSet. + */ + public void setInputCharSet(final CharSet inputCharSet) { synchronized (inMutex) { - this.inputEncoding = inputEncoding; + this.inputCharSet = inputCharSet; } } @@ -573,7 +591,7 @@ public void createStreams() { } if ((outputFilterChains != null && outputFilterChains.size() > 0) - || !outputEncoding.equalsIgnoreCase(inputEncoding)) { + || !outputCharSet.equivalent(inputCharSet)) { try { final LeadPipeInputStream snk = new LeadPipeInputStream(); snk.setManagingComponent(managingTask); @@ -581,7 +599,7 @@ public void createStreams() { InputStream outPumpIn = snk; Reader reader = new InputStreamReader(outPumpIn, - inputEncoding); + inputCharSet.getCharset()); if (outputFilterChains != null && outputFilterChains.size() > 0) { @@ -591,7 +609,7 @@ public void createStreams() { helper.setFilterChains(outputFilterChains); reader = helper.getAssembledReader(); } - outPumpIn = new ReaderInputStream(reader, outputEncoding); + outPumpIn = new ReaderInputStream(reader, outputCharSet.getCharset()); final Thread t = new Thread(threadGroup, new StreamPumper( outPumpIn, outputStream, true), "output pumper"); @@ -615,7 +633,7 @@ public void createStreams() { } if ((errorFilterChains != null && errorFilterChains.size() > 0) - || !errorEncoding.equalsIgnoreCase(inputEncoding)) { + || !errorCharSet.equivalent(inputCharSet)) { try { final LeadPipeInputStream snk = new LeadPipeInputStream(); snk.setManagingComponent(managingTask); @@ -623,7 +641,7 @@ public void createStreams() { InputStream errPumpIn = snk; Reader reader = new InputStreamReader(errPumpIn, - inputEncoding); + inputCharSet.getCharset()); if (errorFilterChains != null && errorFilterChains.size() > 0) { @@ -633,7 +651,7 @@ public void createStreams() { helper.setFilterChains(errorFilterChains); reader = helper.getAssembledReader(); } - errPumpIn = new ReaderInputStream(reader, errorEncoding); + errPumpIn = new ReaderInputStream(reader, errorCharSet.getCharset()); final Thread t = new Thread(threadGroup, new StreamPumper( errPumpIn, errorStream, true), "error pumper"); @@ -678,16 +696,11 @@ public void createStreams() { && inputFilterChains.size() > 0) { final ChainReaderHelper helper = new ChainReaderHelper(); helper.setProject(managingTask.getProject()); - try { - helper.setPrimaryReader(new InputStreamReader(inputStream, - inputEncoding)); - } catch (final IOException eyeOhEx) { - throw new BuildException("error setting up input stream", - eyeOhEx); - } + helper.setPrimaryReader(new InputStreamReader(inputStream, + inputCharSet.getCharset())); helper.setFilterChains(inputFilterChains); - inputStream = new ReaderInputStream( - helper.getAssembledReader(), inputEncoding); + inputStream = new ReaderInputStream(helper.getAssembledReader(), + inputCharSet.getCharset()); } } } diff --git a/src/main/org/apache/tools/ant/taskdefs/Replace.java b/src/main/org/apache/tools/ant/taskdefs/Replace.java index 05d4767a80..38c43cf978 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Replace.java +++ b/src/main/org/apache/tools/ant/taskdefs/Replace.java @@ -38,6 +38,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.FileProvider; @@ -77,7 +78,7 @@ public class Replace extends MatchingTask { private boolean summary = false; /** The encoding used to read and write files - if null, uses default */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); private Union resources; @@ -367,9 +368,7 @@ private class FileInput implements AutoCloseable { buffer = new char[BUFF_SIZE]; is = Files.newInputStream(source.toPath()); try { - reader = new BufferedReader( - encoding != null ? new InputStreamReader(is, encoding) - : new InputStreamReader(is)); + reader = new BufferedReader(new InputStreamReader(is, charSet.getCharset())); } finally { if (reader == null) { is.close(); @@ -429,9 +428,7 @@ private class FileOutput implements AutoCloseable { FileOutput(File out) throws IOException { os = Files.newOutputStream(out.toPath()); try { - writer = new BufferedWriter( - encoding != null ? new OutputStreamWriter(os, encoding) - : new OutputStreamWriter(os)); + writer = new BufferedWriter(new OutputStreamWriter(os, charSet.getCharset())); } finally { if (writer == null) { os.close(); @@ -803,12 +800,22 @@ public void setValue(String value) { /** * Set the file encoding to use on the files read and written by the task; - * optional, defaults to default JVM encoding. + * optional, defaults to platform encoding. * * @param encoding the encoding to use on the files. */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Set the charset to use on the files read and written by the task; + * optional, defaults to platform encoding. + * + * @param charSet the charset to use on the files. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/SQLExec.java b/src/main/org/apache/tools/ant/taskdefs/SQLExec.java index dc116a3438..7801756ab3 100644 --- a/src/main/org/apache/tools/ant/taskdefs/SQLExec.java +++ b/src/main/org/apache/tools/ant/taskdefs/SQLExec.java @@ -26,7 +26,6 @@ import java.io.PrintStream; import java.io.Reader; import java.io.StringReader; -import java.nio.charset.Charset; import java.sql.Blob; import java.sql.Connection; import java.sql.ResultSet; @@ -42,6 +41,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; @@ -163,7 +163,7 @@ public String[] getValues() { /** * Output encoding. */ - private String outputEncoding = null; + private CharSet outputCharSet = CharSet.getDefault(); /** * Action to perform if an error is found @@ -173,7 +173,7 @@ public String[] getValues() { /** * Encoding to use when reading SQL statements from a file */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * Append to an existing file or overwrite it? @@ -361,7 +361,16 @@ public Transaction createTransaction() { * @param encoding the encoding to use on the files */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Set the charset to use on the SQL files read in + * + * @param charSet the encoding to use on the files + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** @@ -438,13 +447,22 @@ public void setOutput(Resource output) { /** * The encoding to use when writing the result to a resource. - *

Default's to the platform's default encoding

- * @param outputEncoding the name of the encoding or null for the - * platform's default encoding + *

Defaults to the platform encoding

+ * @param outputEncoding the name of the encoding or "" for the + * platform encoding * @since Ant 1.9.4 */ public void setOutputEncoding(String outputEncoding) { - this.outputEncoding = outputEncoding; + setOutputCharSet(new CharSet(outputEncoding)); + } + + /** + * The charset to use when writing the result to a resource. + *

Defaults to the platform encoding

+ * @param outputCharSet the CharSet + */ + public void setOutputCharSet(CharSet outputCharSet) { + this.outputCharSet = outputCharSet; } /** @@ -678,12 +696,8 @@ public void execute() throws BuildException { } } } - if (outputEncoding != null) { - out = new PrintStream(new BufferedOutputStream(os), - false, outputEncoding); - } else { - out = new PrintStream(new BufferedOutputStream(os)); - } + out = new PrintStream(new BufferedOutputStream(os), + false, outputCharSet.getValue()); } // Process all transactions @@ -1057,10 +1071,8 @@ private void runTransaction(PrintStream out) if (tSrcResource != null) { log("Executing resource: " + tSrcResource.toString(), Project.MSG_INFO); - Charset charset = encoding == null ? Charset.defaultCharset() - : Charset.forName(encoding); - try (Reader reader = new InputStreamReader( - tSrcResource.getInputStream(), charset)) { + try (Reader reader = new InputStreamReader(tSrcResource.getInputStream(), + charSet.getCharset())) { runStatements(reader, out); } } diff --git a/src/main/org/apache/tools/ant/taskdefs/Tar.java b/src/main/org/apache/tools/ant/taskdefs/Tar.java index 1c56a661a3..7aba4410e7 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Tar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Tar.java @@ -39,6 +39,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.ArchiveFileSet; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; @@ -125,10 +126,9 @@ public class Tar extends MatchingTask { private TarCompressionMethod compression = new TarCompressionMethod(); /** - * Encoding to use for filenames, defaults to the platform's - * default encoding. + * Encoding to use for filenames, defaults to the platform encoding. */ - private String encoding; + private CharSet charSet = CharSet.getDefault(); /** * Add a new fileset with the option to specify permissions @@ -239,8 +239,7 @@ public void setCompression(final TarCompressionMethod mode) { } /** - * Encoding to use for filenames, defaults to the platform's - * default encoding. + * Encoding to use for filenames, defaults to the platform encoding. * *

For a list of possible values see https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.

@@ -249,7 +248,20 @@ public void setCompression(final TarCompressionMethod mode) { * @since Ant 1.9.5 */ public void setEncoding(final String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Charset to use for filenames, defaults to the platform charset. + * + *

For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html + * .

+ * @param charSet the charset + */ + public void setCharSet(final CharSet charSet) { + this.charSet = charSet; } /** @@ -320,9 +332,8 @@ public void execute() throws BuildException { log("Building tar: " + tarFile.getAbsolutePath(), Project.MSG_INFO); try (TarOutputStream tOut = new TarOutputStream( - compression.compress(new BufferedOutputStream( - Files.newOutputStream(tarFile.toPath()))), - encoding)) { + compression.compress(new BufferedOutputStream(Files.newOutputStream(tarFile.toPath()))), + charSet)) { tOut.setDebug(true); if (longFileMode.isTruncateMode()) { tOut.setLongFileMode(TarOutputStream.LONGFILE_TRUNCATE); diff --git a/src/main/org/apache/tools/ant/taskdefs/Untar.java b/src/main/org/apache/tools/ant/taskdefs/Untar.java index c1bcb3061e..0fbcf8c277 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Untar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Untar.java @@ -29,6 +29,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.util.FileNameMapper; @@ -59,7 +60,7 @@ public class Untar extends Expand { private UntarCompressionMethod compression = new UntarCompressionMethod(); public Untar() { - super(null); + super(CharSet.getDefault()); } /** @@ -144,7 +145,7 @@ private void expandStream(String name, InputStream stream, File dir) throws IOException { try (TarInputStream tis = new TarInputStream( compression.decompress(name, new BufferedInputStream(stream)), - getEncoding())) { + getCharSet())) { log("Expanding: " + name + " into " + dir, Project.MSG_INFO); boolean empty = true; FileNameMapper mapper = getMapper(); diff --git a/src/main/org/apache/tools/ant/taskdefs/Zip.java b/src/main/org/apache/tools/ant/taskdefs/Zip.java index b545cb83e8..e02590e0f4 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Zip.java +++ b/src/main/org/apache/tools/ant/taskdefs/Zip.java @@ -41,6 +41,7 @@ import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.ArchiveFileSet; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; @@ -162,10 +163,9 @@ protected final boolean isFirstPass() { private boolean addingNewFiles = false; /** - * Encoding to use for filenames, defaults to the platform's - * default encoding. + * Encoding to use for filenames, defaults to the platform encoding. */ - private String encoding; + private CharSet charSet = CharSet.getDefault(); /** * Whether the original compression of entries coming from a ZIP @@ -404,15 +404,14 @@ public void setWhenempty(final WhenEmpty we) { } /** - * Encoding to use for filenames, defaults to the platform's - * default encoding. + * Encoding to use for filenames, defaults to the platform encoding. * *

For a list of possible values see https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.

* @param encoding the encoding name */ public void setEncoding(final String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** @@ -421,7 +420,28 @@ public void setEncoding(final String encoding) { * @since Ant 1.5.2 */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * charset to use for filenames, defaults to the platform charset. + * + *

For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html + * .

+ * @param charSet the charset + */ + public void setCharSet(final CharSet charSet) { + this.charSet = charSet; + } + + /** + * Encoding to use for filenames. + * @return the name of the encoding to use + */ + public CharSet getCharSet() { + return charSet; } /** @@ -707,7 +727,7 @@ public void executeMain() throws BuildException { if (!skipWriting) { zOut = new ZipOutputStream(zipFile); - zOut.setEncoding(encoding); + zOut.setCharSet(charSet); zOut.setUseLanguageEncodingFlag(useLanguageEncodingFlag); zOut.setCreateUnicodeExtraFields(createUnicodeExtraFields. getPolicy()); @@ -738,7 +758,7 @@ public void executeMain() throws BuildException { } final DirectoryScanner ds = oldFiles.getDirectoryScanner(getProject()); - ((ZipScanner) ds).setEncoding(encoding); + ((ZipScanner) ds).setCharSet(charSet); Stream includedResourceNames = Stream.of(ds.getIncludedFiles()); @@ -962,7 +982,7 @@ protected final void addResources(final FileSet fileset, final Resource[] resour dealingWithFiles = true; base = fileset.getDir(getProject()); } else if (zfs instanceof ZipFileSet) { - zf = new ZipFile(zfs.getSrc(getProject()), encoding); + zf = new ZipFile(zfs.getSrc(getProject()), charSet.getCharset()); } for (Resource resource : resources) { @@ -1209,7 +1229,7 @@ protected boolean createEmptyZip(final File zipFile) throws BuildException { private synchronized ZipScanner getZipScanner() { if (zs == null) { zs = new ZipScanner(); - zs.setEncoding(encoding); + zs.setCharSet(charSet); zs.setSrc(zipFile); } return zs; @@ -1589,7 +1609,7 @@ protected Resource[][] grabResources(final FileSet[] filesets) { final DirectoryScanner rs = filesets[i].getDirectoryScanner(getProject()); if (rs instanceof ZipScanner) { - ((ZipScanner) rs).setEncoding(encoding); + ((ZipScanner) rs).setCharSet(charSet); } final List resources = new Vector<>(); if (!doFilesonly) { @@ -1988,7 +2008,7 @@ public void reset() { emptyBehavior = "skip"; doUpdate = false; doFilesonly = false; - encoding = null; + charSet = CharSet.getDefault(); } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java b/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java index ec2d9d8863..b3d3990819 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java @@ -33,6 +33,7 @@ import org.apache.tools.ant.taskdefs.Javac; import org.apache.tools.ant.taskdefs.LogStreamHandler; import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.util.FileUtils; @@ -69,7 +70,8 @@ public abstract class DefaultCompilerAdapter protected Path src; protected File destDir; - protected String encoding; + protected CharSet charSet = CharSet.getDefault(); + private boolean hasCharSet = false; protected boolean debug = false; protected boolean optimize = false; protected boolean deprecation = false; @@ -107,7 +109,8 @@ public void setJavac(final Javac attributes) { this.attributes = attributes; src = attributes.getSrcdir(); destDir = attributes.getDestdir(); - encoding = attributes.getEncoding(); + charSet = attributes.getCharSet(); + hasCharSet = attributes.hasCharSet(); debug = attributes.getDebug(); optimize = attributes.getOptimize(); deprecation = attributes.getDeprecation(); @@ -342,9 +345,9 @@ protected Commandline setupJavacCommandlineSwitches(final Commandline cmd, } } - if (encoding != null) { + if (hasCharSet) { cmd.createArgument().setValue("-encoding"); - cmd.createArgument().setValue(encoding); + cmd.createArgument().setValue(charSet.getValue()); } if (debug) { if (useDebugLevel && assumeJava1_2Plus()) { @@ -865,6 +868,10 @@ protected String getNoDebugArgument() { return assumeJava1_2Plus() ? "-g:none" : null; } + protected boolean hasCharset() { + return hasCharSet; + } + private void setImplicitSourceSwitch(final Commandline cmd, final String target, final String source) { attributes.log("", Project.MSG_WARN); diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java b/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java index 0d482862c4..5c86244643 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java @@ -98,8 +98,8 @@ protected Commandline setupGCJCommand() { cmd.createArgument().setValue("-classpath"); cmd.createArgument().setPath(classpath); - if (encoding != null) { - cmd.createArgument().setValue("--encoding=" + encoding); + if (hasCharset()) { + cmd.createArgument().setValue("--encoding=" + charSet.getValue()); } if (debug) { cmd.createArgument().setValue("-g1"); diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java b/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java index e6b5c37e1b..51db4ae3ce 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java @@ -103,9 +103,9 @@ public boolean execute() throws BuildException { cmd.createArgument().setValue("-classpath"); cmd.createArgument().setPath(classpath); - if (encoding != null) { + if (hasCharset()) { cmd.createArgument().setValue("-encoding"); - cmd.createArgument().setValue(encoding); + cmd.createArgument().setValue(charSet.getValue()); } if (debug) { String debugLevel = attributes.getDebugLevel(); diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java b/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java index eaaddafd14..41fc4e18c6 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java @@ -93,9 +93,9 @@ protected Commandline setupKjcCommand() { // kjc-1.5A doesn't support -encoding option now. // but it will be supported near the feature. - if (encoding != null) { + if (hasCharset()) { cmd.createArgument().setValue("-encoding"); - cmd.createArgument().setValue(encoding); + cmd.createArgument().setValue(charSet.getValue()); } if (debug) { diff --git a/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java b/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java index 54f811743c..7cd4fc709d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java @@ -23,6 +23,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; @@ -77,7 +78,7 @@ public String[] getValues() { private boolean failOnError = true; private boolean includeFileNames = false; private String messageMimeType = null; - private String messageFileInputEncoding; + private CharSet messageFileInputCharSet = CharSet.getDefault(); /* special headers */ /** sender */ private EmailAddress from = null; @@ -95,8 +96,10 @@ public String[] getValues() { /** file list */ private Path attachments = null; - /** Character set for MimeMailer*/ - private String charset = null; + /** Character set for MimeMailer */ + private CharSet charSet = CharSet.getDefault(); + /** Is character set defined explicitly */ + private boolean hasCharSet = false; /** User for SMTP auth */ private String user = null; /** Password for SMTP auth */ @@ -525,15 +528,14 @@ public void execute() { } message.setMimeType(messageMimeType); } - // set the character set if not done already (and required) - if (charset != null) { - if (message.getCharset() != null) { - throw new BuildException( - "The charset can only be specified in one location"); - } - message.setCharset(charset); + if (message.hasCharSet() && hasCharSet) { + throw new BuildException("The charset can only be specified in one location"); + } + // set the character set of message unless equivalent + if (!charSet.equivalent(message.getCharSet())) { + message.setCharSet(charSet); } - message.setInputEncoding(messageFileInputEncoding); + message.setInputCharSet(messageFileInputCharSet); // identify which files should be attached Vector files = new Vector<>(); @@ -613,7 +615,7 @@ private void logBuildException(String reason, BuildException e) { * @since Ant 1.6 */ public void setCharset(String charset) { - this.charset = charset; + setCharSet(new CharSet(charset)); } /** @@ -623,17 +625,46 @@ public void setCharset(String charset) { * @since Ant 1.6 */ public String getCharset() { - return charset; + return charSet.getValue(); + } + + /** + * Sets the character set of mail message. + * Will be ignored if mimeType contains ....; Charset=... substring or + * encoding is not mime. + * @param charSet the charset to use. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; + hasCharSet = true; + } + + /** + * Returns the character set of mail message. + * + * @return Charset of mail message. + */ + public CharSet getCharSet() { + return charSet; } /** * Sets the encoding to expect when reading the message from a file. *

Will be ignored if the message has been specified inline.

- * @param encoding the name of the charset used + * @param encoding the name of the encoding used * @since Ant 1.9.4 */ public void setMessageFileInputEncoding(String encoding) { - messageFileInputEncoding = encoding; + setMessageFileInputCharSet(new CharSet(encoding)); + } + + /** + * Sets the charset to expect when reading the message from a file. + *

Will be ignored if the message has been specified inline.

+ * @param charSet the name of the charset used + */ + public void setMessageFileInputCharSet(CharSet charSet) { + messageFileInputCharSet = charSet; } } diff --git a/src/main/org/apache/tools/ant/taskdefs/email/Message.java b/src/main/org/apache/tools/ant/taskdefs/email/Message.java index 477c736765..34287831cf 100644 --- a/src/main/org/apache/tools/ant/taskdefs/email/Message.java +++ b/src/main/org/apache/tools/ant/taskdefs/email/Message.java @@ -20,9 +20,7 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintStream; @@ -30,6 +28,7 @@ import java.nio.file.Files; import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.types.CharSet; /** * Class representing an email message. @@ -41,8 +40,9 @@ public class Message extends ProjectComponent { private StringBuffer buffer = new StringBuffer(); private String mimeType = "text/plain"; private boolean specified = false; - private String charset = null; - private String inputEncoding; + private CharSet charSet = CharSet.getDefault(); + private boolean hasCharSet = false; + private CharSet inputCharSet = CharSet.getDefault(); /** Creates a new empty message */ public Message() { @@ -115,8 +115,7 @@ public void print(PrintStream ps) throws IOException { // So, using BufferedWriter over OutputStreamWriter instead of PrintStream BufferedWriter out = null; try { - out = charset == null ? new BufferedWriter(new OutputStreamWriter(ps)) - : new BufferedWriter(new OutputStreamWriter(ps, charset)); + out = new BufferedWriter(new OutputStreamWriter(ps, charSet.getCharset())); if (messageSource != null) { // Read message from a file try (BufferedReader in = new BufferedReader(getReader(messageSource))) { @@ -152,39 +151,65 @@ public boolean isMimeTypeSpecified() { * @since Ant 1.6 */ public void setCharset(String charset) { - this.charset = charset; + setCharSet(new CharSet(charset)); } /** * Returns the charset of mail message. * - * @return Charset of mail message. + * @return charset of mail message. * @since Ant 1.6 */ public String getCharset() { - return charset; + return charSet.getValue(); } /** - * Sets the encoding to expect when reading the message from a file. + * Sets the CharSet of mail message. + * Will be ignored if mimeType contains ....; Charset=... substring. + * @param charSet the CharSet. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; + hasCharSet = true; + } + + /** + * Returns the CharSet of mail message. + * + * @return CharSet of mail message. + */ + public CharSet getCharSet() { + return charSet; + } + + /** + * Sets the character encoding to expect when reading the message from a file. *

Will be ignored if the message has been specified inline.

- * @param encoding the name of the charset used + * @param encoding the name of the character encoding used * @since Ant 1.9.4 */ public void setInputEncoding(String encoding) { - this.inputEncoding = encoding; + setInputCharSet(new CharSet(encoding)); + } + + /** + * Sets the charset to expect when reading the message from a file. + *

Will be ignored if the message has been specified inline.

+ * @param charSet the charset used + */ + public void setInputCharSet(CharSet charSet) { + this.inputCharSet = charSet; + } + + /** + * @return true if charset attribute is set explicitly + */ + public boolean hasCharSet() { + return hasCharSet; } private Reader getReader(File f) throws IOException { - if (inputEncoding != null) { - InputStream fis = Files.newInputStream(f.toPath()); - try { - return new InputStreamReader(fis, inputEncoding); - } catch (IOException ex) { - fis.close(); - throw ex; - } - } - return new FileReader(f); + return new InputStreamReader(Files.newInputStream(f.toPath()), inputCharSet.getCharset()); } } diff --git a/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java b/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java index e052e7a1be..f416547a3e 100644 --- a/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java +++ b/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java @@ -52,6 +52,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; /** @@ -65,10 +66,6 @@ public class MimeMailer extends Mailer { private static final String GENERIC_ERROR = "Problem while sending mime mail:"; - /** Default character set */ - private static final String DEFAULT_CHARSET - = System.getProperty("file.encoding"); - // To work properly with national charsets we have to use // implementation of interface javax.activation.DataSource /** @@ -78,7 +75,7 @@ public class MimeMailer extends Mailer { class StringDataSource implements javax.activation.DataSource { private String data = null; private String type = null; - private String charset = null; + private CharSet charSet = CharSet.getDefault(); private ByteArrayOutputStream out; @Override @@ -87,11 +84,11 @@ public InputStream getInputStream() throws IOException { throw new IOException("No data"); } if (out != null) { - final String encodedOut = out.toString(charset); + final String encodedOut = out.toString(charSet.getValue()); data = (data != null) ? data.concat(encodedOut) : encodedOut; out = null; } - return new ByteArrayInputStream(data.getBytes(charset)); + return new ByteArrayInputStream(data.getBytes(charSet.getCharset())); } @Override @@ -112,7 +109,7 @@ public String getContentType() { } // Must be like "text/plain; charset=windows-1251" return (type != null ? type : "text/plain") + - "; charset=" + charset; + "; charset=" + charSet.getValue(); } @Override @@ -121,11 +118,19 @@ public String getName() { } public void setCharset(final String charset) { - this.charset = charset; + setCharSet(new CharSet(charset)); } public String getCharset() { - return charset; + return charSet.getValue(); + } + + public void setCharSet(final CharSet charSet) { + this.charSet = charSet; + } + + public CharSet getCharSet() { + return charSet; } } @@ -198,26 +203,21 @@ public void send() { // Choosing character set of the mail message // First: looking it from MimeType - String charset = parseCharSetFromMimeType(message.getMimeType()); - if (charset != null) { - // Assign/reassign message charset from MimeType - message.setCharset(charset); + CharSet charSet = parseCharSetFromMimeType(message.getMimeType()); + if (charSet == null) { + // get charset from message + charSet = message.getCharSet(); } else { - // Next: looking if charset having explicit definition - charset = message.getCharset(); - if (charset == null) { - // Using default - charset = DEFAULT_CHARSET; - message.setCharset(charset); - } + // Assign/reassign message charset from MimeType + message.setCharSet(charSet); } // Using javax.activation.DataSource paradigm final StringDataSource sds = new StringDataSource(); sds.setContentType(message.getMimeType()); - sds.setCharset(charset); + sds.setCharSet(charSet); if (subject != null) { - msg.setSubject(subject, charset); + msg.setSubject(subject, charSet.getValue()); } msg.addHeader("Date", getDate()); @@ -297,7 +297,7 @@ private static InternetAddress[] internetAddresses(final Vector li return addrs.toArray(new InternetAddress[addrs.size()]); } - private String parseCharSetFromMimeType(final String type) { + private CharSet parseCharSetFromMimeType(final String type) { if (type == null) { return null; } @@ -308,7 +308,7 @@ private String parseCharSetFromMimeType(final String type) { // Assuming mime type in form "text/XXXX; charset=XXXXXX" final StringTokenizer token = new StringTokenizer(type.substring(pos), "=; "); token.nextToken(); // Skip 'charset=' - return token.nextToken(); + return new CharSet(token.nextToken()); } private void didntReach(final Address addr, final String category, diff --git a/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java b/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java index 806102ca42..664827d35b 100644 --- a/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java +++ b/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java @@ -83,12 +83,8 @@ public void send() { mailMessage.setSubject(subject); } mailMessage.setHeader("Date", getDate()); - if (message.getCharset() != null) { - mailMessage.setHeader("Content-Type", message.getMimeType() + mailMessage.setHeader("Content-Type", message.getMimeType() + "; charset=\"" + message.getCharset() + "\""); - } else { - mailMessage.setHeader("Content-Type", message.getMimeType()); - } if (headers != null) { for (Header h : headers) { mailMessage.setHeader(h.getName(), h.getValue()); diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java b/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java index ad7b1bf96f..5a3d2fb15f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java @@ -26,6 +26,7 @@ import org.apache.tools.ant.taskdefs.MatchingTask; import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapter; import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapterFactory; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.util.FileNameMapper; @@ -42,7 +43,7 @@ public class Native2Ascii extends MatchingTask { private boolean reverse = false; // convert from ascii back to native - private String encoding = null; // encoding to convert to/from + private CharSet charSet = CharSet.getDefault(); // encoding to convert to/from private File srcDir = null; // Where to find input files private File destDir = null; // Where to put output files private String extension = null; // Extension of output files if different @@ -79,13 +80,13 @@ public boolean getReverse() { /** * Set the encoding to translate to/from. - * If unset, the default encoding for the JVM is used. + * If unset, the platform encoding is used. * * @param encoding String containing the name of the Native * encoding to convert from or to. */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** @@ -95,7 +96,26 @@ public void setEncoding(String encoding) { * @since Ant 1.6.3 */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * Set the charset to translate to/from. + * If unset, the platform charset is used. + * + * @param charSet CharSet of native encoding to convert from or to. + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; + } + + /** + * The value of the charset attribute. + * + * @return the charset attribute. + */ + public CharSet getCharSet() { + return charSet; } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java b/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java index 7ed0404b46..daa2bdb873 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java @@ -27,12 +27,12 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; -import java.nio.charset.Charset; import java.nio.file.Files; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.RegularExpression; import org.apache.tools.ant.types.Resource; @@ -131,7 +131,7 @@ public class ReplaceRegExp extends Task { /** * Encoding to assume for the files */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** Default Constructor */ public ReplaceRegExp() { @@ -238,13 +238,23 @@ public void setByLine(boolean byline) { /** * Specifies the encoding Ant expects the files to be in - - * defaults to the platforms default encoding. + * defaults to the platform encoding. * * @param encoding the encoding attribute * @since Ant 1.6 */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Specifies the charset Ant expects the files to be in - + * defaults to the platform charset. + * + * @param charSet the charset attribute + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** @@ -354,14 +364,13 @@ protected void doReplace(File f, int options) try { boolean changes = false; - final Charset charset = encoding == null ? Charset.defaultCharset() : Charset.forName(encoding); try (InputStream is = Files.newInputStream(f.toPath()); OutputStream os = Files.newOutputStream(temp.toPath())) { Reader r = null; Writer w = null; try { - r = new InputStreamReader(is, charset); - w = new OutputStreamWriter(os, charset); + r = new InputStreamReader(is, charSet.getCharset()); + w = new OutputStreamWriter(os, charSet.getCharset()); log("Replacing pattern '" + regex.getPattern(getProject()) + "' with '" + subs.getExpression(getProject()) + "' in '" + f.getPath() + "'" + (byline ? " by line" : "") diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/Script.java b/src/main/org/apache/tools/ant/taskdefs/optional/Script.java index 416a8f8d07..2cf71aba15 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/Script.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/Script.java @@ -22,6 +22,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.ScriptRunnerHelper; @@ -138,7 +139,16 @@ public void setSetBeans(boolean setBeans) { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - helper.setEncoding(encoding); + helper.setCharSet(new CharSet(encoding)); + } + + /** + * Set the encoding of the script from an external file; optional. + * + * @param charSet the encoding of the file containing the script source. + */ + public void setCharSet(CharSet charSet) { + helper.setCharSet(charSet); } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java b/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java index f84aebe9cb..abf0b6996b 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java @@ -35,6 +35,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.LineTokenizer; @@ -108,17 +109,17 @@ public class Translate extends MatchingTask { /** * Source file encoding scheme */ - private String srcEncoding; + private CharSet srcCharSet = CharSet.getDefault(); /** * Destination file encoding scheme */ - private String destEncoding; + private CharSet destCharSet = CharSet.getDefault(); /** * Resource Bundle file encoding scheme, defaults to srcEncoding */ - private String bundleEncoding; + private CharSet bundleCharSet = CharSet.getDefault(); /** * Starting token to identify keys @@ -171,6 +172,10 @@ public class Translate extends MatchingTask { */ private boolean loaded = false; + private boolean hasDestCharSet = false; + + private boolean hasBundleCharSet = false; + /** * Sets Family name of resource bundle; required. * @param bundle family name of resource bundle @@ -229,11 +234,11 @@ public void setEndToken(String endToken) { /** * Sets source file encoding scheme; optional, - * defaults to encoding of local system. + * defaults to platform encoding. * @param srcEncoding source file encoding */ public void setSrcEncoding(String srcEncoding) { - this.srcEncoding = srcEncoding; + setSrcCharSet(new CharSet(srcEncoding)); } /** @@ -242,7 +247,7 @@ public void setSrcEncoding(String srcEncoding) { * @param destEncoding destination file encoding scheme */ public void setDestEncoding(String destEncoding) { - this.destEncoding = destEncoding; + setDestCharSet(new CharSet(destEncoding)); } /** @@ -251,7 +256,36 @@ public void setDestEncoding(String destEncoding) { * @param bundleEncoding bundle file encoding scheme */ public void setBundleEncoding(String bundleEncoding) { - this.bundleEncoding = bundleEncoding; + setBundleCharSet(new CharSet(bundleEncoding)); + } + + /** + * Sets source file charset; optional, + * defaults to platform encoding. + * @param srcCharSet source file charset + */ + public void setSrcCharSet(CharSet srcCharSet) { + this.srcCharSet = srcCharSet; + } + + /** + * Sets destination file charset; optional. Defaults to source file + * charset + * @param destCharSet destination file charset + */ + public void setDestCharSet(CharSet destCharSet) { + this.destCharSet = destCharSet; + hasDestCharSet = true; + } + + /** + * Sets Resource Bundle file charset; optional. Defaults to source file + * charset + * @param bundleCharSet bundle file encoding scheme + */ + public void setBundleCharSet(CharSet bundleCharSet) { + this.bundleCharSet = bundleCharSet; + hasBundleCharSet = true; } /** @@ -324,16 +358,12 @@ public void execute() throws BuildException { throw new BuildException("%s is not a directory", toDir); } - if (srcEncoding == null) { - srcEncoding = System.getProperty("file.encoding"); - } - - if (destEncoding == null) { - destEncoding = srcEncoding; + if (!hasDestCharSet) { + destCharSet = srcCharSet; } - if (bundleEncoding == null) { - bundleEncoding = srcEncoding; + if (!hasBundleCharSet) { + bundleCharSet = srcCharSet; } loadResourceMaps(); @@ -381,7 +411,7 @@ private void loadResourceMaps() throws BuildException { language = locale.getLanguage().isEmpty() ? "" : "_" + locale.getLanguage(); country = locale.getCountry().isEmpty() ? "" : "_" + locale.getCountry(); variant = locale.getVariant().isEmpty() ? "" : "_" + locale.getVariant(); - bundleEncoding = System.getProperty("file.encoding"); + bundleCharSet = CharSet.getDefault(); processBundle(bundle + language + country + variant, BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT, false); processBundle(bundle + language + country, BUNDLE_DEFAULT_LANGUAGE_COUNTRY, false); @@ -418,7 +448,7 @@ private void processBundle(final String bundleFile, final int i, */ private void loadResourceMap(InputStream ins) throws BuildException { try (BufferedReader in = - new BufferedReader(new InputStreamReader(ins, bundleEncoding))) { + new BufferedReader(new InputStreamReader(ins, bundleCharSet.getCharset()))) { String line; while ((line = in.readLine()) != null) { //So long as the line isn't empty and isn't a comment... @@ -524,9 +554,9 @@ private void translate() throws BuildException { private void translateOneFile(File src, File dest) throws IOException { try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter( - Files.newOutputStream(dest.toPath()), destEncoding)); - BufferedReader in = new BufferedReader(new InputStreamReader( - Files.newInputStream(src.toPath()), srcEncoding))) { + Files.newOutputStream(dest.toPath()), destCharSet.getCharset())); + BufferedReader in = new BufferedReader(new InputStreamReader( + Files.newInputStream(src.toPath()), srcCharSet.getCharset()))) { LineTokenizer lineTokenizer = new LineTokenizer(); lineTokenizer.setIncludeDelims(true); String line = lineTokenizer.getToken(in); diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java index eba66e5bd2..e77e6b2875 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java @@ -31,6 +31,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.optional.Native2Ascii; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.util.Native2AsciiUtils; /** @@ -46,10 +47,9 @@ public class BuiltinNative2Ascii implements Native2AsciiAdapter { public final boolean convert(Native2Ascii args, File srcFile, File destFile) throws BuildException { boolean reverse = args.getReverse(); - String encoding = args.getEncoding(); - try (BufferedReader input = getReader(srcFile, encoding, reverse); - Writer output = getWriter(destFile, encoding, reverse)) { - + CharSet charSet = args.getCharSet(); + try (BufferedReader input = getReader(srcFile, charSet, reverse); + Writer output = getWriter(destFile, charSet, reverse)) { translate(input, output, reverse ? Native2AsciiUtils::ascii2native : Native2AsciiUtils::native2ascii); return true; @@ -58,26 +58,21 @@ public final boolean convert(Native2Ascii args, File srcFile, } } - private BufferedReader getReader(File srcFile, String encoding, + private BufferedReader getReader(File srcFile, CharSet charSet, boolean reverse) throws IOException { - if (reverse || encoding == null) { - return new BufferedReader(new FileReader(srcFile)); - } - return new BufferedReader(new InputStreamReader( - Files.newInputStream(srcFile.toPath()), encoding)); + return reverse ? new BufferedReader(new FileReader(srcFile)) + : new BufferedReader(new InputStreamReader(Files.newInputStream(srcFile.toPath()), + charSet.getCharset())); } - private Writer getWriter(File destFile, String encoding, + private Writer getWriter(File destFile, CharSet charSet, boolean reverse) throws IOException { if (!reverse) { - encoding = "ASCII"; - } - if (encoding == null) { - return new BufferedWriter(new FileWriter(destFile)); + charSet = CharSet.getAscii(); } return new BufferedWriter( new OutputStreamWriter(Files.newOutputStream(destFile.toPath()), - encoding)); + charSet.getCharset())); } private void translate(BufferedReader input, Writer output, diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java index f0cf94cb0d..899bacca84 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java @@ -22,6 +22,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.taskdefs.optional.Native2Ascii; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Commandline; /** @@ -69,9 +70,10 @@ public final boolean convert(Native2Ascii args, File srcFile, */ protected void setup(Commandline cmd, Native2Ascii args) throws BuildException { - if (args.getEncoding() != null) { + CharSet cs = args.getCharSet(); + if (!cs.equivalent(CharSet.getDefault())) { cmd.createArgument().setValue("-encoding"); - cmd.createArgument().setValue(args.getEncoding()); + cmd.createArgument().setValue(cs.getValue()); } cmd.addArguments(args.getCurrentArgs()); } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java b/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java index 4a3aeba429..01e39ce55f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java @@ -33,6 +33,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.taskdefs.DefBase; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.util.ClasspathUtils; import org.apache.tools.ant.util.ScriptRunnerBase; @@ -193,7 +194,7 @@ public void execute() { "scriptdef requires a language attribute to specify the script language"); } - if (helper.getSrc() == null && helper.getEncoding() != null) { + if (helper.getSrc() == null && helper.hasCharSet()) { throw new BuildException( "scriptdef requires a src attribute if the encoding is set"); } @@ -392,7 +393,16 @@ public void setSrc(File file) { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - helper.setEncoding(encoding); + helper.setCharSet(new CharSet(encoding)); + } + + /** + * Sets the charset of the script from an external file; optional. + * + * @param charSet the charset of the file containing the script source. + */ + public void setCharSet(CharSet charSet) { + helper.setCharSet(charSet); } /** diff --git a/src/main/org/apache/tools/ant/types/ArchiveFileSet.java b/src/main/org/apache/tools/ant/types/ArchiveFileSet.java index 1082e9ede9..0e489e93f4 100644 --- a/src/main/org/apache/tools/ant/types/ArchiveFileSet.java +++ b/src/main/org/apache/tools/ant/types/ArchiveFileSet.java @@ -72,7 +72,7 @@ public abstract class ArchiveFileSet extends FileSet { private boolean errorOnMissingArchive = true; - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** Constructor for ArchiveFileSet */ public ArchiveFileSet() { @@ -102,7 +102,7 @@ protected ArchiveFileSet(ArchiveFileSet fileset) { fileModeHasBeenSet = fileset.fileModeHasBeenSet; dirModeHasBeenSet = fileset.dirModeHasBeenSet; errorOnMissingArchive = fileset.errorOnMissingArchive; - encoding = fileset.encoding; + charSet = fileset.charSet; } /** @@ -269,26 +269,48 @@ public String getFullpath(Project p) { } /** - * Set the encoding used for this ZipFileSet. + * Set the encoding used for this ArchiveFileSet. * @param enc encoding as String. * @since Ant 1.9.5 */ public void setEncoding(String enc) { - checkAttributesAllowed(); - this.encoding = enc; + setCharSet(new CharSet(enc)); } /** - * Get the encoding used for this ZipFileSet. + * Get the encoding used for this ArchiveFileSet. * @return String encoding. * @since Ant 1.9.5 */ public String getEncoding() { if (isReference()) { AbstractFileSet ref = getRef(); - return ref instanceof ArchiveFileSet ? ((ArchiveFileSet) ref).getEncoding() : null; + return ref instanceof ArchiveFileSet ? ((ArchiveFileSet) ref).getEncoding() + : CharSet.getDefault().getValue(); + } + return charSet.getValue(); + } + + /** + * Set the encoding used for this ArchiveFileSet. + * @param charSet encoding as CharSet. + */ + public void setCharSet(CharSet charSet) { + checkAttributesAllowed(); + this.charSet = charSet; + } + + /** + * Get the encoding used for this ArchiveFileSet. + * @return CharSet encoding. + */ + public CharSet getCharSet() { + if (isReference()) { + AbstractFileSet ref = getRef(getProject()); + return ref instanceof ArchiveFileSet ? ((ArchiveFileSet) ref).getCharSet() + : CharSet.getDefault(); } - return encoding; + return charSet; } /** diff --git a/src/main/org/apache/tools/ant/types/ArchiveScanner.java b/src/main/org/apache/tools/ant/types/ArchiveScanner.java index c0aa12d6a6..ed5875084c 100644 --- a/src/main/org/apache/tools/ant/types/ArchiveScanner.java +++ b/src/main/org/apache/tools/ant/types/ArchiveScanner.java @@ -83,7 +83,7 @@ public abstract class ArchiveScanner extends DirectoryScanner { * * @since Ant 1.6 */ - private String encoding; + private CharSet encoding = CharSet.getDefault(); /** * @since Ant 1.8.0 @@ -138,11 +138,19 @@ public void setSrc(Resource src) { /** * Sets encoding of file names. - * @param encoding the encoding format + * @param encoding the encoding name * @since Ant 1.6 */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Sets CharSet of file names. + * @param charSet the CharSet + */ + public void setCharSet(CharSet charSet) { + this.encoding = charSet; } /** @@ -311,7 +319,7 @@ public Resource getResource(String name) { * patterns and didn't match any exclude patterns. */ protected abstract void fillMapsFromArchive(Resource archive, - String encoding, + CharSet encoding, Map fileEntries, Map matchFileEntries, Map dirEntries, diff --git a/src/main/org/apache/tools/ant/types/PatternSet.java b/src/main/org/apache/tools/ant/types/PatternSet.java index f2b186ea35..2b7d901e90 100644 --- a/src/main/org/apache/tools/ant/types/PatternSet.java +++ b/src/main/org/apache/tools/ant/types/PatternSet.java @@ -20,10 +20,8 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -186,11 +184,10 @@ public String toString() { * @since Ant 1.10.4 */ public class PatternFileNameEntry extends NameEntry { - private String encoding; + private CharSet charSet = CharSet.getDefault(); /** - * Encoding to use when reading the file, defaults to the platform's default - * encoding. + * Encoding to use when reading the file, defaults to the platform encoding. * *

* For a list of possible values see @@ -201,24 +198,45 @@ public class PatternFileNameEntry extends NameEntry { * @param encoding String */ public final void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** - * Encoding to use when reading the file, defaults to the platform's default - * encoding. + * Encoding to use when reading the file, defaults to the platform encoding. * * @return the encoding name */ public final String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * Encoding to use when reading the file, defaults to the platform encoding. + * + *

+ * For a list of possible values see + * + * https://docs.oracle.com/javase/1.5.0/docs/guide/intl/encoding.doc.html. + *

+ * + * @param charSet CharSet + */ + public final void setCharSet(CharSet charSet) { + this.charSet = charSet; + } + + /** + * Encoding to use when reading the file, defaults to the platform encoding. + * + * @return the encoding CharSet + */ + public final CharSet getCharSet() { + return charSet; } @Override public String toString() { - String baseString = super.toString(); - return encoding == null ? baseString - : baseString + ";encoding->" + encoding; + return super.toString() + ";encoding->" + charSet.getValue(); } } @@ -413,13 +431,10 @@ public void setExcludesfile(File excludesFile) throws BuildException { * Reads path matching patterns from a file and adds them to the * includes or excludes list (as appropriate). */ - private void readPatterns(File patternfile, String encoding, List patternlist, Project p) + private void readPatterns(File patternfile, CharSet encoding, List patternlist, Project p) throws BuildException { - - try (Reader r = encoding == null ? new FileReader(patternfile) - : new InputStreamReader(new FileInputStream(patternfile), encoding); - BufferedReader patternReader = new BufferedReader(r)) { - + try (BufferedReader patternReader = new BufferedReader(new InputStreamReader( + new FileInputStream(patternfile), encoding.getCharset()))) { // Create one NameEntry in the appropriate pattern list for each // line in the file. patternReader.lines() @@ -532,7 +547,7 @@ private void readFiles(Project p) { throw new BuildException("Includesfile " + inclFile.getAbsolutePath() + " not found."); } - readPatterns(inclFile, ne.getEncoding(), includeList, p); + readPatterns(inclFile, ne.getCharSet(), includeList, p); } } includesFileList.clear(); @@ -546,7 +561,7 @@ private void readFiles(Project p) { throw new BuildException("Excludesfile " + exclFile.getAbsolutePath() + " not found."); } - readPatterns(exclFile, ne.getEncoding(), excludeList, p); + readPatterns(exclFile, ne.getCharSet(), excludeList, p); } } excludesFileList.clear(); diff --git a/src/main/org/apache/tools/ant/types/RedirectorElement.java b/src/main/org/apache/tools/ant/types/RedirectorElement.java index c778ca2772..030bcd14de 100644 --- a/src/main/org/apache/tools/ant/types/RedirectorElement.java +++ b/src/main/org/apache/tools/ant/types/RedirectorElement.java @@ -94,13 +94,13 @@ public class RedirectorElement extends DataType { private Vector errorFilterChains = new Vector<>(); /** The output encoding */ - private String outputEncoding; + private CharSet outputCharSet = CharSet.getDefault(); /** The error encoding */ - private String errorEncoding; + private CharSet errorCharSet = CharSet.getDefault(); /** The input encoding */ - private String inputEncoding; + private CharSet inputCharSet = CharSet.getDefault(); /** whether to log the inputstring */ private Boolean logInputString; @@ -108,6 +108,12 @@ public class RedirectorElement extends DataType { /** Is the output binary or can we safely split it into lines? */ private boolean outputIsBinary = false; + private boolean hasOutputCharSet = false; + + private boolean hasErrorCharSet = false; + + private boolean hasInputCharSet = false; + /** * Add the input file mapper. * @param inputMapper Mapper. @@ -184,9 +190,9 @@ public void setRefid(Reference r) throws BuildException { || logError != null || append != null || createEmptyFiles != null - || inputEncoding != null - || outputEncoding != null - || errorEncoding != null + || hasOutputCharSet + || hasInputCharSet + || hasErrorCharSet || outputProperty != null || errorProperty != null || logInputString != null) { @@ -264,7 +270,7 @@ public void setOutputEncoding(String outputEncoding) { if (isReference()) { throw tooManyAttributes(); } - this.outputEncoding = outputEncoding; + setOutputCharSet(new CharSet(outputEncoding)); } /** @@ -276,7 +282,7 @@ public void setErrorEncoding(String errorEncoding) { if (isReference()) { throw tooManyAttributes(); } - this.errorEncoding = errorEncoding; + setErrorCharSet(new CharSet(errorEncoding)); } /** @@ -287,7 +293,44 @@ public void setInputEncoding(String inputEncoding) { if (isReference()) { throw tooManyAttributes(); } - this.inputEncoding = inputEncoding; + setInputCharSet(new CharSet(inputEncoding)); + } + + /** + * Set the output encoding. + * @param outputCharSet CharSet. + */ + public void setOutputCharSet(CharSet outputCharSet) { + if (isReference()) { + throw tooManyAttributes(); + } + this.outputCharSet = outputCharSet; + hasOutputCharSet = true; + } + + /** + * Set the error encoding. + * + * @param errorCharSet CharSet. + */ + public void setErrorCharSet(CharSet errorCharSet) { + if (isReference()) { + throw tooManyAttributes(); + } + this.errorCharSet = errorCharSet; + hasErrorCharSet = true; + } + + /** + * Set the input encoding. + * @param inputCharSet String. + */ + public void setInputCharSet(CharSet inputCharSet) { + if (isReference()) { + throw tooManyAttributes(); + } + this.inputCharSet = inputCharSet; + hasInputCharSet = true; } /** @@ -538,14 +581,14 @@ public void configure(Redirector redirector, String sourcefile) { if (!errorFilterChains.isEmpty()) { redirector.setErrorFilterChains(errorFilterChains); } - if (inputEncoding != null) { - redirector.setInputEncoding(inputEncoding); + if (hasInputCharSet) { + redirector.setInputCharSet(inputCharSet); } - if (outputEncoding != null) { - redirector.setOutputEncoding(outputEncoding); + if (hasOutputCharSet) { + redirector.setOutputCharSet(outputCharSet); } - if (errorEncoding != null) { - redirector.setErrorEncoding(errorEncoding); + if (hasErrorCharSet) { + redirector.setErrorCharSet(errorCharSet); } redirector.setBinaryOutput(outputIsBinary); } diff --git a/src/main/org/apache/tools/ant/types/TarFileSet.java b/src/main/org/apache/tools/ant/types/TarFileSet.java index 2d085027a4..000d0832a5 100644 --- a/src/main/org/apache/tools/ant/types/TarFileSet.java +++ b/src/main/org/apache/tools/ant/types/TarFileSet.java @@ -181,7 +181,7 @@ public boolean hasGroupIdBeenSet() { @Override protected ArchiveScanner newArchiveScanner() { TarScanner zs = new TarScanner(); - zs.setEncoding(getEncoding()); + zs.setCharSet(getCharSet()); return zs; } diff --git a/src/main/org/apache/tools/ant/types/TarScanner.java b/src/main/org/apache/tools/ant/types/TarScanner.java index 1dca3ee2aa..be443d16c5 100644 --- a/src/main/org/apache/tools/ant/types/TarScanner.java +++ b/src/main/org/apache/tools/ant/types/TarScanner.java @@ -48,7 +48,7 @@ public class TarScanner extends ArchiveScanner { * resources found inside the archive that matched all include * patterns and didn't match any exclude patterns. */ - protected void fillMapsFromArchive(Resource src, String encoding, + protected void fillMapsFromArchive(Resource src, CharSet encoding, Map fileEntries, Map matchFileEntries, Map dirEntries, Map matchDirEntries) { diff --git a/src/main/org/apache/tools/ant/types/ZipFileSet.java b/src/main/org/apache/tools/ant/types/ZipFileSet.java index a73a2e9130..c047c2ac1f 100644 --- a/src/main/org/apache/tools/ant/types/ZipFileSet.java +++ b/src/main/org/apache/tools/ant/types/ZipFileSet.java @@ -61,7 +61,7 @@ protected ZipFileSet(ZipFileSet fileset) { @Override protected ArchiveScanner newArchiveScanner() { ZipScanner zs = new ZipScanner(); - zs.setEncoding(getEncoding()); + zs.setCharSet(getCharSet()); return zs; } diff --git a/src/main/org/apache/tools/ant/types/ZipScanner.java b/src/main/org/apache/tools/ant/types/ZipScanner.java index 317c4e2c26..ebd1a37cb3 100644 --- a/src/main/org/apache/tools/ant/types/ZipScanner.java +++ b/src/main/org/apache/tools/ant/types/ZipScanner.java @@ -52,7 +52,7 @@ public class ZipScanner extends ArchiveScanner { * patterns and didn't match any exclude patterns. */ @Override - protected void fillMapsFromArchive(Resource src, String encoding, + protected void fillMapsFromArchive(Resource src, CharSet encoding, Map fileEntries, Map matchFileEntries, Map dirEntries, Map matchDirEntries) { @@ -60,7 +60,7 @@ protected void fillMapsFromArchive(Resource src, String encoding, .map(FileProvider::getFile).orElseThrow(() -> new BuildException( "Only file provider resources are supported")); - try (ZipFile zf = new ZipFile(srcFile, encoding)) { + try (ZipFile zf = new ZipFile(srcFile, encoding.getValue())) { StreamUtils.enumerationAsStream(zf.getEntries()).forEach(entry -> { Resource r = new ZipResource(srcFile, encoding, entry); String name = entry.getName(); diff --git a/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java b/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java index 19bebf191a..0496b514ca 100644 --- a/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java +++ b/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java @@ -21,6 +21,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.ScriptRunnerBase; @@ -164,6 +165,15 @@ public void setSetBeans(boolean setBeans) { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - helper.setEncoding(encoding); + helper.setCharSet(new CharSet(encoding)); + } + + /** + * Set the encoding of the script from an external file; optional. + * + * @param charSet the CharSet of the file containing the script source. + */ + public void setEncoding(CharSet charSet) { + helper.setCharSet(charSet); } } diff --git a/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java b/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java index a5a83487cf..fcab784713 100644 --- a/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java +++ b/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java @@ -23,6 +23,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.filters.TokenFilter; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.ScriptRunnerBase; @@ -190,6 +191,15 @@ public void setSetBeans(boolean setBeans) { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - helper.setEncoding(encoding); + helper.setCharSet(new CharSet(encoding)); + } + + /** + * Set the encoding of the script from an external file; optional. + * + * @param charSet the CharSet of the file containing the script source. + */ + public void setEncoding(CharSet charSet) { + helper.setCharSet(charSet); } } diff --git a/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java b/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java index 5f1b5ea140..184adc0be7 100644 --- a/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java +++ b/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java @@ -21,6 +21,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.selectors.BaseSelector; @@ -229,6 +230,15 @@ public void setSelected(boolean selected) { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - helper.setEncoding(encoding); + helper.setCharSet(new CharSet(encoding)); + } + + /** + * Set the encoding of the script from an external file; optional. + * + * @param charSet the CharSet of the file containing the script source. + */ + public void setEncoding(CharSet charSet) { + helper.setCharSet(charSet); } } diff --git a/src/main/org/apache/tools/ant/types/resources/ResourceList.java b/src/main/org/apache/tools/ant/types/resources/ResourceList.java index 2925cb418f..3fb5cc13ee 100644 --- a/src/main/org/apache/tools/ant/types/resources/ResourceList.java +++ b/src/main/org/apache/tools/ant/types/resources/ResourceList.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.Stack; @@ -33,6 +32,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.filters.util.ChainReaderHelper; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.DataType; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.Reference; @@ -49,7 +49,8 @@ public class ResourceList extends DataType implements ResourceCollection { private final ArrayList textDocuments = new ArrayList<>(); private final Union cachedResources = new Union(); private volatile boolean cached = false; - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); + private boolean isEncodingSet = false; private File baseDir; public ResourceList() { @@ -83,8 +84,7 @@ public final void addFilterChain(FilterChain filter) { } /** - * Encoding to use for input, defaults to the platform's default - * encoding. + * Encoding to use for input, defaults to the platform encoding. * *

* For a list of possible values see @@ -98,7 +98,26 @@ public final void setEncoding(String encoding) { if (isReference()) { throw tooManyAttributes(); } - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * Encoding to use for input, defaults to the platform encoding. + * + *

+ * For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html. + *

+ * + * @param charSet CharSet + */ + public final void setCharSet(CharSet charSet) { + if (isReference()) { + throw tooManyAttributes(); + } + this.charSet = charSet; + isEncodingSet = true; } /** @@ -124,7 +143,7 @@ public final void setBasedir(File baseDir) { */ @Override public void setRefid(Reference r) throws BuildException { - if (encoding != null) { + if (isEncodingSet) { throw tooManyAttributes(); } if (!filterChains.isEmpty() || !textDocuments.isEmpty()) { @@ -231,9 +250,8 @@ private ResourceCollection read(Resource r) { private Reader open(Resource r) throws IOException { ChainReaderHelper crh = new ChainReaderHelper(); - crh.setPrimaryReader(new InputStreamReader( - new BufferedInputStream(r.getInputStream()), encoding == null - ? Charset.defaultCharset() : Charset.forName(encoding))); + crh.setPrimaryReader(new InputStreamReader(new BufferedInputStream(r.getInputStream()), + charSet.getCharset())); crh.setFilterChains(filterChains); crh.setProject(getProject()); return crh.getAssembledReader(); diff --git a/src/main/org/apache/tools/ant/types/resources/StringResource.java b/src/main/org/apache/tools/ant/types/resources/StringResource.java index ede4154c6b..e95ca0d117 100644 --- a/src/main/org/apache/tools/ant/types/resources/StringResource.java +++ b/src/main/org/apache/tools/ant/types/resources/StringResource.java @@ -26,6 +26,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.Resource; @@ -39,8 +40,9 @@ public class StringResource extends Resource { private static final int STRING_MAGIC = Resource.getMagicNumber("StringResource".getBytes()); - private static final String DEFAULT_ENCODING = "UTF-8"; - private String encoding = DEFAULT_ENCODING; + private CharSet charSet = CharSet.getUtf8(); + + private boolean isEncodingSet = false; /** * Default constructor. @@ -130,8 +132,7 @@ public void addText(String text) { * @param s the encoding name. */ public synchronized void setEncoding(String s) { - checkAttributesAllowed(); - encoding = s; + setCharSet(new CharSet(s)); } /** @@ -139,7 +140,25 @@ public synchronized void setEncoding(String s) { * @return the encoding name. */ public synchronized String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * Set the encoding to be used for this StringResource. + * @param cs the CharSet. + */ + public synchronized void setCharSet(CharSet cs) { + checkAttributesAllowed(); + charSet = cs; + isEncodingSet = true; + } + + /** + * Get the encoding used by this StringResource. + * @return the CharSet. + */ + public synchronized CharSet getCharSet() { + return charSet; } /** @@ -194,8 +213,7 @@ public synchronized InputStream getInputStream() throws IOException { if (content == null) { throw new IllegalStateException("unset string value"); } - return new ByteArrayInputStream(encoding == null - ? content.getBytes() : content.getBytes(encoding)); + return new ByteArrayInputStream(content.getBytes(charSet.getCharset())); } /** @@ -223,7 +241,7 @@ public synchronized OutputStream getOutputStream() throws IOException { */ @Override public void setRefid(Reference r) { - if (encoding != DEFAULT_ENCODING) { + if (isEncodingSet) { throw tooManyAttributes(); } super.setRefid(r); @@ -253,10 +271,7 @@ public StringResourceFilterOutputStream() { @Override public void close() throws IOException { super.close(); - String result = encoding == null - ? baos.toString() : baos.toString(encoding); - - setValueFromOutputStream(result); + setValueFromOutputStream(baos.toString(charSet.getValue())); } private void setValueFromOutputStream(String output) { diff --git a/src/main/org/apache/tools/ant/types/resources/Tokens.java b/src/main/org/apache/tools/ant/types/resources/Tokens.java index 387f8a3058..8e000f06dd 100644 --- a/src/main/org/apache/tools/ant/types/resources/Tokens.java +++ b/src/main/org/apache/tools/ant/types/resources/Tokens.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStreamReader; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -28,6 +27,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.DataType; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; @@ -43,7 +43,7 @@ public class Tokens extends BaseResourceCollectionWrapper { private Tokenizer tokenizer; - private String encoding; + private CharSet charSet = CharSet.getDefault(); /** * Sort the contained elements. @@ -58,9 +58,7 @@ protected synchronized Collection getCollection() { tokenizer = new LineTokenizer(); } try (ConcatResourceInputStream cat = new ConcatResourceInputStream(rc); - InputStreamReader rdr = new InputStreamReader(cat, - encoding == null ? Charset.defaultCharset() - : Charset.forName(encoding))) { + InputStreamReader rdr = new InputStreamReader(cat, charSet.getCharset())) { cat.setManagingComponent(this); List result = new ArrayList<>(); for (String s = tokenizer.getToken(rdr); s != null; s = @@ -83,8 +81,16 @@ protected synchronized Collection getCollection() { * Set the encoding used to create the tokens. * @param encoding the encoding to use. */ - public synchronized void setEncoding(String encoding) { - this.encoding = encoding; + public void setEncoding(String encoding) { + setEncoding(new CharSet(encoding)); + } + + /** + * Set the encoding used to create the tokens. + * @param charSet the CharSet to use. + */ + public synchronized void setEncoding(CharSet charSet) { + this.charSet = charSet; } /** diff --git a/src/main/org/apache/tools/ant/types/resources/ZipResource.java b/src/main/org/apache/tools/ant/types/resources/ZipResource.java index bc84e81c38..3ee69ee9c6 100644 --- a/src/main/org/apache/tools/ant/types/resources/ZipResource.java +++ b/src/main/org/apache/tools/ant/types/resources/ZipResource.java @@ -25,6 +25,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.util.FileUtils; @@ -38,7 +39,8 @@ */ public class ZipResource extends ArchiveResource { - private String encoding; + private CharSet charSet = CharSet.getDefault(); + private boolean hasCharSet = false; private ZipExtraField[] extras; private int method; @@ -56,8 +58,19 @@ public ZipResource() { * @param e the ZipEntry. */ public ZipResource(File z, String enc, ZipEntry e) { + this(z, new CharSet(enc), e); + } + + /** + * Construct a ZipResource representing the specified + * entry in the specified zipfile. + * @param z the zipfile as File. + * @param charSet the CharSet used for filenames. + * @param e the ZipEntry. + */ + public ZipResource(File z, CharSet charSet, ZipEntry e) { super(z, true); - setEncoding(enc); + setCharSet(charSet); setEntry(e); } @@ -95,8 +108,7 @@ public void addConfigured(ResourceCollection a) { * @param enc the String encoding. */ public void setEncoding(String enc) { - checkAttributesAllowed(); - encoding = enc; + setCharSet(new CharSet(enc)); } /** @@ -105,7 +117,26 @@ public void setEncoding(String enc) { */ public String getEncoding() { return isReference() - ? getRef().getEncoding() : encoding; + ? getRef().getEncoding() : charSet.getValue(); + } + + /** + * Set the encoding to use with the zipfile. + * @param encoding the String encoding. + */ + public void setCharSet(CharSet encoding) { + checkAttributesAllowed(); + this.charSet = encoding; + hasCharSet = true; + } + + /** + * Get the encoding to use with the zipfile. + * @return String encoding. + */ + public CharSet getCharSet() { + return isReference() + ? getRef().getCharSet() : charSet; } /** @@ -113,7 +144,7 @@ public String getEncoding() { * @param r the Reference to set. */ public void setRefid(Reference r) { - if (encoding != null) { + if (hasCharSet) { throw tooManyAttributes(); } super.setRefid(r); @@ -129,7 +160,7 @@ public InputStream getInputStream() throws IOException { if (isReference()) { return getRef().getInputStream(); } - return getZipEntryStream(new ZipFile(getZipfile(), getEncoding()), getName()); + return getZipEntryStream(new ZipFile(getZipfile(), getCharSet().getCharset()), getName()); } /** @@ -209,7 +240,7 @@ protected void finalize() throws Throwable { protected void fetchEntry() { ZipFile z = null; try { - z = new ZipFile(getZipfile(), getEncoding()); + z = new ZipFile(getZipfile(), getCharSet().getCharset()); setEntry(z.getEntry(getName())); } catch (IOException e) { log(e.getMessage(), Project.MSG_DEBUG); diff --git a/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java index 662c7bf08e..8f45695f36 100644 --- a/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java +++ b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java @@ -22,10 +22,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.nio.charset.Charset; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Parameter; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.resources.FileResource; @@ -51,7 +51,7 @@ public class ContainsSelector extends BaseExtendSelector implements ResourceSele private String contains = null; private boolean casesensitive = true; private boolean ignorewhitespace = false; - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * @return a string describing this object @@ -76,7 +76,15 @@ public void setText(String contains) { * @param encoding encoding of the resources processed */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); + } + + /** + * The encoding of the resources processed + * @param charSet CharSet of the resources processed + */ + public void setCharSet(CharSet charSet) { + this.charSet = charSet; } /** @@ -170,9 +178,8 @@ public boolean isSelected(Resource r) { if (ignorewhitespace) { userstr = SelectorUtils.removeWhitespace(userstr); } - try (BufferedReader in = new BufferedReader( - new InputStreamReader(r.getInputStream(), encoding == null - ? Charset.defaultCharset() : Charset.forName(encoding)))) { + try (BufferedReader in = new BufferedReader(new InputStreamReader(r.getInputStream(), + charSet.getCharset()))) { try { String teststr = in.readLine(); while (teststr != null) { diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java index ad90bcb934..2c6926b4ed 100644 --- a/src/main/org/apache/tools/ant/util/FileUtils.java +++ b/src/main/org/apache/tools/ant/util/FileUtils.java @@ -54,6 +54,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.launch.Locator; import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.FilterSetCollection; import org.apache.tools.ant.types.resources.FileResource; @@ -390,7 +391,7 @@ public void copyFile(File sourceFile, File destFile, FilterSetCollection filters */ public void copyFile(File sourceFile, File destFile, FilterSetCollection filters, boolean overwrite, boolean preserveLastModified) throws IOException { - copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, null); + copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, CharSet.getDefault()); } /** @@ -419,6 +420,30 @@ public void copyFile(File sourceFile, File destFile, preserveLastModified, encoding, null); } + /** + * Convenience method to copy a file from a source to a destination specifying if token + * filtering must be used, if source files may overwrite newer destination files, the last + * modified time of destFile file should be made equal to the last modified time + * of sourceFile and which character encoding to assume. + * + * @param sourceFile the file to copy from. Must not be null. + * @param destFile the file to copy to. Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param overwrite Whether or not the destination file should be overwritten if it already + * exists. + * @param preserveLastModified Whether or not the last modified time of the resulting file + * should be set to that of the source file. + * @param charSet the CharSet used to read and write the files. + * + * @throws IOException if the copying fails. + */ + public void copyFile(File sourceFile, File destFile, + FilterSetCollection filters, boolean overwrite, + boolean preserveLastModified, CharSet charSet) throws IOException { + copyFile(sourceFile, destFile, filters, null, overwrite, + preserveLastModified, charSet, null); + } + /** * Convenience method to copy a file from a source to a * destination specifying if token filtering must be used, if @@ -453,6 +478,38 @@ public void copyFile(File sourceFile, File destFile, overwrite, preserveLastModified, encoding, encoding, project); } + /** + * Convenience method to copy a file from a source to a + * destination specifying if token filtering must be used, if + * filter chains must be used, if source files may overwrite + * newer destination files and the last modified time of + * destFile file should be made equal + * to the last modified time of sourceFile. + * + * @param sourceFile the file to copy from. + * Must not be null. + * @param destFile the file to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination file should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the resulting file should be set to that + * of the source file. + * @param charSet the CharSet used to read and write the files. + * @param project the project instance. + * + * @throws IOException if the copying fails. + */ + public void copyFile(File sourceFile, File destFile, + FilterSetCollection filters, Vector filterChains, + boolean overwrite, boolean preserveLastModified, + CharSet charSet, Project project) throws IOException { + copyFile(sourceFile, destFile, filters, filterChains, + overwrite, preserveLastModified, charSet, charSet, project); + } + /** * Convenience method to copy a file from a source to a * destination specifying if token filtering must be used, if @@ -490,6 +547,41 @@ public void copyFile(File sourceFile, File destFile, false, inputEncoding, outputEncoding, project); } + /** + * Convenience method to copy a file from a source to a + * destination specifying if token filtering must be used, if + * filter chains must be used, if source files may overwrite + * newer destination files and the last modified time of + * destFile file should be made equal + * to the last modified time of sourceFile. + * + * @param sourceFile the file to copy from. + * Must not be null. + * @param destFile the file to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination file should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the resulting file should be set to that + * of the source file. + * @param inputCharSet the CharSet used to read the files. + * @param outputCharSet the CharSet used to write the files. + * @param project the project instance. + * + * + * @throws IOException if the copying fails. + */ + public void copyFile(File sourceFile, File destFile, + FilterSetCollection filters, Vector filterChains, + boolean overwrite, boolean preserveLastModified, + CharSet inputCharSet, CharSet outputCharSet, + Project project) throws IOException { + copyFile(sourceFile, destFile, filters, filterChains, overwrite, preserveLastModified, + false, inputCharSet, outputCharSet, project); + } + /** * Convenience method to copy a file from a source to a * destination specifying if token filtering must be used, if @@ -530,6 +622,44 @@ public void copyFile(File sourceFile, File destFile, project, /* force: */ false); } + /** + * Convenience method to copy a file from a source to a + * destination specifying if token filtering must be used, if + * filter chains must be used, if source files may overwrite + * newer destination files and the last modified time of + * destFile file should be made equal + * to the last modified time of sourceFile. + * + * @param sourceFile the file to copy from. + * Must not be null. + * @param destFile the file to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination file should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the resulting file should be set to that + * of the source file. + * @param append whether to append to the destination file. + * @param inputCharSet the CharSet used to read the files. + * @param outputCharSet the CharSet used to write the files. + * @param project the project instance. + * + * + * @throws IOException if the copying fails. + */ + public void copyFile(File sourceFile, File destFile, + FilterSetCollection filters, Vector filterChains, + boolean overwrite, boolean preserveLastModified, + boolean append, + CharSet inputCharSet, CharSet outputCharSet, + Project project) throws IOException { + copyFile(sourceFile, destFile, filters, filterChains, overwrite, + preserveLastModified, append, inputCharSet, outputCharSet, + project, /* force: */ false); + } + /** * Convenience method to copy a file from a source to a * destination specifying if token filtering must be used, if @@ -565,11 +695,51 @@ public void copyFile(File sourceFile, File destFile, boolean append, String inputEncoding, String outputEncoding, Project project, boolean force) throws IOException { + ResourceUtils.copyResource(new FileResource(sourceFile), + new FileResource(destFile), + filters, filterChains, overwrite, + preserveLastModified, append, inputEncoding, + outputEncoding, project, force); + } + + /** + * Convenience method to copy a file from a source to a + * destination specifying if token filtering must be used, if + * filter chains must be used, if source files may overwrite + * newer destination files and the last modified time of + * destFile file should be made equal + * to the last modified time of sourceFile. + * + * @param sourceFile the file to copy from. + * Must not be null. + * @param destFile the file to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination file should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the resulting file should be set to that + * of the source file. + * @param append whether to append to the destination file. + * @param inputCharSet the CharSet used to read the files. + * @param outputCharSet the CharSet used to write the files. + * @param project the project instance. + * @param force whether to overwrite read-only destination files. + * + * @throws IOException if the copying fails. + */ + public void copyFile(File sourceFile, File destFile, + FilterSetCollection filters, Vector filterChains, + boolean overwrite, boolean preserveLastModified, + boolean append, + CharSet inputCharSet, CharSet outputCharSet, + Project project, boolean force) throws IOException { ResourceUtils.copyResource(new FileResource(sourceFile), new FileResource(destFile), filters, filterChains, overwrite, - preserveLastModified, append, inputEncoding, - outputEncoding, project, force); + preserveLastModified, append, inputCharSet, + outputCharSet, project, force); } // CheckStyle:ParameterNumberCheck ON diff --git a/src/main/org/apache/tools/ant/util/ReaderInputStream.java b/src/main/org/apache/tools/ant/util/ReaderInputStream.java index 610351a362..544c965a9a 100644 --- a/src/main/org/apache/tools/ant/util/ReaderInputStream.java +++ b/src/main/org/apache/tools/ant/util/ReaderInputStream.java @@ -17,6 +17,8 @@ */ package org.apache.tools.ant.util; +import org.apache.tools.ant.types.CharSet; + import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -33,7 +35,7 @@ public class ReaderInputStream extends InputStream { /** Source Reader */ private Reader in; - private String encoding = System.getProperty("file.encoding"); + private Charset charset = Charset.defaultCharset(); private byte[] slack; @@ -62,7 +64,7 @@ public ReaderInputStream(Reader reader, String encoding) { if (encoding == null) { throw new IllegalArgumentException("encoding must not be null"); } - this.encoding = encoding; + this.charset = new CharSet(encoding).getCharset(); } /** @@ -72,14 +74,13 @@ public ReaderInputStream(Reader reader, String encoding) { * * @param reader non-null Reader. * @param charset non-null Charset charset. - * @since Ant 1.10.6 */ public ReaderInputStream(Reader reader, Charset charset) { this(reader); if (charset == null) { throw new IllegalArgumentException("encoding must not be null"); } - this.encoding = charset.name(); + this.charset = charset; } /** @@ -137,7 +138,7 @@ public synchronized int read(byte[] b, int off, int len) throws IOException { return -1; } if (n > 0) { - slack = new String(buf, 0, n).getBytes(encoding); + slack = new String(buf, 0, n).getBytes(charset); begin = 0; } } diff --git a/src/main/org/apache/tools/ant/util/ResourceUtils.java b/src/main/org/apache/tools/ant/util/ResourceUtils.java index 0e20388c16..cac621bba0 100644 --- a/src/main/org/apache/tools/ant/util/ResourceUtils.java +++ b/src/main/org/apache/tools/ant/util/ResourceUtils.java @@ -28,7 +28,6 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.nio.channels.FileChannel; -import java.nio.charset.Charset; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Vector; @@ -36,6 +35,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.filters.util.ChainReaderHelper; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.FilterSetCollection; import org.apache.tools.ant.types.Resource; @@ -258,7 +258,7 @@ public static void copyResource(final Resource source, final Resource dest) thro public static void copyResource(final Resource source, final Resource dest, final Project project) throws IOException { copyResource(source, dest, null, null, false, - false, null, null, project); + false, CharSet.getDefault(), CharSet.getDefault(), project); } // CheckStyle:ParameterNumberCheck OFF - bc @@ -297,6 +297,39 @@ public static void copyResource(final Resource source, final Resource dest, copyResource(source, dest, filters, filterChains, overwrite, preserveLastModified, false, inputEncoding, outputEncoding, project); } + /** + * Convenience method to copy content from one Resource to another + * specifying whether token filtering must be used, whether filter chains + * must be used, whether newer destination files may be overwritten and + * whether the last modified time of dest file should be made + * equal to the last modified time of source. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination Resource should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the destination Resource should be set to that + * of the source. + * @param inputEncoding the encoding used to read the files. + * @param outputEncoding the encoding used to write the files. + * @param project the project instance. + * + * @throws IOException if the copying fails. + */ + public static void copyResource(final Resource source, final Resource dest, + final FilterSetCollection filters, final Vector filterChains, + final boolean overwrite, final boolean preserveLastModified, + final CharSet inputEncoding, final CharSet outputEncoding, + final Project project) + throws IOException { + copyResource(source, dest, filters, filterChains, overwrite, preserveLastModified, false, inputEncoding, outputEncoding, project); + } + // CheckStyle:ParameterNumberCheck OFF - bc /** * Convenience method to copy content from one Resource to another @@ -337,6 +370,43 @@ public static void copyResource(final Resource source, final Resource dest, outputEncoding, project, /* force: */ false); } + /** + * Convenience method to copy content from one Resource to another + * specifying whether token filtering must be used, whether filter chains + * must be used, whether newer destination files may be overwritten and + * whether the last modified time of dest file should be made + * equal to the last modified time of source. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination Resource should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the destination Resource should be set to that + * of the source. + * @param append Whether to append to an Appendable Resource. + * @param inputEncoding the encoding used to read the files. + * @param outputEncoding the encoding used to write the files. + * @param project the project instance. + * + * @throws IOException if the copying fails. + */ + public static void copyResource(final Resource source, final Resource dest, + final FilterSetCollection filters, final Vector filterChains, + final boolean overwrite, final boolean preserveLastModified, + final boolean append, + final CharSet inputEncoding, final CharSet outputEncoding, + final Project project) + throws IOException { + copyResource(source, dest, filters, filterChains, overwrite, + preserveLastModified, append, inputEncoding, + outputEncoding, project, /* force: */ false); + } + /** * Convenience method to copy content from one Resource to another * specifying whether token filtering must be used, whether filter chains @@ -371,6 +441,43 @@ public static void copyResource(final Resource source, final Resource dest, final boolean append, final String inputEncoding, final String outputEncoding, final Project project, final boolean force) + throws IOException { + copyResource(source, dest, filters, filterChains, overwrite, preserveLastModified, append, + new CharSet(inputEncoding), new CharSet(outputEncoding), project, force); + } + + /** + * Convenience method to copy content from one Resource to another + * specifying whether token filtering must be used, whether filter chains + * must be used, whether newer destination files may be overwritten and + * whether the last modified time of dest file should be made + * equal to the last modified time of source. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination Resource should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the destination Resource should be set to that + * of the source. + * @param append Whether to append to an Appendable Resource. + * @param inputCharSet the CharSet used to read the files. + * @param outputCharSet the CharSet used to write the files. + * @param project the project instance. + * @param force whether read-only target files will be overwritten + * + * @throws IOException if the copying fails. + */ + public static void copyResource(final Resource source, final Resource dest, + final FilterSetCollection filters, final Vector filterChains, + final boolean overwrite, final boolean preserveLastModified, + final boolean append, + final CharSet inputCharSet, final CharSet outputCharSet, + final Project project, final boolean force) throws IOException { if (!overwrite && !SelectorUtils.isOutOfDate(source, dest, FileUtils.getFileUtils().getFileTimestampGranularity())) { @@ -380,11 +487,11 @@ public static void copyResource(final Resource source, final Resource dest, && filters.hasFilters()); final boolean filterChainsAvailable = (filterChains != null && !filterChains.isEmpty()); - String effectiveInputEncoding; + CharSet effectiveInputCharSet; if (source instanceof StringResource) { - effectiveInputEncoding = ((StringResource) source).getEncoding(); + effectiveInputCharSet = ((StringResource) source).getCharSet(); } else { - effectiveInputEncoding = inputEncoding; + effectiveInputCharSet = inputCharSet; } File destFile = null; if (dest.as(FileProvider.class) != null) { @@ -402,15 +509,13 @@ public static void copyResource(final Resource source, final Resource dest, if (filterSetsAvailable) { copyWithFilterSets(source, dest, filters, filterChains, - append, effectiveInputEncoding, - outputEncoding, project); + append, effectiveInputCharSet, + outputCharSet, project); } else if (filterChainsAvailable - || (effectiveInputEncoding != null - && !effectiveInputEncoding.equals(outputEncoding)) - || (effectiveInputEncoding == null && outputEncoding != null)) { + || !effectiveInputCharSet.equivalent(outputCharSet)) { copyWithFilterChainsOrTranscoding(source, dest, filterChains, - append, effectiveInputEncoding, - outputEncoding, + append, effectiveInputCharSet, + outputCharSet, project); } else { boolean copied = false; @@ -639,7 +744,7 @@ private static void copyWithFilterSets(final Resource source, final Resource des final FilterSetCollection filters, final Vector filterChains, final boolean append, - final String inputEncoding, final String outputEncoding, + final CharSet inputCharSet, final CharSet outputCharSet, final Project project) throws IOException { @@ -649,11 +754,11 @@ private static void copyWithFilterSets(final Resource source, final Resource des return; } - try (Reader in = filterWith(project, inputEncoding, filterChains, + try (Reader in = filterWith(project, inputCharSet, filterChains, source.getInputStream()); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( getOutputStream(dest, append, project), - charsetFor(outputEncoding)))) { + outputCharSet.getCharset()))) { final LineTokenizer lineTokenizer = new LineTokenizer(); lineTokenizer.setIncludeDelims(true); @@ -671,9 +776,9 @@ private static void copyWithFilterSets(final Resource source, final Resource des } } - private static Reader filterWith(Project project, String encoding, + private static Reader filterWith(Project project, CharSet charSet, Vector filterChains, InputStream input) { - Reader r = new InputStreamReader(input, charsetFor(encoding)); + Reader r = new InputStreamReader(input, charSet.getCharset()); if (filterChains != null && !filterChains.isEmpty()) { final ChainReaderHelper crh = new ChainReaderHelper(); crh.setBufferSize(FileUtils.BUF_SIZE); @@ -685,16 +790,12 @@ private static Reader filterWith(Project project, String encoding, return new BufferedReader(r); } - private static Charset charsetFor(String encoding) { - return encoding == null ? Charset.defaultCharset() : Charset.forName(encoding); - } - private static void copyWithFilterChainsOrTranscoding(final Resource source, final Resource dest, final Vector filterChains, final boolean append, - final String inputEncoding, - final String outputEncoding, + final CharSet inputCharSet, + final CharSet outputCharSet, final Project project) throws IOException { @@ -704,11 +805,11 @@ private static void copyWithFilterChainsOrTranscoding(final Resource source, return; } - try (Reader in = filterWith(project, inputEncoding, filterChains, + try (Reader in = filterWith(project, inputCharSet, filterChains, source.getInputStream()); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( getOutputStream(dest, append, project), - charsetFor(outputEncoding)))) { + outputCharSet.getCharset()))) { final char[] buffer = new char[FileUtils.BUF_SIZE]; while (true) { final int nRead = in.read(buffer, 0, buffer.length); diff --git a/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java b/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java index f45988e0f2..9bbe0cd441 100644 --- a/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java +++ b/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java @@ -31,6 +31,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.PropertyResource; @@ -52,7 +53,7 @@ public abstract class ScriptRunnerBase { /** Script content */ private String script = ""; - private String encoding; + private CharSet charSet = CharSet.getDefault(); /** Enable script compilation. */ private boolean compiled; @@ -208,7 +209,15 @@ public final boolean getCompiled() { * @param encoding encoding of the external file containing the script source. */ public void setEncoding(String encoding) { - this.encoding = encoding; + this.charSet = new CharSet(encoding); + } + + /** + * Set encoding of the script from an external file; optional. + * @param cs encoding of the external file containing the script source. + */ + public void setCharSet(CharSet cs) { + this.charSet = cs; } /** @@ -222,10 +231,7 @@ public void setSrc(File file) { } try (InputStream in = Files.newInputStream(file.toPath())) { - final Charset charset = null == encoding ? Charset.defaultCharset() - : Charset.forName(encoding); - - readSource(in, filename, charset); + readSource(in, filename, charSet.getCharset()); } catch (IOException e) { //this can only happen if the file got deleted a short moment ago throw new BuildException("file " + filename + " not found.", e); diff --git a/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java b/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java index acec7915bb..5c2ca9fa81 100644 --- a/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java +++ b/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java @@ -20,6 +20,7 @@ import java.io.File; import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.ResourceCollection; @@ -31,7 +32,8 @@ public class ScriptRunnerHelper { private ClasspathUtils.Delegate cpDelegate = null; private File srcFile; - private String encoding; + private CharSet charSet = CharSet.getDefault(); + private boolean hasCharSet = false; private String manager = "auto"; private String language; private String text; @@ -56,11 +58,11 @@ public void setProjectComponent(ProjectComponent component) { public ScriptRunnerBase getScriptRunner() { ScriptRunnerBase runner = getRunner(); runner.setCompiled(compiled); - - if (encoding != null) { - // set it first, because runner.setSrc() loads immediately the file - runner.setEncoding(encoding); + if (hasCharSet) { + // set it first, because runner.setSrc() loads the file immediately + runner.setCharSet(charSet); } + if (srcFile != null) { runner.setSrc(srcFile); } @@ -131,7 +133,7 @@ public File getSrc() { * @since Ant 1.10.2 */ public void setEncoding(String encoding) { - this.encoding = encoding; + setCharSet(new CharSet(encoding)); } /** @@ -140,7 +142,25 @@ public void setEncoding(String encoding) { * @since Ant 1.10.2 */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * Set the encoding of the script from an external file; optional. + * + * @param cs the encoding of the file containing the script source. + */ + public void setCharSet(CharSet cs) { + this.charSet = cs; + hasCharSet = true; + } + + /** + * Get the external file encoding. + * @return the encoding of the file containing the script source. + */ + public CharSet getCharSet() { + return charSet; } /** @@ -261,4 +281,8 @@ private ScriptRunnerBase getRunner() { public void add(ResourceCollection resource) { resources.add(resource); } + + public boolean hasCharSet() { + return hasCharSet; + } } diff --git a/src/main/org/apache/tools/tar/TarInputStream.java b/src/main/org/apache/tools/tar/TarInputStream.java index 0477d5cb9e..6f8e81a6aa 100644 --- a/src/main/org/apache/tools/tar/TarInputStream.java +++ b/src/main/org/apache/tools/tar/TarInputStream.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.Map; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.zip.ZipEncoding; import org.apache.tools.zip.ZipEncodingHelper; @@ -88,6 +89,15 @@ public TarInputStream(InputStream is, String encoding) { this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE, encoding); } + /** + * Constructor for TarInputStream. + * @param is the input stream to use + * @param charSet name of the CharSet to use for file names + */ + public TarInputStream(InputStream is, CharSet charSet) { + this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE, charSet); + } + /** * Constructor for TarInputStream. * @param is the input stream to use @@ -107,6 +117,16 @@ public TarInputStream(InputStream is, int blockSize, String encoding) { this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE, encoding); } + /** + * Constructor for TarInputStream. + * @param is the input stream to use + * @param blockSize the block size to use + * @param charSet name of the CharSet to use for file names + */ + public TarInputStream(InputStream is, int blockSize, CharSet charSet) { + this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE, charSet); + } + /** * Constructor for TarInputStream. * @param is the input stream to use @@ -114,7 +134,7 @@ public TarInputStream(InputStream is, int blockSize, String encoding) { * @param recordSize the record size to use */ public TarInputStream(InputStream is, int blockSize, int recordSize) { - this(is, blockSize, recordSize, null); + this(is, blockSize, recordSize, CharSet.getDefault()); } /** @@ -126,13 +146,25 @@ public TarInputStream(InputStream is, int blockSize, int recordSize) { */ public TarInputStream(InputStream is, int blockSize, int recordSize, String encoding) { + this(is, blockSize, recordSize, new CharSet(encoding)); + } + + /** + * Constructor for TarInputStream. + * @param is the input stream to use + * @param blockSize the block size to use + * @param recordSize the record size to use + * @param charSet name of the CharSet to use for file names + */ + public TarInputStream(InputStream is, int blockSize, int recordSize, + CharSet charSet) { super(is); this.buffer = new TarBuffer(is, blockSize, recordSize); this.readBuf = null; this.oneBuf = new byte[1]; this.debug = false; this.hasHitEOF = false; - this.encoding = ZipEncodingHelper.getZipEncoding(encoding); + this.encoding = ZipEncodingHelper.getZipEncoding(charSet); } /** diff --git a/src/main/org/apache/tools/tar/TarOutputStream.java b/src/main/org/apache/tools/tar/TarOutputStream.java index ccf1f42e2d..144c8bb7f6 100644 --- a/src/main/org/apache/tools/tar/TarOutputStream.java +++ b/src/main/org/apache/tools/tar/TarOutputStream.java @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.Map; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.zip.ZipEncoding; import org.apache.tools.zip.ZipEncodingHelper; @@ -91,7 +92,7 @@ public class TarOutputStream extends FilterOutputStream { private boolean addPaxHeadersForNonAsciiNames = false; private static final ZipEncoding ASCII = - ZipEncodingHelper.getZipEncoding("ASCII"); + ZipEncodingHelper.getZipEncoding(CharSet.getAscii()); /** * Constructor for TarInputStream. @@ -112,6 +113,16 @@ public TarOutputStream(OutputStream os, String encoding) { this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE, encoding); } + /** + * Constructor for TarInputStream. + * + * @param os the output stream to use + * @param charSet name of the CharSet to use for file names + */ + public TarOutputStream(OutputStream os, CharSet charSet) { + this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE, charSet); + } + /** * Constructor for TarInputStream. * @@ -133,6 +144,17 @@ public TarOutputStream(OutputStream os, int blockSize, String encoding) { this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE, encoding); } + /** + * Constructor for TarInputStream. + * + * @param os the output stream to use + * @param blockSize the block size to use + * @param charSet name of the CharSet to use for file names + */ + public TarOutputStream(OutputStream os, int blockSize, CharSet charSet) { + this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE, charSet); + } + /** * Constructor for TarInputStream. * @@ -141,7 +163,7 @@ public TarOutputStream(OutputStream os, int blockSize, String encoding) { * @param recordSize the record size to use */ public TarOutputStream(OutputStream os, int blockSize, int recordSize) { - this(os, blockSize, recordSize, null); + this(os, blockSize, recordSize, CharSet.getDefault()); } /** @@ -154,8 +176,21 @@ public TarOutputStream(OutputStream os, int blockSize, int recordSize) { */ public TarOutputStream(OutputStream os, int blockSize, int recordSize, String encoding) { + this(os, blockSize, recordSize, new CharSet(encoding)); + } + + /** + * Constructor for TarInputStream. + * + * @param os the output stream to use + * @param blockSize the block size to use + * @param recordSize the record size to use + * @param charSet name of the CharSet to use for file names + */ + public TarOutputStream(OutputStream os, int blockSize, int recordSize, + CharSet charSet) { super(os); - this.encoding = ZipEncodingHelper.getZipEncoding(encoding); + this.encoding = ZipEncodingHelper.getZipEncoding(charSet); this.buffer = new TarBuffer(os, blockSize, recordSize); this.debug = false; diff --git a/src/main/org/apache/tools/tar/TarUtils.java b/src/main/org/apache/tools/tar/TarUtils.java index b6e12c4dac..2a1e3aaf8e 100644 --- a/src/main/org/apache/tools/tar/TarUtils.java +++ b/src/main/org/apache/tools/tar/TarUtils.java @@ -27,6 +27,7 @@ import java.math.BigInteger; import java.nio.ByteBuffer; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.zip.ZipEncoding; import org.apache.tools.zip.ZipEncodingHelper; @@ -40,7 +41,7 @@ public class TarUtils { private static final int BYTE_MASK = 255; static final ZipEncoding DEFAULT_ENCODING = - ZipEncodingHelper.getZipEncoding(null); + ZipEncodingHelper.getZipEncoding(CharSet.getDefault()); /** * Encapsulates the algorithms used up to Ant 1.8 as ZipEncoding. diff --git a/src/main/org/apache/tools/zip/AsiExtraField.java b/src/main/org/apache/tools/zip/AsiExtraField.java index 8afddb5339..dd76230b9f 100644 --- a/src/main/org/apache/tools/zip/AsiExtraField.java +++ b/src/main/org/apache/tools/zip/AsiExtraField.java @@ -47,7 +47,7 @@ * *

Since the documentation this class is based upon doesn't mention * the character encoding of the file name at all, it is assumed that - * it uses the current platform's default encoding.

+ * it uses the current platform encoding.

*/ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { diff --git a/src/main/org/apache/tools/zip/FallbackZipEncoding.java b/src/main/org/apache/tools/zip/FallbackZipEncoding.java index 19a5a0ff12..65da66e627 100644 --- a/src/main/org/apache/tools/zip/FallbackZipEncoding.java +++ b/src/main/org/apache/tools/zip/FallbackZipEncoding.java @@ -19,6 +19,8 @@ package org.apache.tools.zip; +import org.apache.tools.ant.types.CharSet; + import java.io.IOException; import java.nio.ByteBuffer; @@ -40,24 +42,24 @@ *

The methods of this class are reentrant.

*/ class FallbackZipEncoding implements ZipEncoding { - private final String charset; + private final CharSet charSet; /** - * Construct a fallback zip encoding, which uses the platform's - * default charset. + * Construct a fallback zip encoding, which uses the platform + * character set. */ public FallbackZipEncoding() { - this.charset = null; + this.charSet = CharSet.getDefault(); } /** * Construct a fallback zip encoding, which uses the given charset. * * @param charset The name of the charset or {@code null} for - * the platform's default character set. + * the platform character set. */ public FallbackZipEncoding(final String charset) { - this.charset = charset; + this.charSet = new CharSet(charset); } /** @@ -71,21 +73,13 @@ public boolean canEncode(final String name) { * @see org.apache.tools.zip.ZipEncoding#encode(java.lang.String) */ public ByteBuffer encode(final String name) throws IOException { - if (this.charset == null) { // i.e. use default charset, see no-args constructor - return ByteBuffer.wrap(name.getBytes()); - } else { - return ByteBuffer.wrap(name.getBytes(this.charset)); - } + return ByteBuffer.wrap(name.getBytes(this.charSet.getCharset())); } /** * @see org.apache.tools.zip.ZipEncoding#decode(byte[]) */ public String decode(final byte[] data) throws IOException { - if (this.charset == null) { // i.e. use default charset, see no-args constructor - return new String(data); - } else { - return new String(data, this.charset); - } + return new String(data, this.charSet.getCharset()); } } diff --git a/src/main/org/apache/tools/zip/NioZipEncoding.java b/src/main/org/apache/tools/zip/NioZipEncoding.java index 4853d2e9f4..e2f5d62bf8 100644 --- a/src/main/org/apache/tools/zip/NioZipEncoding.java +++ b/src/main/org/apache/tools/zip/NioZipEncoding.java @@ -20,7 +20,6 @@ package org.apache.tools.zip; import java.io.IOException; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; diff --git a/src/main/org/apache/tools/zip/Simple8BitZipEncoding.java b/src/main/org/apache/tools/zip/Simple8BitZipEncoding.java index b3c1132b94..629f0b6821 100644 --- a/src/main/org/apache/tools/zip/Simple8BitZipEncoding.java +++ b/src/main/org/apache/tools/zip/Simple8BitZipEncoding.java @@ -20,7 +20,6 @@ package org.apache.tools.zip; import java.io.IOException; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/org/apache/tools/zip/ZipEncodingHelper.java b/src/main/org/apache/tools/zip/ZipEncodingHelper.java index be6b0ecbbc..014debc944 100644 --- a/src/main/org/apache/tools/zip/ZipEncodingHelper.java +++ b/src/main/org/apache/tools/zip/ZipEncodingHelper.java @@ -18,10 +18,11 @@ package org.apache.tools.zip; +import org.apache.tools.ant.types.CharSet; + import java.nio.Buffer; import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -155,15 +156,15 @@ static ByteBuffer growBuffer(final ByteBuffer b, final int newCapacity) { on.put(b); return on; } - + /** * Prepares a buffer to be read after writing. - * + * * @param b The buffer */ static void prepareBufferForRead(final Buffer b) { - // ByteBuffer has overridden methods in java 11 but not in java 8 - // so the Buffer is significant to get java 8 compatible classes + // ByteBuffer has overridden methods in Java 9+ + // use Buffer for Java 8 compatibility b.limit(b.position()); b.rewind(); } @@ -200,12 +201,7 @@ static void appendSurrogate(final ByteBuffer bb, final char c) { /** * name of the encoding UTF-8 */ - static final String UTF8 = "UTF8"; - - /** - * variant name of the encoding UTF-8 used for comparisons. - */ - private static final String UTF_DASH_8 = "utf-8"; + static final String UTF8 = StandardCharsets.UTF_8.name(); /** * name of the encoding UTF-8 @@ -215,47 +211,48 @@ static void appendSurrogate(final ByteBuffer bb, final char c) { /** * Instantiates a zip encoding. * - * @param name The name of the zip encoding. Specify {@code null} for - * the platform's default encoding. + * @param name The non-null name of the zip encoding. + * Specify "" for the platform encoding. + * NB! {@code null} is permitted for backwards compatibility. * @return A zip encoding for the given encoding name. */ public static ZipEncoding getZipEncoding(final String name) { + return (name == null && !isUTF8("")) ? new FallbackZipEncoding() + : getZipEncoding(new CharSet(name)); + } - // fallback encoding is good enough for utf-8. - if (isUTF8(name)) { + /** + * Instantiates a zip encoding. + * + * @param cs The charset of the zip encoding. + * @return A zip encoding for the given encoding name. + */ + public static ZipEncoding getZipEncoding(final CharSet cs) { + // fallback encoding is good enough for UTF-8. + if (isUTF8(cs)) { return UTF8_ZIP_ENCODING; } - if (name == null) { - return new FallbackZipEncoding(); - } - - final SimpleEncodingHolder h = simpleEncodings.get(name); - - if (h != null) { - return h.getEncoding(); - } - - try { - - final Charset cs = Charset.forName(name); - return new NioZipEncoding(cs); - - } catch (final UnsupportedCharsetException e) { - return new FallbackZipEncoding(name); - } + final SimpleEncodingHolder h = simpleEncodings.get(cs.getValue()); + return (h == null) ? new NioZipEncoding(cs.getCharset()) : h.getEncoding(); } /** - * Whether a given encoding - or the platform's default encoding - * if the parameter is null - is UTF-8. + * Whether a given encoding is UTF-8. + * + * @param encoding The non-null name of an encoding. + * Specify "" for platform encoding */ static boolean isUTF8(String encoding) { - if (encoding == null) { - // check platform's default encoding - encoding = System.getProperty("file.encoding"); - } - return UTF8.equalsIgnoreCase(encoding) - || UTF_DASH_8.equalsIgnoreCase(encoding); + return isUTF8(new CharSet(encoding)); + } + + /** + * Whether a given charset is UTF-8. + * + * @param charSet a CharSet + */ + static boolean isUTF8(CharSet charSet) { + return charSet.equivalent(CharSet.getUtf8()); } } diff --git a/src/main/org/apache/tools/zip/ZipFile.java b/src/main/org/apache/tools/zip/ZipFile.java index dfb6bcf90c..d55abf4da1 100644 --- a/src/main/org/apache/tools/zip/ZipFile.java +++ b/src/main/org/apache/tools/zip/ZipFile.java @@ -18,6 +18,8 @@ package org.apache.tools.zip; +import org.apache.tools.ant.types.CharSet; + import static org.apache.tools.zip.ZipConstants.DWORD; import static org.apache.tools.zip.ZipConstants.SHORT; import static org.apache.tools.zip.ZipConstants.WORD; @@ -30,6 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -105,9 +108,9 @@ private static final class OffsetEntry { *

For a list of possible values see * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html. - * Defaults to the platform's default character encoding.

+ * Defaults to the platform character encoding.

*/ - private final String encoding; + private final Charset charset; /** * The zip encoding to use for filenames and the file comment. @@ -141,27 +144,27 @@ private static final class OffsetEntry { private final byte[] SHORT_BUF = new byte[SHORT]; /** - * Opens the given file for reading, assuming the platform's - * native encoding for file names. + * Opens the given file for reading, assuming the platform + * encoding for file names. * * @param f the archive. * * @throws IOException if an error occurs while reading the file. */ public ZipFile(final File f) throws IOException { - this(f, null); + this(f, Charset.defaultCharset()); } /** - * Opens the given file for reading, assuming the platform's - * native encoding for file names. + * Opens the given file for reading, assuming the platform + * encoding for file names. * * @param name name of the archive. * * @throws IOException if an error occurs while reading the file. */ public ZipFile(final String name) throws IOException { - this(new File(name), null); + this(new File(name), Charset.defaultCharset()); } /** @@ -170,12 +173,25 @@ public ZipFile(final String name) throws IOException { * * @param name name of the archive. * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * for the platform encoding * * @throws IOException if an error occurs while reading the file. */ public ZipFile(final String name, final String encoding) throws IOException { - this(new File(name), encoding, true); + this(new File(name), Charset.forName(encoding), true); + } + + /** + * Opens the given file for reading, assuming the specified + * encoding for file names, scanning unicode extra fields. + * + * @param name name of the archive. + * @param charset the Charset to use for file names + * + * @throws IOException if an error occurs while reading the file. + */ + public ZipFile(final String name, final Charset charset) throws IOException { + this(new File(name), charset, true); } /** @@ -184,12 +200,26 @@ public ZipFile(final String name, final String encoding) throws IOException { * * @param f the archive. * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * for the platform encoding * * @throws IOException if an error occurs while reading the file. */ public ZipFile(final File f, final String encoding) throws IOException { - this(f, encoding, true); + this(f, Charset.forName(encoding), true); + } + + /** + * Opens the given file for reading, assuming the specified + * encoding for file names and scanning for unicode extra fields. + * + * @param f the archive. + * @param charset the encoding to use for file names, use null + * for the platform encoding + * + * @throws IOException if an error occurs while reading the file. + */ + public ZipFile(final File f, final Charset charset) throws IOException { + this(f, charset, true); } /** @@ -198,17 +228,34 @@ public ZipFile(final File f, final String encoding) throws IOException { * * @param f the archive. * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * for the platform encoding * @param useUnicodeExtraFields whether to use InfoZIP Unicode * Extra Fields (if present) to set the file names. * * @throws IOException if an error occurs while reading the file. */ public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields) + throws IOException { + this(f, Charset.forName(encoding), useUnicodeExtraFields); + } + + /** + * Opens the given file for reading, assuming the specified + * encoding for file names. + * + * @param f the archive. + * @param charset the Charset to use for file names, use null + * for the platform encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode + * Extra Fields (if present) to set the file names. + * + * @throws IOException if an error occurs while reading the file. + */ + public ZipFile(final File f, final Charset charset, final boolean useUnicodeExtraFields) throws IOException { this.archiveName = f.getAbsolutePath(); - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); + this.charset = charset; + this.zipEncoding = ZipEncodingHelper.getZipEncoding(getCharSet()); this.useUnicodeExtraFields = useUnicodeExtraFields; archive = new RandomAccessFile(f, "r"); boolean success = false; @@ -230,12 +277,17 @@ public ZipFile(final File f, final String encoding, final boolean useUnicodeExtr } /** - * The encoding to use for filenames and the file comment. - * - * @return null if using the platform's default character encoding. + * @return the CharSet to use for filenames and the file comment. + */ + public CharSet getCharSet() { + return new CharSet(charset.name()); + } + + /** + * @return the encoding to use for filenames and the file comment. */ public String getEncoding() { - return encoding; + return charset.name(); } /** diff --git a/src/main/org/apache/tools/zip/ZipOutputStream.java b/src/main/org/apache/tools/zip/ZipOutputStream.java index 75acf5927e..ed73b2a220 100644 --- a/src/main/org/apache/tools/zip/ZipOutputStream.java +++ b/src/main/org/apache/tools/zip/ZipOutputStream.java @@ -18,6 +18,8 @@ package org.apache.tools.zip; +import org.apache.tools.ant.types.CharSet; + import static org.apache.tools.zip.ZipConstants.DATA_DESCRIPTOR_MIN_VERSION; import static org.apache.tools.zip.ZipConstants.DWORD; import static org.apache.tools.zip.ZipConstants.INITIAL_VERSION; @@ -140,10 +142,16 @@ public class ZipOutputStream extends FilterOutputStream { */ public static final int STORED = java.util.zip.ZipEntry.STORED; + /** + * default charset for file names and comment. + */ + private static final CharSet DEFAULT_CHARSET = CharSet.getDefault(); + /** * default encoding for file names and comment. */ - static final String DEFAULT_ENCODING = null; + @Deprecated + static final String DEFAULT_ENCODING = DEFAULT_CHARSET.getValue(); /** * General purpose flag, which indicates that filenames are @@ -255,21 +263,21 @@ public class ZipOutputStream extends FilterOutputStream { *

For a list of possible values see * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html. - * Defaults to the platform's default character encoding.

+ * Defaults to the platform character encoding.

* * @since 1.3 */ - private String encoding = null; + private CharSet charSet = CharSet.getDefault(); /** * The zip encoding to use for filenames and the file comment. *

* This field is of internal use and will be set in {@link - * #setEncoding(String)}. + * #setCharSet(CharSet)}. *

*/ private ZipEncoding zipEncoding = - ZipEncodingHelper.getZipEncoding(DEFAULT_ENCODING); + ZipEncodingHelper.getZipEncoding(DEFAULT_CHARSET); // CheckStyle:VisibilityModifier OFF - bc @@ -382,14 +390,28 @@ public boolean isSeekable() { *

For a list of possible values see * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html. - * Defaults to the platform's default character encoding.

+ * Defaults to the platform character encoding.

* @param encoding the encoding value * @since 1.3 */ public void setEncoding(final String encoding) { - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - if (useUTF8Flag && !ZipEncodingHelper.isUTF8(encoding)) { + setCharSet(new CharSet(encoding)); + } + + /** + * The charset to use for filenames and the file comment. + * + *

For a list of possible values see + * + * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html + * . + * Defaults to the platform character encoding.

+ * @param charSet the encoding value + */ + public void setCharSet(final CharSet charSet) { + this.charSet = charSet; + this.zipEncoding = ZipEncodingHelper.getZipEncoding(charSet); + if (useUTF8Flag && !ZipEncodingHelper.isUTF8(charSet)) { useUTF8Flag = false; } } @@ -397,12 +419,21 @@ public void setEncoding(final String encoding) { /** * The encoding to use for filenames and the file comment. * - * @return null if using the platform's default character encoding. + * @return null if using the platform character encoding. * * @since 1.3 */ public String getEncoding() { - return encoding; + return charSet.getValue(); + } + + /** + * The encoding to use for filenames and the file comment. + * + * @return null if using the platform character encoding. + */ + public CharSet getCharSet() { + return charSet; } /** @@ -414,7 +445,7 @@ public String getEncoding() { * @param b boolean */ public void setUseLanguageEncodingFlag(boolean b) { - useUTF8Flag = b && ZipEncodingHelper.isUTF8(encoding); + useUTF8Flag = b && ZipEncodingHelper.isUTF8(charSet); } /** @@ -1423,7 +1454,7 @@ protected static byte[] toDosTime(long t) { protected byte[] getBytes(String name) throws ZipException { try { ByteBuffer b = - ZipEncodingHelper.getZipEncoding(encoding).encode(name); + ZipEncodingHelper.getZipEncoding(charSet).encode(name); byte[] result = new byte[b.limit()]; System.arraycopy(b.array(), b.arrayOffset(), result, 0, result.length); diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java index 9c71eb9bb5..ec3b5987ea 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java @@ -24,11 +24,10 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import org.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.CharSet; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -69,16 +68,17 @@ public void testLogBlankEcho() { @Test public void testLogUTF8Echo() throws IOException { File removeThis = folder.newFile("abc.txt"); - Charset cs = StandardCharsets.UTF_8; + CharSet cs = CharSet.getUtf8(); String msg = "\u00e4\u00a9"; echo.setTaskName("testLogUTF8Echo"); echo.setMessage(msg); echo.setFile(removeThis); - echo.setEncoding(cs.name()); + echo.setCharSet(cs); echo.execute(); - assertEquals(msg, readFully(new InputStreamReader(new FileInputStream(removeThis), cs))); + assertEquals(msg, readFully(new InputStreamReader(new FileInputStream(removeThis), + cs.getCharset()))); } private class EchoTestLogger extends DefaultLogger { diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/modules/LinkTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/modules/LinkTest.java index 6492ab72f8..14e576d9a6 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/modules/LinkTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/modules/LinkTest.java @@ -782,7 +782,7 @@ public void testReleaseInfoAddFileWithCharset() ImageStructure image = verifyImageBuiltNormally(); File release = new File(image.root, "release"); - // Using FileReader here since 'release' file is in platform's charset. + // Using FileReader here since 'release' file is in platform charset. try (BufferedReader reader = new BufferedReader( new FileReader(release))) { diff --git a/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java b/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java index d931ae0a25..d92052a5c5 100644 --- a/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java +++ b/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java @@ -233,7 +233,7 @@ public void testEncodingOfIncludesFile() throws IOException { PatternSet.PatternFileNameEntry ne = (PatternSet.PatternFileNameEntry) p.createIncludesFile(); ne.setName(testFile.getAbsolutePath()); - ne.setEncoding(cs.name()); + ne.setCharSet(new CharSet(cs.name())); assertArrayEquals(new String[] {"\u00e4"}, p.getIncludePatterns(project)); } } diff --git a/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java b/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java index 4b884338ce..bd9b72d04a 100644 --- a/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java +++ b/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java @@ -19,6 +19,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildFileRule; +import org.apache.tools.ant.types.CharSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.Reference; import org.junit.After; @@ -52,7 +53,7 @@ public void tearDown() { public void testEmptyElementSetEncodingThenRefid() { thrown.expect(BuildException.class); thrown.expectMessage("You must not specify more than one attribute when using refid"); - rl.setEncoding("foo"); + rl.setCharSet(CharSet.getAscii()); rl.setRefid(new Reference(buildRule.getProject(), "dummyref")); } @@ -61,7 +62,7 @@ public void testEmptyElementSetRefidThenEncoding() { thrown.expect(BuildException.class); thrown.expectMessage("You must not specify more than one attribute when using refid"); rl.setRefid(new Reference(buildRule.getProject(), "dummyref")); - rl.setEncoding("foo"); + rl.setCharSet(CharSet.getAscii()); } @Test diff --git a/src/tests/junit/org/apache/tools/zip/UTF8ZipFilesTest.java b/src/tests/junit/org/apache/tools/zip/UTF8ZipFilesTest.java index fe5eccdb77..4bbbef1fad 100644 --- a/src/tests/junit/org/apache/tools/zip/UTF8ZipFilesTest.java +++ b/src/tests/junit/org/apache/tools/zip/UTF8ZipFilesTest.java @@ -25,20 +25,29 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.zip.CRC32; + +import org.apache.tools.ant.types.CharSet; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; public class UTF8ZipFilesTest { - private static final String UTF_8 = "utf-8"; - private static final String CP437 = "cp437"; - private static final String US_ASCII = "US-ASCII"; + private static final CharSet UTF_8 = CharSet.getUtf8(); + private static final CharSet CP437 = new CharSet("cp437"); + private static final CharSet US_ASCII = CharSet.getAscii(); private static final String ASCII_TXT = "ascii.txt"; private static final String EURO_FOR_DOLLAR_TXT = "\u20AC_for_Dollar.txt"; private static final String OIL_BARREL_TXT = "\u00D6lf\u00E4sser.txt"; + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + private File file; + @Test public void testUtf8FileRoundtripExplicitUnicodeExtra() throws IOException { @@ -93,7 +102,7 @@ public void testZipFileReadsUnicodeFields() throws IOException { ZipFile zf = null; try { createTestFile(file, US_ASCII, false, true); - zf = new ZipFile(file, US_ASCII, true); + zf = new ZipFile(file, US_ASCII.getCharset(), true); assertCanRead(zf, ASCII_TXT); assertCanRead(zf, EURO_FOR_DOLLAR_TXT); assertCanRead(zf, OIL_BARREL_TXT); @@ -105,30 +114,22 @@ public void testZipFileReadsUnicodeFields() throws IOException { } } - private static void testFileRoundtrip(String encoding, boolean withEFS, - boolean withExplicitUnicodeExtra) - throws IOException { - - File file = File.createTempFile(encoding + "-test", ".zip"); - try { - createTestFile(file, encoding, withEFS, withExplicitUnicodeExtra); - testFile(file, encoding); - } finally { - if (file.exists()) { - file.delete(); - } - } + private void testFileRoundtrip(CharSet encoding, boolean withEFS, + boolean withExplicitUnicodeExtra) throws IOException { + File file = folder.newFile(encoding.getValue() + "-test.zip"); + createTestFile(file, encoding, withEFS, withExplicitUnicodeExtra); + testFile(file, encoding); } - private static void createTestFile(File file, String encoding, + private static void createTestFile(File file, CharSet charSet, boolean withEFS, boolean withExplicitUnicodeExtra) throws IOException { - ZipEncoding zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); + ZipEncoding zipEncoding = ZipEncodingHelper.getZipEncoding(charSet); try (ZipOutputStream zos = new ZipOutputStream(file)) { - zos.setEncoding(encoding); + zos.setCharSet(charSet); zos.setUseLanguageEncodingFlag(withEFS); zos.setCreateUnicodeExtraFields(withExplicitUnicodeExtra ? ZipOutputStream.UnicodeExtraFieldPolicy.NEVER @@ -185,11 +186,11 @@ private static void createTestFile(File file, String encoding, } } - private static void testFile(File file, String encoding) + private static void testFile(File file, CharSet encoding) throws IOException { ZipFile zf = null; try { - zf = new ZipFile(file, encoding, false); + zf = new ZipFile(file, encoding.getCharset(), false); for (ZipEntry ze : Collections.list(zf.getEntries())) { if (ze.getName().endsWith("sser.txt")) { assertUnicodeName(ze, OIL_BARREL_TXT, encoding); @@ -213,13 +214,13 @@ private static UnicodePathExtraField findUniCodePath(ZipEntry ze) { private static void assertUnicodeName(ZipEntry ze, String expectedName, - String encoding) + CharSet charSet) throws IOException { if (!expectedName.equals(ze.getName())) { UnicodePathExtraField ucpf = findUniCodePath(ze); assertNotNull(ucpf); - ZipEncoding enc = ZipEncodingHelper.getZipEncoding(encoding); + ZipEncoding enc = ZipEncodingHelper.getZipEncoding(charSet); ByteBuffer ne = enc.encode(ze.getName()); CRC32 crc = new CRC32(); diff --git a/src/tests/junit/org/apache/tools/zip/ZipEncodingTest.java b/src/tests/junit/org/apache/tools/zip/ZipEncodingTest.java index a16ac83614..aebe9d41f4 100644 --- a/src/tests/junit/org/apache/tools/zip/ZipEncodingTest.java +++ b/src/tests/junit/org/apache/tools/zip/ZipEncodingTest.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import org.apache.tools.ant.types.CharSet; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -45,13 +46,13 @@ public class ZipEncodingTest { @Test public void testSimpleCp437Encoding() throws IOException { - doSimpleEncodingTest("Cp437", null); + doSimpleEncodingTest(new CharSet("Cp437"), null); } @Test public void testSimpleCp850Encoding() throws IOException { - doSimpleEncodingTest("Cp850", null); + doSimpleEncodingTest(new CharSet("Cp850"), null); } @Test @@ -108,7 +109,7 @@ public void testNioCp1252Encoding() throws IOException { (byte) 0xF9, (byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF}; - doSimpleEncodingTest("Cp1252", b); + doSimpleEncodingTest(new CharSet("Cp1252"), b); } private static void assertByteEquals(byte[] expected, ByteBuffer actual) { @@ -121,10 +122,10 @@ private static void assertByteEquals(byte[] expected, ByteBuffer actual) { } - private void doSimpleEncodingTest(String name, byte[] testBytes) + private void doSimpleEncodingTest(CharSet charSet, byte[] testBytes) throws IOException { - ZipEncoding enc = ZipEncodingHelper.getZipEncoding(name); + ZipEncoding enc = ZipEncodingHelper.getZipEncoding(charSet); if (testBytes == null) {