Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 1313 invoked from network); 6 Jun 2010 15:57:09 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 6 Jun 2010 15:57:09 -0000 Received: (qmail 25400 invoked by uid 500); 6 Jun 2010 15:57:09 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 25334 invoked by uid 500); 6 Jun 2010 15:57:08 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 25327 invoked by uid 99); 6 Jun 2010 15:57:08 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 06 Jun 2010 15:57:08 +0000 X-ASF-Spam-Status: No, hits=-1316.7 required=10.0 tests=ALL_TRUSTED,AWL X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 06 Jun 2010 15:57:08 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id DB60623889C5; Sun, 6 Jun 2010 15:56:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r951878 - in /commons/proper/configuration/trunk: conf/test.properties src/java/org/apache/commons/configuration/PropertiesConfiguration.java src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java Date: Sun, 06 Jun 2010 15:56:47 -0000 To: commits@commons.apache.org From: oheger@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100606155647.DB60623889C5@eris.apache.org> Author: oheger Date: Sun Jun 6 15:56:47 2010 New Revision: 951878 URL: http://svn.apache.org/viewvc?rev=951878&view=rev Log: [CONFIGURATION-418] Improved handling of escaped list delimiters Modified: commons/proper/configuration/trunk/conf/test.properties commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java Modified: commons/proper/configuration/trunk/conf/test.properties URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/test.properties?rev=951878&r1=951877&r2=951878&view=diff ============================================================================== --- commons/proper/configuration/trunk/conf/test.properties (original) +++ commons/proper/configuration/trunk/conf/test.properties Sun Jun 6 15:56:47 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\\ + Modified: commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java?rev=951878&r1=951877&r2=951878&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java (original) +++ commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java Sun Jun 6 15:56:47 2010 @@ -210,6 +210,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; @@ -589,6 +592,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 @@ -828,13 +849,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; } /** @@ -1104,7 +1119,7 @@ public class PropertiesConfiguration ext } else { - v = escapeValue(value); + v = escapeValue(value, false); } write(escapeKey(key)); @@ -1160,12 +1175,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); @@ -1174,6 +1190,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 @@ -1185,19 +1240,19 @@ public class PropertiesConfiguration ext if (!values.isEmpty()) { Iterator it = values.iterator(); - String lastValue = escapeValue(it.next()); + String lastValue = escapeValue(it.next(), true); StringBuffer buf = new StringBuffer(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/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java?rev=951878&r1=951877&r2=951878&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java (original) +++ commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java Sun Jun 6 15:56:47 2010 @@ -995,6 +995,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