You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2003/08/24 12:50:58 UTC
cvs commit: jakarta-commons/collections/src/java/org/apache/commons/collections ExtendedProperties.java
scolebourne 2003/08/24 03:50:58
Modified: collections/src/test/org/apache/commons/collections
TestExtendedProperties.java
collections/src/java/org/apache/commons/collections
ExtendedProperties.java
Log:
Fix escaping behaviour of save method
bug 19061, from Mohan Kishore, reported by Dariusz Wojtas
Revision Changes Path
1.5 +75 -8 jakarta-commons/collections/src/test/org/apache/commons/collections/TestExtendedProperties.java
Index: TestExtendedProperties.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestExtendedProperties.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- TestExtendedProperties.java 21 Sep 2001 03:15:15 -0000 1.4
+++ TestExtendedProperties.java 24 Aug 2003 10:50:58 -0000 1.5
@@ -7,7 +7,7 @@
*
* The Apache Software License, Version 1.1
*
- * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
+ * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,12 +65,15 @@
import junit.framework.TestCase;
import junit.framework.TestSuite;
+import java.io.*;
+
/**
- * Tests some basic functions of the ExtendedProperties
- * class
+ * Tests some basic functions of the ExtendedProperties
+ * class
*
- * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
- * @version $Id$
+ * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
+ * @author Mohan Kishore
+ * @version $Id$
*/
public class TestExtendedProperties extends TestCase
{
@@ -151,5 +154,69 @@
eprop.setProperty("db", "${applicationRoot}/db/hypersonic");
String dbProp = "/home/applicationRoot/db/hypersonic";
assertTrue("Checking interpolated variable", eprop.getString("db").equals(dbProp));
+ }
+
+ public void testSaveAndLoad() {
+ ExtendedProperties ep1 = new ExtendedProperties();
+ ExtendedProperties ep2 = new ExtendedProperties();
+
+ try {
+ /* initialize value:
+ one=Hello\World
+ two=Hello\,World
+ three=Hello,World
+ */
+ String s1 = "one=Hello\\World\ntwo=Hello\\,World\nthree=Hello,World";
+ byte[] bytes = s1.getBytes();
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ep1.load(bais);
+ assertEquals("Back-slashes not interpreted properly",
+ "Hello\\World", ep1.getString("one"));
+ assertEquals("Escaped commas not interpreted properly",
+ "Hello,World", ep1.getString("two"));
+ assertEquals("Commas not interpreted properly",
+ 2, ep1.getVector("three").size());
+ assertEquals("Commas not interpreted properly",
+ "Hello", ep1.getVector("three").get(0));
+ assertEquals("Commas not interpreted properly",
+ "World", ep1.getVector("three").get(1));
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ep1.save(baos, null);
+ bytes = baos.toByteArray();
+ bais = new ByteArrayInputStream(bytes);
+ ep2.load(bais);
+ assertEquals("Back-slash not same after being saved and loaded",
+ ep1.getString("one"), ep2.getString("one"));
+ assertEquals("Escaped comma not same after being saved and loaded",
+ ep1.getString("two"), ep2.getString("two"));
+ assertEquals("Comma not same after being saved and loaded",
+ ep1.getString("three"), ep2.getString("three"));
+ } catch (IOException ioe) {
+ fail("There was an exception saving and loading the EP");
+ }
+ }
+
+ public void testTrailingBackSlash() {
+ ExtendedProperties ep1 = new ExtendedProperties();
+
+ try {
+ /*
+ initialize using:
+ one=ONE
+ two=TWO \\
+ three=THREE
+ */
+ String s1 = "one=ONE\ntwo=TWO \\\\\nthree=THREE";
+ byte[] bytes = s1.getBytes();
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ep1.load(bais);
+ assertEquals("Trailing back-slashes not interpreted properly",
+ 3, ep1.size());
+ assertEquals("Back-slash not escaped properly",
+ "TWO \\", ep1.getString("two"));
+ } catch (IOException ioe) {
+ fail("There was an exception loading the EP");
+ }
}
}
1.13 +65 -8 jakarta-commons/collections/src/java/org/apache/commons/collections/ExtendedProperties.java
Index: ExtendedProperties.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/ExtendedProperties.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- ExtendedProperties.java 20 Jun 2003 07:59:59 -0000 1.12
+++ ExtendedProperties.java 24 Aug 2003 10:50:58 -0000 1.13
@@ -103,6 +103,9 @@
* the comma.
* </li>
* <li>
+ * Backslashes are escaped by using two consecutive backslashes i.e. \\
+ * </li>
+ * <li>
* If a <i>key</i> is used more than once, the values are appended
* like if they were on the same line separated with commas.
* </li>
@@ -170,6 +173,7 @@
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
* @author Janek Bogucki
+ * @author Mohan Kishore
*/
public class ExtendedProperties extends Hashtable {
@@ -248,6 +252,57 @@
return result.toString();
}
+
+ /**
+ * Inserts a backslash before every comma and backslash.
+ */
+ private static String escape(String s) {
+ StringBuffer buf = new StringBuffer(s);
+ for (int i=0; i < buf.length();i++) {
+ char c = buf.charAt(i);
+ if (c == ',' || c == '\\') {
+ buf.insert(i, '\\');
+ i++;
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Removes a backslash from every pair of backslashes.
+ */
+ private static String unescape(String s) {
+ StringBuffer buf = new StringBuffer(s);
+ for (int i=0; i < buf.length()-1;i++) {
+ char c1 = buf.charAt(i);
+ char c2 = buf.charAt(i+1);
+ if (c1 == '\\' && c2 == '\\') {
+ buf.deleteCharAt(i);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Counts the number of successive times 'ch' appears in the
+ * 'line' before the position indicated by the 'index'.
+ */
+ private static int countPreceding(String line, int index, char ch) {
+ int i;
+ for (i = index-1; i >= 0; i--) {
+ if (line.charAt(i) != ch) break;
+ }
+ return index-1-i;
+ }
+
+ /**
+ * Checks if the line ends with odd number of backslashes
+ */
+ private static boolean endsWithSlash(String line) {
+ if (!line.endsWith("\\")) return false;
+
+ return (countPreceding(line, line.length()-1, '\\') % 2 == 0);
+ }
/**
* This class is used to read properties lines. These lines do
@@ -284,7 +339,7 @@
String line = readLine().trim();
if ((line.length() != 0) && (line.charAt(0) != '#'))
{
- if (line.endsWith("\\"))
+ if (endsWithSlash(line))
{
line = line.substring(0, line.length() - 1);
buffer.append(line);
@@ -350,7 +405,7 @@
while (hasMoreTokens())
{
String token = super.nextToken();
- if (token.endsWith("\\"))
+ if (endsWithSlash(token))
{
buffer.append(token.substring(0, token.length() - 1));
buffer.append(DELIMITER);
@@ -678,7 +733,7 @@
* just goes in rather than risking vectorization
* if it contains an escaped comma
*/
- addStringProperty(key,value);
+ addStringProperty(key,unescape(value));
}
}
else
@@ -692,7 +747,9 @@
* to perform operations with configuration
* in a definite order it will be possible.
*/
-
+ if (token instanceof String) {
+ token = unescape((String)token);
+ }
addPropertyDirect( key, token );
}
}
@@ -821,7 +878,7 @@
StringBuffer currentOutput = new StringBuffer();
currentOutput.append(key);
currentOutput.append("=");
- currentOutput.append((String) value);
+ currentOutput.append(escape((String) value));
theWrtr.println(currentOutput.toString());
}
else if(value instanceof Vector)
@@ -835,7 +892,7 @@
StringBuffer currentOutput = new StringBuffer();
currentOutput.append(key);
currentOutput.append("=");
- currentOutput.append(currentElement);
+ currentOutput.append(escape(currentElement));
theWrtr.println(currentOutput.toString());
}
}