Substring operator is false for types other than string and
it should obey escape characters. (FELIX-2039)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@936021 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
index 8127b49..3802275 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -346,13 +346,10 @@
         // result immediately.
         if (lhs instanceof Comparable)
         {
-            // The substring operator only works on string values, so if the
-            // lhs is not a string, then do an equality comparison using the
-            // original string containing wildcards.
+            // Spec says SUBSTRING is false for all types other than string.
             if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
             {
-                op = SimpleFilter.EQ;
-                rhsUnknown = SimpleFilter.unparseSubstring((List<String>) rhsUnknown);
+                return false;
             }
 
             Object rhs;
@@ -438,13 +435,10 @@
             return false;
         }
 
-        // The substring operator only works on string values, so if the
-        // lhs is not a string, then do an equality comparison using the
-        // original string containing wildcards.
+        // Spec says SUBSTRING is false for all types other than string.
         if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
         {
-            op = SimpleFilter.EQ;
-            rhsUnknown = SimpleFilter.unparseSubstring((List<String>) rhsUnknown);
+            return false;
         }
 
         // Since we cannot identify the LHS type, then we can only perform
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
index 0cabf9a..20bb90d 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
@@ -107,28 +107,44 @@
         return sb.toString();
     }
 
+    private static String toDecodedString(String s, int startIdx, int endIdx)
+    {
+        StringBuffer sb = new StringBuffer(endIdx - startIdx);
+        boolean escaped = false;
+        for (int i = 0; i < (endIdx - startIdx); i++)
+        {
+            char c = s.charAt(startIdx + i);
+            if (!escaped && (c == '\\'))
+            {
+                escaped = true;
+            }
+            else
+            {
+                escaped = false;
+                sb.append(c);
+            }
+        }
+
+        return sb.toString();
+    }
+
     private static String toEncodedString(Object o)
     {
         if (o instanceof String)
         {
             String s = (String) o;
-            if ((s.indexOf('\\') >= 0)
-                || (s.indexOf('(') >= 0)
-                || (s.indexOf(')') >= 0))
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < s.length(); i++)
             {
-                StringBuffer sb = new StringBuffer();
-                for (int i = 0; i < s.length(); i++)
+                char c = s.charAt(i);
+                if ((c == '\\') || (c == '(') || (c == ')') || (c == '*'))
                 {
-                    char c = s.charAt(i);
-                    if ((c == '\\') || (c == '(') || (c == ')'))
-                    {
-                        sb.append('\\');
-                    }
-                    sb.append(c);
+                    sb.append('\\');
                 }
-
-                o = sb.toString();
+                sb.append(c);
             }
+
+            o = sb.toString();
         }
 
         return o.toString();
@@ -320,36 +336,14 @@
         }
 
         // Parse value.
-        StringBuffer sb = new StringBuffer(endIdx - startIdx);
-        for (int offset = 0; offset < (endIdx - startIdx); )
-        {
-            char c = filter.charAt(startIdx + offset);
-            if ((c == '(') || (c == ')'))
-            {
-                throw new IllegalArgumentException(
-                    "Illegal value: " + filter.substring(startIdx, endIdx));
-            }
-            else if (c == '\\')
-            {
-                offset++;
-            }
-
-            if ((startIdx + offset) >= endIdx)
-            {
-                throw new IllegalArgumentException(
-                    "Illegal value: " + filter.substring(startIdx, endIdx));
-            }
-
-            sb.append(filter.charAt(startIdx + offset));
-            offset++;
-        }
-        Object value = sb.toString();
+        Object value = toDecodedString(filter, startIdx, endIdx);
 
         // Check if the equality comparison is actually a substring
         // or present operation.
         if (op == EQ)
         {
-            List<String> values = parseSubstring((String) value);
+            String valueStr = filter.substring(startIdx, endIdx);
+            List<String> values = parseSubstring(valueStr);
             if ((values.size() == 2)
                 && (values.get(0).length() == 0)
                 && (values.get(1).length() == 0))
@@ -378,6 +372,7 @@
         int idx = 0;
 
         // We assume (sub)strings can contain leading and trailing blanks
+        boolean escaped = false;
 loop:   for (;;)
         {
             if (idx >= value.length())
@@ -399,8 +394,14 @@
                 break loop;
             }
 
+            // Read the next character and account for escapes.
             char c = value.charAt(idx++);
-            if (c == '*')
+            if (!escaped && ((c == '(') || (c == ')')))
+            {
+                throw new IllegalArgumentException(
+                    "Illegal value: " + value);
+            }
+            else if (!escaped && (c == '*'))
             {
                 if (wasStar)
                 {
@@ -421,8 +422,13 @@
                 }
                 wasStar = true;
             }
+            else if (!escaped && (c == '\\'))
+            {
+                escaped = true;
+            }
             else
             {
+                escaped = false;
                 wasStar = false;
                 ss.append(c);
             }