diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
| commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
| tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/os/PatternMatcher.java | |
| parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/os/PatternMatcher.java')
| -rw-r--r-- | core/java/android/os/PatternMatcher.java | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java new file mode 100644 index 000000000000..56dc837549a7 --- /dev/null +++ b/core/java/android/os/PatternMatcher.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** + * A simple pattern matcher, which is safe to use on untrusted data: it does + * not provide full reg-exp support, only simple globbing that can not be + * used maliciously. + */ +public class PatternMatcher implements Parcelable { + /** + * Pattern type: the given pattern must exactly match the string it is + * tested against. + */ + public static final int PATTERN_LITERAL = 0; + + /** + * Pattern type: the given pattern must match the + * beginning of the string it is tested against. + */ + public static final int PATTERN_PREFIX = 1; + + /** + * Pattern type: the given pattern is interpreted with a + * simple glob syntax for matching against the string it is tested against. + * In this syntax, you can use the '*' character to match against zero or + * more occurrences of the character immediately before. If the + * character before it is '.' it will match any character. The character + * '\' can be used as an escape. This essentially provides only the '*' + * wildcard part of a normal regexp. + */ + public static final int PATTERN_SIMPLE_GLOB = 2; + + private final String mPattern; + private final int mType; + + public PatternMatcher(String pattern, int type) { + mPattern = pattern; + mType = type; + } + + public final String getPath() { + return mPattern; + } + + public final int getType() { + return mType; + } + + public boolean match(String str) { + return matchPattern(mPattern, str, mType); + } + + public String toString() { + String type = "? "; + switch (mType) { + case PATTERN_LITERAL: + type = "LITERAL: "; + break; + case PATTERN_PREFIX: + type = "PREFIX: "; + break; + case PATTERN_SIMPLE_GLOB: + type = "GLOB: "; + break; + } + return "PatternMatcher{" + type + mPattern + "}"; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPattern); + dest.writeInt(mType); + } + + public PatternMatcher(Parcel src) { + mPattern = src.readString(); + mType = src.readInt(); + } + + public static final Parcelable.Creator<PatternMatcher> CREATOR + = new Parcelable.Creator<PatternMatcher>() { + public PatternMatcher createFromParcel(Parcel source) { + return new PatternMatcher(source); + } + + public PatternMatcher[] newArray(int size) { + return new PatternMatcher[size]; + } + }; + + static boolean matchPattern(String pattern, String match, int type) { + if (match == null) return false; + if (type == PATTERN_LITERAL) { + return pattern.equals(match); + } if (type == PATTERN_PREFIX) { + return match.startsWith(pattern); + } else if (type != PATTERN_SIMPLE_GLOB) { + return false; + } + + final int NP = pattern.length(); + if (NP <= 0) { + return match.length() <= 0; + } + final int NM = match.length(); + int ip = 0, im = 0; + char nextChar = pattern.charAt(0); + while ((ip<NP) && (im<NM)) { + char c = nextChar; + ip++; + nextChar = ip < NP ? pattern.charAt(ip) : 0; + final boolean escaped = (c == '\\'); + if (escaped) { + c = nextChar; + ip++; + nextChar = ip < NP ? pattern.charAt(ip) : 0; + } + if (nextChar == '*') { + if (!escaped && c == '.') { + if (ip >= (NP-1)) { + // at the end with a pattern match, so + // all is good without checking! + return true; + } + ip++; + nextChar = pattern.charAt(ip); + // Consume everything until the next character in the + // pattern is found. + if (nextChar == '\\') { + ip++; + nextChar = ip < NP ? pattern.charAt(ip) : 0; + } + do { + if (match.charAt(im) == nextChar) { + break; + } + im++; + } while (im < NM); + if (im == NM) { + // Whoops, the next character in the pattern didn't + // exist in the match. + return false; + } + ip++; + nextChar = ip < NP ? pattern.charAt(ip) : 0; + im++; + } else { + // Consume only characters matching the one before '*'. + do { + if (match.charAt(im) != c) { + break; + } + im++; + } while (im < NM); + ip++; + nextChar = ip < NP ? pattern.charAt(ip) : 0; + } + } else { + if (c != '.' && match.charAt(im) != c) return false; + im++; + } + } + + if (ip >= NP && im >= NM) { + // Reached the end of both strings, all is good! + return true; + } + + // One last check: we may have finished the match string, but still + // have a '.*' at the end of the pattern, which should still count + // as a match. + if (ip == NP-2 && pattern.charAt(ip) == '.' + && pattern.charAt(ip+1) == '*') { + return true; + } + + return false; + } +} |
