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