Fix escaping behaviour of save method

bug 19061, from Mohan Kishore, reported by Dariusz Wojtas


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131114 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stephen Colebourne 2003-08-24 10:50:58 +00:00
parent 084754f692
commit 7bbdeabc05
2 changed files with 140 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/ExtendedProperties.java,v 1.12 2003/06/20 07:59:59 scolebourne Exp $
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/ExtendedProperties.java,v 1.13 2003/08/24 10:50:58 scolebourne Exp $
* ====================================================================
*
* The Apache Software License, Version 1.1
@ -103,6 +103,9 @@ import java.util.Vector;
* 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>
@ -158,7 +161,7 @@ import java.util.Vector;
* it, go ahead and tune it up!
*
* @since Commons Collections 1.0
* @version $Revision: 1.12 $ $Date: 2003/06/20 07:59:59 $
* @version $Revision: 1.13 $ $Date: 2003/08/24 10:50:58 $
*
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
@ -170,6 +173,7 @@ import java.util.Vector;
* @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 @@ public class ExtendedProperties extends Hashtable {
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 @@ public class ExtendedProperties extends Hashtable {
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 @@ public class ExtendedProperties extends Hashtable {
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 @@ public class ExtendedProperties extends Hashtable {
* 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 @@ public class ExtendedProperties extends Hashtable {
* 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 @@ public class ExtendedProperties extends Hashtable {
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 @@ public class ExtendedProperties extends Hashtable {
StringBuffer currentOutput = new StringBuffer();
currentOutput.append(key);
currentOutput.append("=");
currentOutput.append(currentElement);
currentOutput.append(escape(currentElement));
theWrtr.println(currentOutput.toString());
}
}

View File

@ -1,13 +1,13 @@
/*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestExtendedProperties.java,v 1.4 2001/09/21 03:15:15 jvanzyl Exp $
* $Revision: 1.4 $
* $Date: 2001/09/21 03:15:15 $
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestExtendedProperties.java,v 1.5 2003/08/24 10:50:58 scolebourne Exp $
* $Revision: 1.5 $
* $Date: 2003/08/24 10:50:58 $
*
* ====================================================================
*
* 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.Test;
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: TestExtendedProperties.java,v 1.4 2001/09/21 03:15:15 jvanzyl Exp $
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @author Mohan Kishore
* @version $Id: TestExtendedProperties.java,v 1.5 2003/08/24 10:50:58 scolebourne Exp $
*/
public class TestExtendedProperties extends TestCase
{
@ -152,4 +155,68 @@ public class TestExtendedProperties extends TestCase
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");
}
}
}