Author: oheger
Date: Sun Jun  6 16:12:08 2010
New Revision: 951884

URL: http://svn.apache.org/viewvc?rev=951884&view=rev
Log:
[CONFIGURATION-418] Improved handling of escaped list delimiters. Ported fix to 
configuration2 branch.

Modified:
    
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
    
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
    
commons/proper/configuration/branches/configuration2_experimental/src/test/resources/test.properties

Modified: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java?rev=951884&r1=951883&r2=951884&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/PropertiesConfiguration.java
 Sun Jun  6 16:12:08 2010
@@ -212,6 +212,9 @@ public class PropertiesConfiguration ext
     /** Constant for the escaping character.*/
     private static final String ESCAPE = "\\";
 
+    /** Constant for the escaped escaping character.*/
+    private static final String DOUBLE_ESC = ESCAPE + ESCAPE;
+
     /** Constant for the radix of hex numbers.*/
     private static final int HEX_RADIX = 16;
 
@@ -594,6 +597,24 @@ public class PropertiesConfiguration ext
     }
 
     /**
+     * Returns the number of trailing backslashes. This is sometimes needed for
+     * the correct handling of escape characters.
+     *
+     * @param line the string to investigate
+     * @return the number of trailing backslashes
+     */
+    private static int countTrailingBS(String line)
+    {
+        int bsCount = 0;
+        for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == 
'\\'; idx--)
+        {
+            bsCount++;
+        }
+
+        return bsCount;
+    }
+
+    /**
      * This class is used to read properties lines. These lines do
      * not terminate with new-line chars but rather when there is no
      * backslash sign a the end of the line.  This is used to
@@ -837,13 +858,7 @@ public class PropertiesConfiguration ext
          */
         private static boolean checkCombineLines(String line)
         {
-            int bsCount = 0;
-            for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == 
'\\'; idx--)
-            {
-                bsCount++;
-            }
-
-            return bsCount % 2 != 0;
+            return countTrailingBS(line) % 2 != 0;
         }
 
         /**
@@ -1018,7 +1033,7 @@ public class PropertiesConfiguration ext
         {
             String v;
 
-            if (value instanceof List)
+            if (value instanceof List<?>)
             {
                 List<?> values = (List<?>) value;
                 if (forceSingleLine)
@@ -1033,7 +1048,7 @@ public class PropertiesConfiguration ext
             }
             else
             {
-                v = escapeValue(value);
+                v = escapeValue(value, false);
             }
 
             write(escapeKey(key));
@@ -1089,12 +1104,13 @@ public class PropertiesConfiguration ext
          * will be escaped.
          *
          * @param value the property value
+         * @param inList a flag whether the value is part of a list
          * @return the escaped property value
          * @since 1.3
          */
-        private String escapeValue(Object value)
+        private String escapeValue(Object value, boolean inList)
         {
-            String escapedValue = 
StringEscapeUtils.escapeJava(String.valueOf(value));
+            String escapedValue = handleBackslashs(value, inList);
             if (delimiter != 0)
             {
                 escapedValue = StringUtils.replace(escapedValue, 
String.valueOf(delimiter), ESCAPE + delimiter);
@@ -1103,6 +1119,45 @@ public class PropertiesConfiguration ext
         }
 
         /**
+         * Performs the escaping of backslashes in the specified properties
+         * value. Because a double backslash is used to escape the escape
+         * character of a list delimiter, double backslashes also have to be
+         * escaped if the property is part of a (single line) list. Then, in 
all cases each backslash has to be doubled in order to produce a
+         * valid properties file.
+         *
+         * @param value the value to be escaped
+         * @param inList a flag whether the value is part of a list
+         * @return the value with escaped backslashes as string
+         */
+        private String handleBackslashs(Object value, boolean inList)
+        {
+            String strValue = String.valueOf(value);
+
+            if (inList && strValue.indexOf(DOUBLE_ESC) >= 0)
+            {
+                char esc = ESCAPE.charAt(0);
+                StringBuffer buf = new StringBuffer(strValue.length() + 8);
+                for (int i = 0; i < strValue.length(); i++)
+                {
+                    if (strValue.charAt(i) == esc && i < strValue.length() - 1
+                            && strValue.charAt(i + 1) == esc)
+                    {
+                        buf.append(DOUBLE_ESC).append(DOUBLE_ESC);
+                        i++;
+                    }
+                    else
+                    {
+                        buf.append(strValue.charAt(i));
+                    }
+                }
+
+                strValue = buf.toString();
+            }
+
+            return StringEscapeUtils.escapeJava(strValue);
+        }
+
+        /**
          * Transforms a list of values into a single line value.
          *
          * @param values the list with the values
@@ -1114,19 +1169,19 @@ public class PropertiesConfiguration ext
             if (!values.isEmpty())
             {
                 Iterator<?> it = values.iterator();
-                String lastValue = escapeValue(it.next());
+                String lastValue = escapeValue(it.next(), true);
                 StringBuilder buf = new StringBuilder(lastValue);
                 while (it.hasNext())
                 {
                     // if the last value ended with an escape character, it has
                     // to be escaped itself; otherwise the list delimiter will
                     // be escaped
-                    if (lastValue.endsWith(ESCAPE))
+                    if (lastValue.endsWith(ESCAPE) && 
(countTrailingBS(lastValue) / 2) % 2 != 0)
                     {
                         buf.append(ESCAPE).append(ESCAPE);
                     }
                     buf.append(delimiter);
-                    lastValue = escapeValue(it.next());
+                    lastValue = escapeValue(it.next(), true);
                     buf.append(lastValue);
                 }
                 return buf.toString();

Modified: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java?rev=951884&r1=951883&r2=951884&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
 Sun Jun  6 16:12:08 2010
@@ -991,6 +991,33 @@ public class TestPropertiesConfiguration
     }
 
     /**
+     * Tests whether backslashes are correctly handled if lists are parsed. 
This
+     * test is related to CONFIGURATION-418.
+     */
+    public void testBackslashEscapingInLists() throws ConfigurationException
+    {
+        checkBackslashList("share2");
+        checkBackslashList("share1");
+    }
+
+    /**
+     * Helper method for testing the content of a list with elements that
+     * contain backslashes.
+     *
+     * @param key the key
+     */
+    private void checkBackslashList(String key)
+    {
+        Object prop = conf.getProperty("test." + key);
+        assertTrue("Not a list", prop instanceof List<?>);
+        List<?> list = (List<?>) prop;
+        assertEquals("Wrong number of list elements", 2, list.size());
+        final String prefix = "\\\\" + key;
+        assertEquals("Wrong element 1", prefix + "a", list.get(0));
+        assertEquals("Wrong element 2", prefix + "b", list.get(1));
+    }
+
+    /**
      * Creates a configuration that can be used for testing copy operations.
      *
      * @return the configuration to be copied

Modified: 
commons/proper/configuration/branches/configuration2_experimental/src/test/resources/test.properties
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/resources/test.properties?rev=951884&r1=951883&r2=951884&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/test/resources/test.properties
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/test/resources/test.properties
 Sun Jun  6 16:12:08 2010
@@ -102,3 +102,9 @@ test.separator.formfeedfoo
 test.separator.whitespace foo
 test.separator.no.space=foo
 
+# Tests for backslash escaping in lists
+test.share1 = \\\\\\\\share1a, \\\\\\\\share1b
+test.share2 = \\\\share2a
+test.share2 = \\\\share2b
+test.share3 = \\\\\\\\share3a\\\\\\\\,\\\\\\\\share3b\\
+


Reply via email to