Skip to content

Commit 37ba197

Browse files
committed
<action dev="ggregory" type="add" issue="CODEC-184" due-to="Cyrille Artho">NullPointerException in DoubleMetaPhone.isDoubleMetaphoneEqual when using empty strings</action>
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/codec/trunk@1586300 13f79535-47bb-0310-9956-ffa450edef68
1 parent 8c14577 commit 37ba197

5 files changed

Lines changed: 122 additions & 2 deletions

File tree

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ The <action> type attribute can be add,update,fix,remove.
4343
</properties>
4444
<body>
4545
<release version="1.10" date="DD Mmmm 2014" description="Feature and fix release.">
46+
<action dev="ggregory" type="add" issue="CODEC-184" due-to="Cyrille Artho">NullPointerException in DoubleMetaPhone.isDoubleMetaphoneEqual when using empty strings</action>
4647
<action dev="ggregory" type="add" issue="CODEC-181" due-to="Ivan Martinez-Ortiz">Make possible to provide padding byte to BaseNCodec in constructor</action>
4748
<action dev="ggregory" type="fix" issue="CODEC-180" due-to="Ville Skyttä">Fix Javadoc 1.8.0 errors</action>
4849
<action dev="ggregory" type="update" issue="CODEC-178">Deprecate Charsets Charset constants in favor of Java 7's java.nio.charset.StandardCharsets</action>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.apache.commons.codec.binary;
2+
3+
/**
4+
* <p>
5+
* Operations on {@link CharSequence} that are {@code null} safe.
6+
* </p>
7+
* <p>
8+
* Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
9+
* </p>
10+
*
11+
* @see CharSequence
12+
* @since 1.10
13+
*/
14+
public class CharSequenceUtils {
15+
16+
/**
17+
* Green implementation of regionMatches.
18+
*
19+
* @param cs
20+
* the {@code CharSequence} to be processed
21+
* @param ignoreCase
22+
* whether or not to be case insensitive
23+
* @param thisStart
24+
* the index to start on the {@code cs} CharSequence
25+
* @param substring
26+
* the {@code CharSequence} to be looked for
27+
* @param start
28+
* the index to start on the {@code substring} CharSequence
29+
* @param length
30+
* character length of the region
31+
* @return whether the region matched
32+
*/
33+
static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
34+
final CharSequence substring, final int start, final int length) {
35+
if (cs instanceof String && substring instanceof String) {
36+
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
37+
}
38+
int index1 = thisStart;
39+
int index2 = start;
40+
int tmpLen = length;
41+
42+
while (tmpLen-- > 0) {
43+
char c1 = cs.charAt(index1++);
44+
char c2 = substring.charAt(index2++);
45+
46+
if (c1 == c2) {
47+
continue;
48+
}
49+
50+
if (!ignoreCase) {
51+
return false;
52+
}
53+
54+
// The same check as in String.regionMatches():
55+
if (Character.toUpperCase(c1) != Character.toUpperCase(c2)
56+
&& Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
57+
return false;
58+
}
59+
}
60+
61+
return true;
62+
}
63+
}

src/main/java/org/apache/commons/codec/binary/StringUtils.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,49 @@
3737
*/
3838
public class StringUtils {
3939

40+
/**
41+
* <p>
42+
* Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
43+
* </p>
44+
*
45+
* <p>
46+
* {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The
47+
* comparison is case sensitive.
48+
* </p>
49+
*
50+
* <pre>
51+
* StringUtils.equals(null, null) = true
52+
* StringUtils.equals(null, "abc") = false
53+
* StringUtils.equals("abc", null) = false
54+
* StringUtils.equals("abc", "abc") = true
55+
* StringUtils.equals("abc", "ABC") = false
56+
* </pre>
57+
*
58+
* <p>
59+
* Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
60+
* </p>
61+
*
62+
* @see Object#equals(Object)
63+
* @param cs1
64+
* the first CharSequence, may be {@code null}
65+
* @param cs2
66+
* the second CharSequence, may be {@code null}
67+
* @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
68+
* @since 1.10
69+
*/
70+
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
71+
if (cs1 == cs2) {
72+
return true;
73+
}
74+
if (cs1 == null || cs2 == null) {
75+
return false;
76+
}
77+
if (cs1 instanceof String && cs2 instanceof String) {
78+
return cs1.equals(cs2);
79+
}
80+
return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length()));
81+
}
82+
4083
/**
4184
* Calls {@link String#getBytes(Charset)}
4285
*

src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.apache.commons.codec.EncoderException;
2121
import org.apache.commons.codec.StringEncoder;
22+
import org.apache.commons.codec.binary.StringUtils;
2223

2324
/**
2425
* Encodes a string into a double metaphone value. This Implementation is based on the algorithm by <CITE>Lawrence
@@ -241,7 +242,7 @@ public boolean isDoubleMetaphoneEqual(final String value1, final String value2)
241242
* {@code false} otherwise.
242243
*/
243244
public boolean isDoubleMetaphoneEqual(final String value1, final String value2, final boolean alternate) {
244-
return doubleMetaphone(value1, alternate).equals(doubleMetaphone(value2, alternate));
245+
return StringUtils.equals(doubleMetaphone(value1, alternate), doubleMetaphone(value2, alternate));
245246
}
246247

247248
/**

src/test/java/org/apache/commons/codec/language/DoubleMetaphoneTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,16 @@ public void testCCedilla() {
10601060
assertTrue(this.getStringEncoder().isDoubleMetaphoneEqual("\u00e7", "S")); // c-cedilla
10611061
}
10621062

1063+
@Test
1064+
public void testCodec184() throws Throwable {
1065+
assertTrue(new DoubleMetaphone().isDoubleMetaphoneEqual("", "", false));
1066+
assertTrue(new DoubleMetaphone().isDoubleMetaphoneEqual("", "", true));
1067+
assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("aa", "", false));
1068+
assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("aa", "", true));
1069+
assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("", "aa", false));
1070+
assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("", "aa", true));
1071+
}
1072+
10631073
@Test
10641074
public void testDoubleMetaphone() {
10651075
assertDoubleMetaphone("TSTN", "testing");
@@ -1111,7 +1121,9 @@ public void testEmpty() {
11111121

11121122
@Test
11131123
public void testIsDoubleMetaphoneEqualBasic() {
1114-
final String[][] testFixture = new String[][] { { "Case", "case" }, {
1124+
final String[][] testFixture = new String[][] { {
1125+
"", "" }, {
1126+
"Case", "case" }, {
11151127
"CASE", "Case" }, {
11161128
"caSe", "cAsE" }, {
11171129
"cookie", "quick" }, {

0 commit comments

Comments
 (0)