/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.cocoon.matching.helpers; import java.util.HashMap; /** * This class is an utility class that perform wilcard-patterns matching and * isolation. * * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a> * (Apache Software Foundation) * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a> * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> * @version CVS $Id$ * @deprecated renamed to WildcardHelper */ public class WildcardURIMatcher { /** The int representing '*' in the pattern <code>int []</code>. */ protected static final int MATCH_FILE = -1; /** The int representing '**' in the pattern <code>int []</code>. */ protected static final int MATCH_PATH = -2; /** The int representing begin in the pattern <code>int []</code>. */ protected static final int MATCH_BEGIN = -4; /** The int representing end in pattern <code>int []</code>. */ protected static final int MATCH_THEEND = -5; /** The int value that terminates the pattern <code>int []</code>. */ protected static final int MATCH_END = -3; /** * match a pattern agains a string and isolates wildcard replacement into a * <code>Stack</code>. */ public static boolean match (HashMap map, String data, int[] expr) throws NullPointerException { if (map == null) throw new NullPointerException ("No map provided"); if (data == null) throw new NullPointerException ("No data provided"); if (expr == null) throw new NullPointerException ("No pattern expression provided"); char buff[] = data.toCharArray(); // Allocate the result buffer char rslt[] = new char[expr.length + buff.length]; // The previous and current position of the expression character // (MATCH_*) int charpos = 0; // The position in the expression, input, translation and result arrays int exprpos = 0; int buffpos = 0; int rsltpos = 0; int offset = -1; // The matching count int mcount = 0; // We want the complete data be in {0} map.put(Integer.toString(mcount),data); // First check for MATCH_BEGIN boolean matchBegin = false; if (expr[charpos] == MATCH_BEGIN) { matchBegin = true; exprpos = ++charpos; } // Search the fist expression character (except MATCH_BEGIN - already skipped) while (expr[charpos] >= 0) charpos++; // The expression charater (MATCH_*) int exprchr = expr[charpos]; while (true) { // Check if the data in the expression array before the current // expression character matches the data in the input buffer if (matchBegin) { if (!matchArray(expr, exprpos, charpos, buff, buffpos)) return (false); matchBegin = false; } else { offset = indexOfArray (expr, exprpos, charpos, buff, buffpos); if (offset < 0) return (false); } // Check for MATCH_BEGIN if (matchBegin) { if (offset != 0) return (false); matchBegin = false; } // Advance buffpos buffpos += (charpos - exprpos); // Check for END's if (exprchr == MATCH_END) { if (rsltpos > 0) map.put(Integer.toString(++mcount),new String(rslt, 0, rsltpos)); // Don't care about rest of input buffer return (true); } else if (exprchr == MATCH_THEEND) { if (rsltpos > 0) map.put (Integer.toString(++mcount),new String(rslt, 0, rsltpos)); // Check that we reach buffer's end return (buffpos == buff.length); } // Search the next expression character exprpos = ++charpos; while (expr[charpos] >= 0) charpos++; int prevchr = exprchr; exprchr = expr[charpos]; // We have here prevchr == * or **. offset = (prevchr == MATCH_FILE) ? indexOfArray (expr, exprpos, charpos, buff, buffpos) : lastIndexOfArray (expr, exprpos, charpos, buff, buffpos); if (offset < 0) return (false); // Copy the data from the source buffer into the result buffer // to substitute the expression character if (prevchr == MATCH_PATH) { while (buffpos < offset) rslt[rsltpos++] = buff[buffpos++]; } else { // Matching file, don't copy '/' while (buffpos < offset) { if (buff[buffpos] == '/') return (false); rslt[rsltpos++] = buff[buffpos++]; } } map.put(Integer.toString(++mcount),new String (rslt, 0, rsltpos)); rsltpos = 0; } } /** * Get the offset of a part of an int array within a char array. * <br> * This method return the index in d of the first occurrence after dpos of * that part of array specified by r, starting at rpos and terminating at * rend. * * @param r The array containing the data that need to be matched in d. * @param rpos The index of the first character in r to look for. * @param rend The index of the last character in r to look for plus 1. * @param d The array of char that should contain a part of r. * @param dpos The starting offset in d for the matching. * @return The offset in d of the part of r matched in d or -1 if that was * not found. */ protected static int indexOfArray (int r[], int rpos, int rend, char d[], int dpos) { // Check if pos and len are legal if (rend < rpos) throw new IllegalArgumentException ("rend < rpos"); // If we need to match a zero length string return current dpos if (rend == rpos) return (d.length); //?? dpos? // If we need to match a 1 char length string do it simply if ((rend - rpos) == 1) { // Search for the specified character for (int x = dpos; x < d.length; x++) if (r[rpos] == d[x]) return (x); } // Main string matching loop. It gets executed if the characters to // match are less then the characters left in the d buffer while ((dpos + rend - rpos) <= d.length) { // Set current startpoint in d int y = dpos; // Check every character in d for equity. If the string is matched // return dpos for (int x = rpos; x <= rend; x++) { if (x == rend) return (dpos); if (r[x] != d[y++]) break; } // Increase dpos to search for the same string at next offset dpos++; } // The remaining chars in d buffer were not enough or the string // wasn't matched return (-1); } /** * Get the offset of a last occurance of an int array within a char array. * <br> * This method return the index in d of the last occurrence after dpos of * that part of array specified by r, starting at rpos and terminating at * rend. * * @param r The array containing the data that need to be matched in d. * @param rpos The index of the first character in r to look for. * @param rend The index of the last character in r to look for plus 1. * @param d The array of char that should contain a part of r. * @param dpos The starting offset in d for the matching. * @return The offset in d of the last part of r matched in d or -1 if that was * not found. */ protected static int lastIndexOfArray (int r[], int rpos, int rend, char d[], int dpos) { // Check if pos and len are legal if (rend < rpos) throw new IllegalArgumentException ("rend < rpos"); // If we need to match a zero length string return current dpos if (rend == rpos) return (d.length); //?? dpos? // If we need to match a 1 char length string do it simply if ((rend - rpos) == 1) { // Search for the specified character for (int x = d.length - 1; x > dpos; x--) if (r[rpos] == d[x]) return (x); } // Main string matching loop. It gets executed if the characters to // match are less then the characters left in the d buffer int l = d.length - (rend - rpos); while (l >= dpos) { // Set current startpoint in d int y = l; // Check every character in d for equity. If the string is matched // return dpos for (int x = rpos; x <= rend; x++) { if (x == rend) return (l); if (r[x] != d[y++]) break; } // Decrease l to search for the same string at next offset l--; } // The remaining chars in d buffer were not enough or the string // wasn't matched return (-1); } /** * Matches elements of array r from rpos to rend with array d, starting from dpos. * <br> * This method return true if elements of array r from rpos to rend * equals elements of array d starting from dpos to dpos+(rend-rpos). * * @param r The array containing the data that need to be matched in d. * @param rpos The index of the first character in r to look for. * @param d The array of char that should start from a part of r. * @param dpos The starting offset in d for the matching. * @return true if array d starts from portion of array r. */ protected static boolean matchArray (int r[], int rpos, int rend, char d[], int dpos) { if (d.length - dpos < rend - rpos) return (false); for (int i = rpos; i < rend; i++) if (r[i] != d[dpos++]) return (false); return (true); } }