xref: /aosp_15_r20/external/jazzer-api/src/main/java/com/code_intelligence/jazzer/utils/SimpleGlobMatcher.kt (revision 33edd6723662ea34453766bfdca85dbfdd5342b8)
1 // Copyright 2022 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.utils
16 
17 class SimpleGlobMatcher(val glob: String) {
18     private enum class Type {
19         // foo.bar (matches foo.bar only)
20         FULL_MATCH,
21 
22         // foo.** (matches foo.bar and foo.bar.baz)
23         PATH_WILDCARD_SUFFIX,
24 
25         // foo.* (matches foo.bar, but not foo.bar.baz)
26         SEGMENT_WILDCARD_SUFFIX,
27     }
28 
29     private val type: Type
30     private val prefix: String
31 
32     init {
33         // Remain compatible with globs such as "\\[" that use escaping.
34         val pattern = glob.replace("\\", "")
35         when {
36             !pattern.contains('*') -> {
37                 type = Type.FULL_MATCH
38                 prefix = pattern
39             }
40             // Ends with "**" and contains no other '*'.
41             pattern.endsWith("**") && pattern.indexOf('*') == pattern.length - 2 -> {
42                 type = Type.PATH_WILDCARD_SUFFIX
43                 prefix = pattern.removeSuffix("**")
44             }
45             // Ends with "*" and contains no other '*'.
46             pattern.endsWith('*') && pattern.indexOf('*') == pattern.length - 1 -> {
47                 type = Type.SEGMENT_WILDCARD_SUFFIX
48                 prefix = pattern.removeSuffix("*")
49             }
50             else -> throw IllegalArgumentException(
51                 "Unsupported glob pattern (only foo.bar, foo.* and foo.** are supported): $pattern",
52             )
53         }
54     }
55 
56     /**
57      * Checks whether [maybeInternalClassName], which may be internal (foo/bar) or not (foo.bar), matches [glob].
58      */
matchesnull59     fun matches(maybeInternalClassName: String): Boolean {
60         val className = maybeInternalClassName.replace('/', '.')
61         return when (type) {
62             Type.FULL_MATCH -> className == prefix
63             Type.PATH_WILDCARD_SUFFIX -> className.startsWith(prefix)
64             Type.SEGMENT_WILDCARD_SUFFIX -> {
65                 // className starts with prefix and contains no further '.'.
66                 className.startsWith(prefix) &&
67                     className.indexOf('.', startIndex = prefix.length) == -1
68             }
69         }
70     }
71 }
72