summaryrefslogtreecommitdiff
path: root/core/java/android/os/PatternMatcher.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/os/PatternMatcher.java
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/os/PatternMatcher.java')
-rw-r--r--core/java/android/os/PatternMatcher.java197
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;
+ }
+}