1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1999 by Sun Microsystems, Inc.
23  * All rights reserved.
24  *
25  */
26 
27 //  AttributePattern.java: Models a pattern for attribute matching.
28 //  Author:           James Kempf
29 //  Created On:       Tue Feb  3 15:26:30 1998
30 //  Last Modified By: James Kempf
31 //  Last Modified On: Thu Aug  6 14:33:57 1998
32 //  Update Count:     19
33 //
34 
35 package com.sun.slp;
36 
37 import java.util.*;
38 import java.io.*;
39 
40 /**
41  * The AttributePattern class models an attribute pattern. It handles
42  * wildcard matching of lowercased, space-compressed strings. Each
43  * element in the parts vector is a PatternPart object. A PatternPart
44  * object is a pattern consisting of (maximally) a beginning wildcard and
45  * string pattern. A PatternPart may be lacking the
46  * any of these, but will always have at least one.
47  *
48  * @author James Kempf
49  */
50 
51 class AttributePattern extends AttributeString {
52 
53     private static final String WILDCARD = "*";
54 
55     private Vector parts = new Vector();
56 
57     /**
58      * The PatternPart class models a single component of a pattern.
59      * It may have a beginning wildcard and string
60      * pattern in the middle. Any of the parts may be missing, but it will
61      * always have at least one.
62      *
63      * @author James Kempf
64      */
65 
66 
67     private class PatternPart extends Object {
68 
69 	boolean wildcard = false;
70 	String pattern = "";
71 
PatternPart(boolean wc, String str)72 	PatternPart(boolean wc, String str) {
73 	    wildcard = wc;
74 	    pattern = str;
75 
76 	}
77     }
78 
AttributePattern(String str, Locale locale)79     AttributePattern(String str, Locale locale) {
80 
81 	super(str, locale);
82 
83 	// Parse out wildcards into PatternPart objects.
84 
85 	// If there's no wildcards, simply insert the string in as the pattern.
86 
87 	if (cstring.indexOf(WILDCARD) == -1) {
88 	    parts.addElement(new PatternPart(false, cstring));
89 
90 	} else {
91 
92 	    // Parse the patterns into parts.
93 
94 	    StringTokenizer tk = new StringTokenizer(cstring, WILDCARD, true);
95 
96 	    while (tk.hasMoreTokens()) {
97 		String middle = "";
98 		boolean wc = false;
99 
100 		String tok = tk.nextToken();
101 
102 		// Beginning wildcard, or, if none, then the middle.
103 
104 		if (tok.equals(WILDCARD)) {
105 		    wc = true;
106 
107 		    // Need to look for middle.
108 
109 		    if (tk.hasMoreTokens()) {
110 			middle = tk.nextToken();
111 
112 		    }
113 
114 		} else {
115 		    middle = tok;
116 
117 		}
118 
119 		// Note that there may be a terminal pattern part that just
120 		//  consists of a wildcard.
121 
122 		parts.addElement(new PatternPart(wc, middle));
123 	    }
124 	}
125     }
126 
isWildcarded()127     boolean isWildcarded() {
128 	return (parts.size() > 1);
129 
130     }
131 
132     // Match the AttributeString object against this pattern,
133     //  returning true if they match.
134 
match(AttributeString str)135     public boolean match(AttributeString str) {
136 	String cstring = str.cstring;
137 	int offset = 0, len = cstring.length();
138 	int i = 0, n = parts.size();
139 	boolean match = true;
140 
141 	// March through the parts, matching against the string.
142 
143 	for (; i < n; i++) {
144 	    PatternPart p = (PatternPart)parts.elementAt(i);
145 
146 	    // If there's a wildcard, check the remainder of the string for
147 	    //  the pattern.
148 
149 	    if (p.wildcard) {
150 
151 		// Note that if the pattern string is empty (""), then this
152 		//  will return offset, but on the next iteration, it will
153 		//  fall out of the loop because an empty pattern string
154 		//  can only occur at the end (like "foo*").
155 
156 		if ((offset = cstring.indexOf(p.pattern, offset)) == -1) {
157 
158 		    // The pattern was not found. Break out of the loop.
159 
160 		    match = false;
161 		    break;
162 		}
163 
164 		offset += p.pattern.length();
165 
166 		// We are at the end of the string.
167 
168 		if (offset >= len) {
169 
170 		    // If we are not at the end of the pattern, then we may not
171 		    //  have a match.
172 
173 		    if (i < (n - 1)) {
174 
175 			// If there is one more in the pattern, and it is
176 			// a pure wildcard, then we *do* have a match.
177 
178 			if (i == (n - 2)) {
179 			    p = (PatternPart)parts.elementAt(i+1);
180 
181 			    if (p.wildcard == true &&
182 			       p.pattern.length() <= 0) {
183 				break;
184 
185 			    }
186 			}
187 
188 			match = false;
189 
190 		    }
191 
192 		    // Break out of the loop, no more string to analyze.
193 
194 		    break;
195 		}
196 
197 	    } else {
198 
199 		// The pattern string must match the beginning part of the
200 		// argument string.
201 
202 		if (!cstring.regionMatches(offset,
203 					   p.pattern,
204 					   0,
205 					   p.
206 					   pattern.length())) {
207 		    match = false;
208 		    break;
209 
210 		}
211 
212 		// Bump up offset by the pattern length, and exit if
213 		// we're beyond the end of the string.
214 
215 		offset += p.pattern.length();
216 
217 		if (offset >= len) {
218 		    break;
219 
220 		}
221 	    }
222 	}
223 
224 	return match;
225     }
226 }
227