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