ebourg 2004/06/03 08:32:46
Modified: configuration/src/java/org/apache/commons/configuration
AbstractConfiguration.java
BasePropertiesConfiguration.java
configuration/conf test.properties
configuration/src/test/org/apache/commons/configuration
TestPropertiesConfiguration.java
Log:
Fixed Bug 27775, the list separator (comma) can be escaped with the \ character
Revision Changes Path
1.9 +7 -16
jakarta-commons/configuration/src/java/org/apache/commons/configuration/AbstractConfiguration.java
Index: AbstractConfiguration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/AbstractConfiguration.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- AbstractConfiguration.java 4 May 2004 22:27:10 -0000 1.8
+++ AbstractConfiguration.java 3 Jun 2004 15:32:46 -0000 1.9
@@ -42,18 +42,13 @@
/** how big the initial arraylist for splitting up name value pairs */
private static final int INITIAL_LIST_SIZE = 2;
-
/** start token */
protected static final String START_TOKEN = "${";
/** end token */
protected static final String END_TOKEN = "}";
- /**
- * Empty constructor.
- */
- public AbstractConfiguration()
- {
- }
+ /** The property delimiter used while parsing (a comma). */
+ protected static final char DELIMITER = ',';
/**
* Add a property to the configuration. If it already exists then the value
@@ -76,8 +71,7 @@
{
if (token instanceof String)
{
- for(Iterator it = processString((String) token).iterator();
- it.hasNext();)
+ for(Iterator it = processString((String) token).iterator();
it.hasNext();)
{
addPropertyDirect(key, it.next());
}
@@ -238,7 +232,7 @@
{
List retList = new ArrayList(INITIAL_LIST_SIZE);
- if (token.indexOf(PropertiesTokenizer.DELIMITER) > 0)
+ if (token.indexOf(DELIMITER) > 0)
{
PropertiesTokenizer tokenizer = new PropertiesTokenizer(token);
@@ -1300,11 +1294,8 @@
* separator is "," but commas into the property value are escaped
* using the backslash in front.
*/
- class PropertiesTokenizer extends StringTokenizer
+ static class PropertiesTokenizer extends StringTokenizer
{
- /** The property delimiter used while parsing (a comma). */
- static final String DELIMITER = ",";
-
/**
* Constructor.
*
@@ -1312,7 +1303,7 @@
*/
public PropertiesTokenizer(String string)
{
- super(string, DELIMITER);
+ super(string, String.valueOf(DELIMITER));
}
/**
1.8 +168 -56
jakarta-commons/configuration/src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java
Index: BasePropertiesConfiguration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- BasePropertiesConfiguration.java 2 Jun 2004 16:42:24 -0000 1.7
+++ BasePropertiesConfiguration.java 3 Jun 2004 15:32:46 -0000 1.8
@@ -30,6 +30,7 @@
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.exception.NestableRuntimeException;
/**
* loads the configuration from a properties file. <p>
@@ -101,7 +102,7 @@
*
* # commas may be escaped in tokens
* commas.excaped = Hi\, what'up?
- *
+ *
* # properties can reference other properties
* base.prop = /base
* first.prop = ${base.prop}/first
@@ -150,19 +151,17 @@
* encoding.
*
* @param input An InputStream.
- * @param enc An encoding.
+ * @param encoding An encoding.
* @exception ConfigurationException
*/
- public synchronized void load(InputStream input, String enc)
- throws ConfigurationException
+ public synchronized void load(InputStream input, String encoding) throws
ConfigurationException
{
PropertiesReader reader = null;
- if (enc != null)
+ if (encoding != null)
{
try
{
- reader =
- new PropertiesReader(new InputStreamReader(input, enc));
+ reader = new PropertiesReader(new InputStreamReader(input,
encoding));
}
catch (UnsupportedEncodingException e)
{
@@ -174,46 +173,47 @@
{
reader = new PropertiesReader(new InputStreamReader(input));
}
+
try {
- while (true)
- {
- String line = reader.readProperty();
-
- if (line == null)
- {
- break; // EOF
- }
-
- int equalSign = line.indexOf('=');
- if (equalSign > 0)
+ while (true)
{
- String key = line.substring(0, equalSign).trim();
- String value = line.substring(equalSign + 1).trim();
+ String line = reader.readProperty();
- // Though some software (e.g. autoconf) may produce
- // empty values like foo=\n, emulate the behavior of
- // java.util.Properties by setting the value to the
- // empty string.
+ if (line == null)
+ {
+ break; // EOF
+ }
- if (StringUtils.isNotEmpty(getInclude())
- && key.equalsIgnoreCase(getInclude()))
+ int equalSign = line.indexOf('=');
+ if (equalSign > 0)
{
- if (getIncludesAllowed())
+ String key = line.substring(0, equalSign).trim();
+ String value = line.substring(equalSign + 1).trim();
+
+ // Though some software (e.g. autoconf) may produce
+ // empty values like foo=\n, emulate the behavior of
+ // java.util.Properties by setting the value to the
+ // empty string.
+
+ if (StringUtils.isNotEmpty(getInclude())
+ && key.equalsIgnoreCase(getInclude()))
{
- String [] files = StringUtils.split(value, ",");
- for (int cnt = 0 ; cnt < files.length ; cnt++)
+ if (getIncludesAllowed())
{
- load(getPropertyStream(files[cnt].trim()));
+ String [] files = StringUtils.split(value, DELIMITER);
+ for (int i = 0; i < files.length; i++)
+ {
+ load(getPropertyStream(files[i].trim()));
+ }
}
}
- }
- else
- {
- addProperty(key, StringEscapeUtils.unescapeJava(value));
+ else
+ {
+ addProperty(key, unescapeJava(value));
+ }
}
}
}
- }
catch (IOException ioe){
throw new ConfigurationException("Could not load configuration from
input stream.",ioe);
}
@@ -226,8 +226,7 @@
* @param filename name of the properties file
* @throws ConfigurationException
*/
- public void save(String filename)
- throws ConfigurationException
+ public void save(String filename) throws ConfigurationException
{
PropertiesWriter out = null;
File file = new File(filename);
@@ -240,20 +239,20 @@
for (Iterator i = this.getKeys(); i.hasNext();)
{
String key = (String) i.next();
- String value = StringUtils.join(this.getStringArray(key), ",
");
- out.writeProperty(key, value);
+ out.writeProperty(key, this.getStringArray(key));
}
out.flush();
out.close();
}
- catch (IOException ioe){
+ catch (IOException ioe)
+ {
try {
- if (out !=null){
+ if (out != null){
out.close();
}
}
catch (IOException ioe2){
-
+
}
throw new ConfigurationException("Could not save to file " +
filename,ioe);
}
@@ -309,8 +308,7 @@
* backslash sign a the end of the line. This is used to
* concatenate multiple lines for readability.
*/
- class PropertiesReader
- extends LineNumberReader
+ class PropertiesReader extends LineNumberReader
{
/**
* Constructor.
@@ -331,8 +329,7 @@
*
* @exception IOException
*/
- public String readProperty()
- throws IOException
+ public String readProperty() throws IOException
{
StringBuffer buffer = new StringBuffer();
@@ -371,8 +368,7 @@
/**
* This class is used to write properties lines.
*/
- class PropertiesWriter
- extends FileWriter
+ class PropertiesWriter extends FileWriter
{
/**
* Constructor.
@@ -380,8 +376,7 @@
* @param file the proerties file
* @throws IOException
*/
- public PropertiesWriter(File file)
- throws IOException
+ public PropertiesWriter(File file) throws IOException
{
super(file);
}
@@ -393,25 +388,142 @@
* @param value
* @exception IOException
*/
- public void writeProperty(String key, String value)
- throws IOException
+ public void writeProperty(String key, String value) throws IOException
{
write(key);
write(" = ");
- write(value != null ? StringEscapeUtils.escapeJava(value) : "");
+ if (value != null)
+ {
+ String v = StringEscapeUtils.escapeJava(value);
+ v = StringUtils.replace(v, String.valueOf(DELIMITER), "\\" +
DELIMITER);
+ write(v);
+ }
+
write('\n');
}
/**
+ * Write a property.
+ *
+ * @param key The key of the property
+ * @param values The array of values of the property
+ */
+ public void writeProperty(String key, String[] values) throws IOException
+ {
+ for (int i = 0; i < values.length; i++)
+ {
+ writeProperty(key, values[i]);
+ }
+ }
+
+ /**
* Write a comment.
*
* @param comment
* @exception IOException
*/
- public void writeComment(String comment)
- throws IOException
+ public void writeComment(String comment) throws IOException
{
write("# " + comment + "\n");
}
} // class PropertiesWriter
+
+ /**
+ * <p>Unescapes any Java literals found in the <code>String</code> to a
+ * <code>Writer</code>.</p> This is a slightly modified version of the
+ * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't
+ * drop escaped commas (i.e '\,').
+ *
+ * @param str the <code>String</code> to unescape, may be null
+ * @throws IllegalArgumentException if the Writer is <code>null</code>
+ */
+ protected static String unescapeJava(String str) {
+
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuffer out = new StringBuffer(sz);
+ StringBuffer unicode = new StringBuffer(4);
+ boolean hadSlash = false;
+ boolean inUnicode = false;
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ if (inUnicode) {
+ // if in unicode, then we're reading unicode
+ // values in somehow
+ unicode.append(ch);
+ if (unicode.length() == 4) {
+ // unicode now contains the four hex digits
+ // which represents our unicode character
+ try {
+ int value = Integer.parseInt(unicode.toString(), 16);
+ out.append((char) value);
+ unicode.setLength(0);
+ inUnicode = false;
+ hadSlash = false;
+ } catch (NumberFormatException nfe) {
+ throw new NestableRuntimeException("Unable to parse unicode
value: " + unicode, nfe);
+ }
+ }
+ continue;
+ }
+ if (hadSlash) {
+ // handle an escaped value
+ hadSlash = false;
+ switch (ch) {
+ case '\\':
+ out.append('\\');
+ break;
+ case '\'':
+ out.append('\'');
+ break;
+ case '\"':
+ out.append('"');
+ break;
+ case 'r':
+ out.append('\r');
+ break;
+ case 'f':
+ out.append('\f');
+ break;
+ case 't':
+ out.append('\t');
+ break;
+ case 'n':
+ out.append('\n');
+ break;
+ case 'b':
+ out.append('\b');
+ break;
+ case DELIMITER:
+ out.append("\\");
+ out.append(DELIMITER);
+ break;
+ case 'u':
+ {
+ // uh-oh, we're in unicode country....
+ inUnicode = true;
+ break;
+ }
+ default :
+ out.append(ch);
+ break;
+ }
+ continue;
+ } else if (ch == '\\') {
+ hadSlash = true;
+ continue;
+ }
+ out.append(ch);
+ }
+ if (hadSlash) {
+ // then we're in the weird case of a \ at the end of the
+ // string, let's output it anyway.
+ out.append('\\');
+ }
+
+ return out.toString();
+ }
+
}
1.4 +1 -0 jakarta-commons/configuration/conf/test.properties
Index: test.properties
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/conf/test.properties,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- test.properties 24 Feb 2004 13:08:03 -0000 1.3
+++ test.properties 3 Jun 2004 15:32:46 -0000 1.4
@@ -6,6 +6,7 @@
include = include.properties
test.unescape = This \n string \t contains \" escaped \\ characters
+test.unescape.list-separator = This string contains \, an escaped list separator
#
# Other test properties
1.6 +16 -7
jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java
Index: TestPropertiesConfiguration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- TestPropertiesConfiguration.java 27 Feb 2004 17:41:34 -0000 1.5
+++ TestPropertiesConfiguration.java 3 Jun 2004 15:32:46 -0000 1.6
@@ -38,7 +38,6 @@
protected void setUp() throws Exception
{
conf = new PropertiesConfiguration(testProperties);
-
}
public void testSave() throws Exception
@@ -55,9 +54,9 @@
conf.addProperty("array", list);
conf.save(testSavePropertiesFile.getAbsolutePath());
-
+
PropertiesConfiguration checkConfig = new
PropertiesConfiguration(testSavePropertiesFile.getAbsolutePath());
- for (Iterator i = conf.getKeys();i.hasNext();){
+ for (Iterator i = conf.getKeys(); i.hasNext();){
String key = (String)i.next();
assertTrue(checkConfig.containsKey(key));
assertEquals(conf.getString(key),checkConfig.getString(key));
@@ -75,7 +74,6 @@
public void testLoadViaPropertyWithBasePath() throws Exception
{
-
PropertiesConfiguration pc = new PropertiesConfiguration();
pc.setBasePath(testBasePath);
pc.setFileName("test.properties");
@@ -86,7 +84,6 @@
public void testLoadViaPropertyWithBasePath2() throws Exception
{
-
PropertiesConfiguration pc = new PropertiesConfiguration();
pc.setBasePath(testBasePath2);
pc.setFileName("conf/test.properties");
@@ -104,6 +101,18 @@
public void testGetStringWithEscapedChars()
{
- assertEquals("String with escaped characters", "This \n string \t contains
\" escaped \\ characters", conf.getString("test.unescape"));
+ String property = conf.getString("test.unescape");
+ assertEquals("String with escaped characters", "This \n string \t contains
\" escaped \\ characters", property);
+ }
+
+ public void testGetStringWithEscapedComma()
+ {
+ String property = conf.getString("test.unescape.list-separator");
+ assertEquals("String with an escaped list separator", "This string contains
, an escaped list separator", property);
+ }
+
+ public void testUnescapeJava()
+ {
+ assertEquals("test\\,test",
PropertiesConfiguration.unescapeJava("test\\,test"));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]