* Remove dependency of <loadproperties> on StringInputStream * Modify StringInputStream to support encoding * Note that StringInputStream is not being used by any other Ant classes - the sole consumer was LoadProperties which no longer uses it. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@273132 13f79535-47bb-0310-9956-ffa450edef68master
@@ -24,6 +24,8 @@ Fixed bugs: | |||||
Other changes: | Other changes: | ||||
-------------- | -------------- | ||||
* <loadproperties> has a new encoding attribute. | |||||
* <echoproperties> can now create XML output. | * <echoproperties> can now create XML output. | ||||
* <echoproperties> has a new srcfile attribute that can make it read | * <echoproperties> has a new srcfile attribute that can make it read | ||||
@@ -28,6 +28,11 @@ specified outside a target. | |||||
<td valign="top">source file</td> | <td valign="top">source file</td> | ||||
<td valign="top" align="center">Yes</td> | <td valign="top" align="center">Yes</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">encoding</td> | |||||
<td valign="top">encoding to use when loading the file</td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
</table> | </table> | ||||
<p> | <p> | ||||
The LoadProperties task supports nested <a href="../CoreTypes/filterchain.html"> | The LoadProperties task supports nested <a href="../CoreTypes/filterchain.html"> | ||||
@@ -58,8 +58,7 @@ import java.io.InputStream; | |||||
import java.io.StringReader; | import java.io.StringReader; | ||||
/** | /** | ||||
* Wraps a String as an InputStream. Note that data will be lost for | |||||
* characters not in ISO Latin 1, as a simple char->byte mapping is assumed. | |||||
* Wraps a String as an InputStream. | |||||
* | * | ||||
* @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | ||||
*/ | */ | ||||
@@ -68,9 +67,15 @@ public class StringInputStream | |||||
/** Source string, stored as a StringReader */ | /** Source string, stored as a StringReader */ | ||||
private StringReader in; | private StringReader in; | ||||
private String encoding; | |||||
private byte[] slack; | |||||
private int begin; | |||||
/** | /** | ||||
* Composes a stream from a String | * Composes a stream from a String | ||||
* | |||||
* | |||||
* @param source The string to read from. Must not be <code>null</code>. | * @param source The string to read from. Must not be <code>null</code>. | ||||
*/ | */ | ||||
public StringInputStream(String source) { | public StringInputStream(String source) { | ||||
@@ -78,32 +83,88 @@ public class StringInputStream | |||||
} | } | ||||
/** | /** | ||||
* Reads from the Stringreader, returning the same value. Note that | |||||
* data will be lost for characters not in ISO Latin 1. Clients | |||||
* assuming a return value in the range -1 to 255 may even fail on | |||||
* such input. | |||||
* | |||||
* @return the value of the next character in the StringReader | |||||
* | |||||
* @exception IOException if the original StringReader fails to be read | |||||
* Composes a stream from a String with the specified encoding | |||||
* | |||||
* @param source The string to read from. Must not be <code>null</code>. | |||||
* @param encoding The encoding scheme. | |||||
*/ | */ | ||||
public int read() throws IOException { | |||||
return in.read(); | |||||
public StringInputStream(String source, String encoding) { | |||||
in = new StringReader(source); | |||||
this.encoding = encoding; | |||||
} | } | ||||
/** | /** | ||||
* Closes the Stringreader. | |||||
* | |||||
* @exception IOException if the original StringReader fails to be closed | |||||
* Reads from the Stringreader, returning the same value. | |||||
* | |||||
* @return the value of the next character in the StringReader | |||||
* | |||||
* @exception IOException if the original StringReader fails to be read | |||||
*/ | */ | ||||
public void close() throws IOException { | |||||
in.close(); | |||||
public synchronized int read() throws IOException { | |||||
if (in == null) { | |||||
throw new IOException("Stream Closed"); | |||||
} | |||||
byte result; | |||||
if (slack != null && begin < slack.length) { | |||||
result = slack[begin]; | |||||
if (++begin == slack.length) { | |||||
slack = null; | |||||
} | |||||
} else { | |||||
byte[] buf = new byte[1]; | |||||
if (read(buf, 0, 1) <= 0) { | |||||
return -1; | |||||
} | |||||
result = buf[0]; | |||||
} | |||||
if (result < 0) { | |||||
return 256 + result; | |||||
} else { | |||||
return result; | |||||
} | |||||
} | |||||
public synchronized int read(byte[] b, int off, int len) | |||||
throws IOException { | |||||
if (in == null) { | |||||
throw new IOException("Stream Closed"); | |||||
} | |||||
while (slack == null) { | |||||
char[] buf = new char[len]; // might read too much | |||||
int n = in.read(buf); | |||||
if (n == -1) { | |||||
return -1; | |||||
} | |||||
if (n > 0) { | |||||
String s = new String(buf, 0, n); | |||||
if (encoding == null) { | |||||
slack = s.getBytes(); | |||||
} else { | |||||
slack = s.getBytes(encoding); | |||||
} | |||||
begin = 0; | |||||
} | |||||
} | |||||
if (len > slack.length - begin) { | |||||
len = slack.length - begin; | |||||
} | |||||
System.arraycopy(slack, begin, b, off, len); | |||||
if ((begin += len) >= slack.length) { | |||||
slack = null; | |||||
} | |||||
return len; | |||||
} | } | ||||
/** | /** | ||||
* Marks the read limit of the StringReader. | * Marks the read limit of the StringReader. | ||||
* | |||||
* @param limit the maximum limit of bytes that can be read before the | |||||
* | |||||
* @param limit the maximum limit of bytes that can be read before the | |||||
* mark position becomes invalid | * mark position becomes invalid | ||||
*/ | */ | ||||
public synchronized void mark(final int limit) { | public synchronized void mark(final int limit) { | ||||
@@ -114,20 +175,46 @@ public class StringInputStream | |||||
} | } | ||||
} | } | ||||
public synchronized int available() throws IOException { | |||||
if (in == null) { | |||||
throw new IOException("Stream Closed"); | |||||
} | |||||
if (slack != null) { | |||||
return slack.length - begin; | |||||
} | |||||
if (in.ready()) { | |||||
return 1; | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
public boolean markSupported () { | |||||
return false; // would be imprecise | |||||
} | |||||
/** | /** | ||||
* Resets the StringReader. | * Resets the StringReader. | ||||
* | |||||
* | |||||
* @exception IOException if the StringReader fails to be reset | * @exception IOException if the StringReader fails to be reset | ||||
*/ | */ | ||||
public synchronized void reset() throws IOException { | public synchronized void reset() throws IOException { | ||||
if (in == null) { | |||||
throw new IOException("Stream Closed"); | |||||
} | |||||
slack = null; | |||||
in.reset(); | in.reset(); | ||||
} | } | ||||
/** | /** | ||||
* @see InputStream#markSupported | |||||
* Closes the Stringreader. | |||||
* | |||||
* @exception IOException if the original StringReader fails to be closed | |||||
*/ | */ | ||||
public boolean markSupported() { | |||||
return in.markSupported(); | |||||
public synchronized void close() throws IOException { | |||||
in.close(); | |||||
slack = null; | |||||
in = null; | |||||
} | } | ||||
} | } | ||||
@@ -56,12 +56,12 @@ package org.apache.tools.ant.taskdefs; | |||||
import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.types.FilterChain; | import org.apache.tools.ant.types.FilterChain; | ||||
import org.apache.tools.ant.filters.StringInputStream; | |||||
import org.apache.tools.ant.filters.util.ChainReaderHelper; | import org.apache.tools.ant.filters.util.ChainReaderHelper; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileInputStream; | import java.io.FileInputStream; | ||||
import java.io.BufferedInputStream; | import java.io.BufferedInputStream; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
import java.io.Reader; | import java.io.Reader; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -88,6 +88,12 @@ public final class LoadProperties extends Task { | |||||
*/ | */ | ||||
private final Vector filterChains = new Vector(); | private final Vector filterChains = new Vector(); | ||||
/** | |||||
* Encoding to use for filenames, defaults to the platform's default | |||||
* encoding. | |||||
*/ | |||||
private String encoding = null; | |||||
/** | /** | ||||
* Sets the file to load. | * Sets the file to load. | ||||
* | * | ||||
@@ -97,6 +103,21 @@ public final class LoadProperties extends Task { | |||||
this.srcFile = srcFile; | this.srcFile = srcFile; | ||||
} | } | ||||
/** | |||||
* Encoding to use for input, defaults to the platform's default | |||||
* encoding. <p> | |||||
* | |||||
* For a list of possible values see <a href="http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html"> | |||||
* http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html | |||||
* </a>.</p> | |||||
* | |||||
* @param encoding The new Encoding value | |||||
*/ | |||||
public final void setEncoding(final String encoding) { | |||||
this.encoding = encoding; | |||||
} | |||||
/** | /** | ||||
* read in a source file's contents and load them up as Ant properties | * read in a source file's contents and load them up as Ant properties | ||||
* | * | ||||
@@ -127,7 +148,11 @@ public final class LoadProperties extends Task { | |||||
//open up the file | //open up the file | ||||
fis = new FileInputStream(srcFile); | fis = new FileInputStream(srcFile); | ||||
bis = new BufferedInputStream(fis); | bis = new BufferedInputStream(fis); | ||||
instream = new InputStreamReader(bis); | |||||
if (encoding == null) { | |||||
instream = new InputStreamReader(bis); | |||||
} else { | |||||
instream = new InputStreamReader(bis, encoding); | |||||
} | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | ChainReaderHelper crh = new ChainReaderHelper(); | ||||
crh.setBufferSize(size); | crh.setBufferSize(size); | ||||
@@ -143,9 +168,14 @@ public final class LoadProperties extends Task { | |||||
text = text + "\n"; | text = text + "\n"; | ||||
} | } | ||||
final StringInputStream sis = new StringInputStream(text); | |||||
ByteArrayInputStream tis = null; | |||||
if ( encoding == null ) { | |||||
tis = new ByteArrayInputStream(text.getBytes()); | |||||
} else { | |||||
tis = new ByteArrayInputStream(text.getBytes(encoding)); | |||||
} | |||||
final Properties props = new Properties(); | final Properties props = new Properties(); | ||||
props.load(sis); | |||||
props.load(tis); | |||||
final Enumeration e = props.keys(); | final Enumeration e = props.keys(); | ||||
while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
final String key = (String) e.nextElement(); | final String key = (String) e.nextElement(); | ||||
@@ -155,7 +185,7 @@ public final class LoadProperties extends Task { | |||||
project.setNewProperty(key, value); | project.setNewProperty(key, value); | ||||
} | } | ||||
} | } | ||||
sis.close(); | |||||
tis.close(); | |||||
} | } | ||||
} catch (final IOException ioe) { | } catch (final IOException ioe) { | ||||